@@ -6,17 +6,20 @@ import (
66
77 "github.com/authorizerdev/authorizer/server/constants"
88 "github.com/authorizerdev/authorizer/server/cookie"
9+ "github.com/authorizerdev/authorizer/server/crypto"
910 "github.com/authorizerdev/authorizer/server/db"
1011 "github.com/authorizerdev/authorizer/server/envstore"
1112 "github.com/authorizerdev/authorizer/server/sessionstore"
1213 "github.com/authorizerdev/authorizer/server/token"
14+ "github.com/authorizerdev/authorizer/server/utils"
1315 "github.com/gin-gonic/gin"
1416 "github.com/google/uuid"
1517)
1618
1719// AuthorizeHandler is the handler for the /authorize route
1820// required params
1921// ?redirect_uri = redirect url
22+ // ?response_mode = to decide if result should be html or re-direct
2023// state[recommended] = to prevent CSRF attack (for authorizer its compulsory)
2124// code_challenge = to prevent CSRF attack
2225// code_challenge_method = to prevent CSRF attack [only sh256 is supported]
@@ -31,56 +34,74 @@ func AuthorizeHandler() gin.HandlerFunc {
3134 scopeString := strings .TrimSpace (gc .Query ("scope" ))
3235 clientID := strings .TrimSpace (gc .Query ("client_id" ))
3336 template := "authorize.tmpl"
37+ responseMode := strings .TrimSpace (gc .Query ("response_mode" ))
3438
35- if clientID == "" {
36- gc .HTML (http .StatusOK , template , gin.H {
37- "target_origin" : redirectURI ,
38- "authorization_response" : map [string ]interface {}{
39- "type" : "authorization_response" ,
40- "response" : map [string ]string {
41- "error" : "client_id is required" ,
42- },
43- },
44- })
45- return
39+ if responseMode == "" {
40+ responseMode = "query"
4641 }
4742
48- if clientID != envstore .EnvStoreObj .GetStringStoreEnvVariable (constants .EnvKeyClientID ) {
49- gc .HTML (http .StatusOK , template , gin.H {
50- "target_origin" : redirectURI ,
51- "authorization_response" : map [string ]interface {}{
52- "type" : "authorization_response" ,
53- "response" : map [string ]string {
54- "error" : "invalid_client_id" ,
43+ if responseMode != "query" && responseMode != "web_message" {
44+ gc .JSON (400 , gin.H {"error" : "invalid response mode" })
45+ }
46+
47+ if redirectURI == "" {
48+ redirectURI = "/app"
49+ }
50+
51+ isQuery := responseMode == "query"
52+
53+ hostname := utils .GetHost (gc )
54+ loginRedirectState := crypto .EncryptB64 (`{"authorizerURL":"` + hostname + `","redirectURL":"` + redirectURI + `"}` )
55+ loginURL := "/app?state=" + loginRedirectState
56+
57+ if clientID == "" {
58+ if isQuery {
59+ gc .Redirect (http .StatusFound , loginURL )
60+ } else {
61+ gc .HTML (http .StatusOK , template , gin.H {
62+ "target_origin" : redirectURI ,
63+ "authorization_response" : map [string ]interface {}{
64+ "type" : "authorization_response" ,
65+ "response" : map [string ]string {
66+ "error" : "client_id is required" ,
67+ },
5568 },
56- },
57- })
69+ })
70+ }
5871 return
5972 }
6073
61- if redirectURI == "" {
62- gc .HTML (http .StatusOK , template , gin.H {
63- "target_origin" : redirectURI ,
64- "authorization_response" : map [string ]interface {}{
65- "type" : "authorization_response" ,
66- "response" : map [string ]string {
67- "error" : "redirect_uri is required" ,
74+ if clientID != envstore .EnvStoreObj .GetStringStoreEnvVariable (constants .EnvKeyClientID ) {
75+ if isQuery {
76+ gc .Redirect (http .StatusFound , loginURL )
77+ } else {
78+ gc .HTML (http .StatusOK , template , gin.H {
79+ "target_origin" : redirectURI ,
80+ "authorization_response" : map [string ]interface {}{
81+ "type" : "authorization_response" ,
82+ "response" : map [string ]string {
83+ "error" : "invalid_client_id" ,
84+ },
6885 },
69- },
70- })
86+ })
87+ }
7188 return
7289 }
7390
7491 if state == "" {
75- gc .HTML (http .StatusOK , template , gin.H {
76- "target_origin" : redirectURI ,
77- "authorization_response" : map [string ]interface {}{
78- "type" : "authorization_response" ,
79- "response" : map [string ]string {
80- "error" : "state is required" ,
92+ if isQuery {
93+ gc .Redirect (http .StatusFound , loginURL )
94+ } else {
95+ gc .HTML (http .StatusOK , template , gin.H {
96+ "target_origin" : redirectURI ,
97+ "authorization_response" : map [string ]interface {}{
98+ "type" : "authorization_response" ,
99+ "response" : map [string ]string {
100+ "error" : "state is required" ,
101+ },
81102 },
82- },
83- })
103+ })
104+ }
84105 return
85106 }
86107
@@ -99,76 +120,96 @@ func AuthorizeHandler() gin.HandlerFunc {
99120 isResponseTypeToken := responseType == "token"
100121
101122 if ! isResponseTypeCode && ! isResponseTypeToken {
102- gc .HTML (http .StatusOK , template , gin.H {
103- "target_origin" : redirectURI ,
104- "authorization_response" : map [string ]interface {}{
105- "type" : "authorization_response" ,
106- "response" : map [string ]string {
107- "error" : "response_type is invalid" ,
108- },
109- },
110- })
111- return
112- }
113-
114- if isResponseTypeCode {
115- if codeChallenge == "" {
116- gc .HTML (http .StatusBadRequest , template , gin.H {
123+ if isQuery {
124+ gc .Redirect (http .StatusFound , loginURL )
125+ } else {
126+ gc .HTML (http .StatusOK , template , gin.H {
117127 "target_origin" : redirectURI ,
118128 "authorization_response" : map [string ]interface {}{
119129 "type" : "authorization_response" ,
120130 "response" : map [string ]string {
121- "error" : "code_challenge is required " ,
131+ "error" : "response_type is invalid " ,
122132 },
123133 },
124134 })
135+ }
136+ return
137+ }
138+
139+ if isResponseTypeCode {
140+ if codeChallenge == "" {
141+ if isQuery {
142+ gc .Redirect (http .StatusFound , loginURL )
143+ } else {
144+ gc .HTML (http .StatusBadRequest , template , gin.H {
145+ "target_origin" : redirectURI ,
146+ "authorization_response" : map [string ]interface {}{
147+ "type" : "authorization_response" ,
148+ "response" : map [string ]string {
149+ "error" : "code_challenge is required" ,
150+ },
151+ },
152+ })
153+ }
125154 return
126155 }
127156 }
128157
129158 sessionToken , err := cookie .GetSession (gc )
130159 if err != nil {
131- gc .HTML (http .StatusOK , template , gin.H {
132- "target_origin" : redirectURI ,
133- "authorization_response" : map [string ]interface {}{
134- "type" : "authorization_response" ,
135- "response" : map [string ]string {
136- "error" : "login_required" ,
137- "error_description" : "Login is required" ,
160+ if isQuery {
161+ gc .Redirect (http .StatusFound , loginURL )
162+ } else {
163+ gc .HTML (http .StatusOK , template , gin.H {
164+ "target_origin" : redirectURI ,
165+ "authorization_response" : map [string ]interface {}{
166+ "type" : "authorization_response" ,
167+ "response" : map [string ]string {
168+ "error" : "login_required" ,
169+ "error_description" : "Login is required" ,
170+ },
138171 },
139- },
140- })
172+ })
173+ }
141174 return
142175 }
143176
144177 // get session from cookie
145178 claims , err := token .ValidateBrowserSession (gc , sessionToken )
146179 if err != nil {
147- gc .HTML (http .StatusOK , template , gin.H {
148- "target_origin" : redirectURI ,
149- "authorization_response" : map [string ]interface {}{
150- "type" : "authorization_response" ,
151- "response" : map [string ]string {
152- "error" : "login_required" ,
153- "error_description" : "Login is required" ,
180+ if isQuery {
181+ gc .Redirect (http .StatusFound , loginURL )
182+ } else {
183+ gc .HTML (http .StatusOK , template , gin.H {
184+ "target_origin" : redirectURI ,
185+ "authorization_response" : map [string ]interface {}{
186+ "type" : "authorization_response" ,
187+ "response" : map [string ]string {
188+ "error" : "login_required" ,
189+ "error_description" : "Login is required" ,
190+ },
154191 },
155- },
156- })
192+ })
193+ }
157194 return
158195 }
159196 userID := claims .Subject
160197 user , err := db .Provider .GetUserByID (userID )
161198 if err != nil {
162- gc .HTML (http .StatusOK , template , gin.H {
163- "target_origin" : redirectURI ,
164- "authorization_response" : map [string ]interface {}{
165- "type" : "authorization_response" ,
166- "response" : map [string ]string {
167- "error" : "signup_required" ,
168- "error_description" : "Sign up required" ,
199+ if isQuery {
200+ gc .Redirect (http .StatusFound , loginURL )
201+ } else {
202+ gc .HTML (http .StatusOK , template , gin.H {
203+ "target_origin" : redirectURI ,
204+ "authorization_response" : map [string ]interface {}{
205+ "type" : "authorization_response" ,
206+ "response" : map [string ]string {
207+ "error" : "signup_required" ,
208+ "error_description" : "Sign up required" ,
209+ },
169210 },
170- },
171- })
211+ })
212+ }
172213 return
173214 }
174215
@@ -180,16 +221,20 @@ func AuthorizeHandler() gin.HandlerFunc {
180221 nonce := uuid .New ().String ()
181222 newSessionTokenData , newSessionToken , err := token .CreateSessionToken (user , nonce , claims .Roles , scope )
182223 if err != nil {
183- gc .HTML (http .StatusOK , template , gin.H {
184- "target_origin" : redirectURI ,
185- "authorization_response" : map [string ]interface {}{
186- "type" : "authorization_response" ,
187- "response" : map [string ]string {
188- "error" : "login_required" ,
189- "error_description" : "Login is required" ,
224+ if isQuery {
225+ gc .Redirect (http .StatusFound , loginURL )
226+ } else {
227+ gc .HTML (http .StatusOK , template , gin.H {
228+ "target_origin" : redirectURI ,
229+ "authorization_response" : map [string ]interface {}{
230+ "type" : "authorization_response" ,
231+ "response" : map [string ]string {
232+ "error" : "login_required" ,
233+ "error_description" : "Login is required" ,
234+ },
190235 },
191- },
192- })
236+ })
237+ }
193238 return
194239 }
195240
@@ -214,16 +259,20 @@ func AuthorizeHandler() gin.HandlerFunc {
214259 // rollover the session for security
215260 authToken , err := token .CreateAuthToken (gc , user , claims .Roles , scope )
216261 if err != nil {
217- gc .HTML (http .StatusOK , template , gin.H {
218- "target_origin" : redirectURI ,
219- "authorization_response" : map [string ]interface {}{
220- "type" : "authorization_response" ,
221- "response" : map [string ]string {
222- "error" : "login_required" ,
223- "error_description" : "Login is required" ,
262+ if isQuery {
263+ gc .Redirect (http .StatusFound , loginURL )
264+ } else {
265+ gc .HTML (http .StatusOK , template , gin.H {
266+ "target_origin" : redirectURI ,
267+ "authorization_response" : map [string ]interface {}{
268+ "type" : "authorization_response" ,
269+ "response" : map [string ]string {
270+ "error" : "login_required" ,
271+ "error_description" : "Login is required" ,
272+ },
224273 },
225- },
226- })
274+ })
275+ }
227276 return
228277 }
229278 sessionstore .RemoveState (sessionToken )
@@ -256,16 +305,20 @@ func AuthorizeHandler() gin.HandlerFunc {
256305 return
257306 }
258307
259- // by default return with error
260- gc .HTML (http .StatusOK , template , gin.H {
261- "target_origin" : redirectURI ,
262- "authorization_response" : map [string ]interface {}{
263- "type" : "authorization_response" ,
264- "response" : map [string ]string {
265- "error" : "login_required" ,
266- "error_description" : "Login is required" ,
308+ if isQuery {
309+ gc .Redirect (http .StatusFound , loginURL )
310+ } else {
311+ // by default return with error
312+ gc .HTML (http .StatusOK , template , gin.H {
313+ "target_origin" : redirectURI ,
314+ "authorization_response" : map [string ]interface {}{
315+ "type" : "authorization_response" ,
316+ "response" : map [string ]string {
317+ "error" : "login_required" ,
318+ "error_description" : "Login is required" ,
319+ },
267320 },
268- },
269- })
321+ })
322+ }
270323 }
271324}
0 commit comments