mirror of https://github.com/h44z/wg-portal.git
				
				
				
			improve logging of OAuth login issues, decrease auth-code exchange timeout (#451)
This commit is contained in:
		
							parent
							
								
									61d8aa6589
								
							
						
					
					
						commit
						e3b65ca337
					
				|  | @ -57,6 +57,52 @@ | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "/auth/login/{provider}/callback": { | ||||||
|  |             "get": { | ||||||
|  |                 "produces": [ | ||||||
|  |                     "application/json" | ||||||
|  |                 ], | ||||||
|  |                 "tags": [ | ||||||
|  |                     "Authentication" | ||||||
|  |                 ], | ||||||
|  |                 "summary": "Handle the OAuth callback.", | ||||||
|  |                 "operationId": "auth_handleOauthCallbackGet", | ||||||
|  |                 "responses": { | ||||||
|  |                     "200": { | ||||||
|  |                         "description": "OK", | ||||||
|  |                         "schema": { | ||||||
|  |                             "type": "array", | ||||||
|  |                             "items": { | ||||||
|  |                                 "$ref": "#/definitions/model.LoginProviderInfo" | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "/auth/login/{provider}/init": { | ||||||
|  |             "get": { | ||||||
|  |                 "produces": [ | ||||||
|  |                     "application/json" | ||||||
|  |                 ], | ||||||
|  |                 "tags": [ | ||||||
|  |                     "Authentication" | ||||||
|  |                 ], | ||||||
|  |                 "summary": "Initiate the OAuth login flow.", | ||||||
|  |                 "operationId": "auth_handleOauthInitiateGet", | ||||||
|  |                 "responses": { | ||||||
|  |                     "200": { | ||||||
|  |                         "description": "OK", | ||||||
|  |                         "schema": { | ||||||
|  |                             "type": "array", | ||||||
|  |                             "items": { | ||||||
|  |                                 "$ref": "#/definitions/model.LoginProviderInfo" | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "/auth/logout": { |         "/auth/logout": { | ||||||
|             "post": { |             "post": { | ||||||
|                 "produces": [ |                 "produces": [ | ||||||
|  | @ -275,52 +321,6 @@ | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "/auth/{provider}/callback": { |  | ||||||
|             "get": { |  | ||||||
|                 "produces": [ |  | ||||||
|                     "application/json" |  | ||||||
|                 ], |  | ||||||
|                 "tags": [ |  | ||||||
|                     "Authentication" |  | ||||||
|                 ], |  | ||||||
|                 "summary": "Handle the OAuth callback.", |  | ||||||
|                 "operationId": "auth_handleOauthCallbackGet", |  | ||||||
|                 "responses": { |  | ||||||
|                     "200": { |  | ||||||
|                         "description": "OK", |  | ||||||
|                         "schema": { |  | ||||||
|                             "type": "array", |  | ||||||
|                             "items": { |  | ||||||
|                                 "$ref": "#/definitions/model.LoginProviderInfo" |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "/auth/{provider}/init": { |  | ||||||
|             "get": { |  | ||||||
|                 "produces": [ |  | ||||||
|                     "application/json" |  | ||||||
|                 ], |  | ||||||
|                 "tags": [ |  | ||||||
|                     "Authentication" |  | ||||||
|                 ], |  | ||||||
|                 "summary": "Initiate the OAuth login flow.", |  | ||||||
|                 "operationId": "auth_handleOauthInitiateGet", |  | ||||||
|                 "responses": { |  | ||||||
|                     "200": { |  | ||||||
|                         "description": "OK", |  | ||||||
|                         "schema": { |  | ||||||
|                             "type": "array", |  | ||||||
|                             "items": { |  | ||||||
|                                 "$ref": "#/definitions/model.LoginProviderInfo" |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "/config/frontend.js": { |         "/config/frontend.js": { | ||||||
|             "get": { |             "get": { | ||||||
|                 "produces": [ |                 "produces": [ | ||||||
|  | @ -2234,6 +2234,9 @@ | ||||||
|                 "MailLinkOnly": { |                 "MailLinkOnly": { | ||||||
|                     "type": "boolean" |                     "type": "boolean" | ||||||
|                 }, |                 }, | ||||||
|  |                 "MinPasswordLength": { | ||||||
|  |                     "type": "integer" | ||||||
|  |                 }, | ||||||
|                 "PersistentConfigSupported": { |                 "PersistentConfigSupported": { | ||||||
|                     "type": "boolean" |                     "type": "boolean" | ||||||
|                 }, |                 }, | ||||||
|  |  | ||||||
|  | @ -383,6 +383,8 @@ definitions: | ||||||
|         type: boolean |         type: boolean | ||||||
|       MailLinkOnly: |       MailLinkOnly: | ||||||
|         type: boolean |         type: boolean | ||||||
|  |       MinPasswordLength: | ||||||
|  |         type: integer | ||||||
|       PersistentConfigSupported: |       PersistentConfigSupported: | ||||||
|         type: boolean |         type: boolean | ||||||
|       SelfProvisioning: |       SelfProvisioning: | ||||||
|  | @ -472,7 +474,22 @@ paths: | ||||||
|       summary: Get all available audit entries. Ordered by timestamp. |       summary: Get all available audit entries. Ordered by timestamp. | ||||||
|       tags: |       tags: | ||||||
|       - Audit |       - Audit | ||||||
|   /auth/{provider}/callback: |   /auth/login: | ||||||
|  |     post: | ||||||
|  |       operationId: auth_handleLoginPost | ||||||
|  |       produces: | ||||||
|  |       - application/json | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: OK | ||||||
|  |           schema: | ||||||
|  |             items: | ||||||
|  |               $ref: '#/definitions/model.LoginProviderInfo' | ||||||
|  |             type: array | ||||||
|  |       summary: Get all available external login providers. | ||||||
|  |       tags: | ||||||
|  |       - Authentication | ||||||
|  |   /auth/login/{provider}/callback: | ||||||
|     get: |     get: | ||||||
|       operationId: auth_handleOauthCallbackGet |       operationId: auth_handleOauthCallbackGet | ||||||
|       produces: |       produces: | ||||||
|  | @ -487,7 +504,7 @@ paths: | ||||||
|       summary: Handle the OAuth callback. |       summary: Handle the OAuth callback. | ||||||
|       tags: |       tags: | ||||||
|       - Authentication |       - Authentication | ||||||
|   /auth/{provider}/init: |   /auth/login/{provider}/init: | ||||||
|     get: |     get: | ||||||
|       operationId: auth_handleOauthInitiateGet |       operationId: auth_handleOauthInitiateGet | ||||||
|       produces: |       produces: | ||||||
|  | @ -502,21 +519,6 @@ paths: | ||||||
|       summary: Initiate the OAuth login flow. |       summary: Initiate the OAuth login flow. | ||||||
|       tags: |       tags: | ||||||
|       - Authentication |       - Authentication | ||||||
|   /auth/login: |  | ||||||
|     post: |  | ||||||
|       operationId: auth_handleLoginPost |  | ||||||
|       produces: |  | ||||||
|       - application/json |  | ||||||
|       responses: |  | ||||||
|         "200": |  | ||||||
|           description: OK |  | ||||||
|           schema: |  | ||||||
|             items: |  | ||||||
|               $ref: '#/definitions/model.LoginProviderInfo' |  | ||||||
|             type: array |  | ||||||
|       summary: Get all available external login providers. |  | ||||||
|       tags: |  | ||||||
|       - Authentication |  | ||||||
|   /auth/logout: |   /auth/logout: | ||||||
|     post: |     post: | ||||||
|       operationId: auth_handleLogoutPost |       operationId: auth_handleLogoutPost | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ package handlers | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"log/slog" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  | @ -189,7 +190,7 @@ func (e AuthEndpoint) handleSessionInfoGet() http.HandlerFunc { | ||||||
| // @Summary Initiate the OAuth login flow.
 | // @Summary Initiate the OAuth login flow.
 | ||||||
| // @Produce json
 | // @Produce json
 | ||||||
| // @Success 200 {object} []model.LoginProviderInfo
 | // @Success 200 {object} []model.LoginProviderInfo
 | ||||||
| // @Router /auth/{provider}/init [get]
 | // @Router /auth/login/{provider}/init [get]
 | ||||||
| func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { | func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		currentSession := e.session.GetData(r.Context()) | 		currentSession := e.session.GetData(r.Context()) | ||||||
|  | @ -234,6 +235,8 @@ func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { | ||||||
| 
 | 
 | ||||||
| 		authCodeUrl, state, nonce, err := e.authService.OauthLoginStep1(context.Background(), provider) | 		authCodeUrl, state, nonce, err := e.authService.OauthLoginStep1(context.Background(), provider) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | 			slog.Debug("failed to create oauth auth code URL", | ||||||
|  | 				"provider", provider, "error", err) | ||||||
| 			if autoRedirect && e.isValidReturnUrl(returnTo) { | 			if autoRedirect && e.isValidReturnUrl(returnTo) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
|  | @ -268,7 +271,7 @@ func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { | ||||||
| // @Summary Handle the OAuth callback.
 | // @Summary Handle the OAuth callback.
 | ||||||
| // @Produce json
 | // @Produce json
 | ||||||
| // @Success 200 {object} []model.LoginProviderInfo
 | // @Success 200 {object} []model.LoginProviderInfo
 | ||||||
| // @Router /auth/{provider}/callback [get]
 | // @Router /auth/login/{provider}/callback [get]
 | ||||||
| func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { | func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		currentSession := e.session.GetData(r.Context()) | 		currentSession := e.session.GetData(r.Context()) | ||||||
|  | @ -306,6 +309,8 @@ func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { | ||||||
| 		oauthState := request.Query(r, "state") | 		oauthState := request.Query(r, "state") | ||||||
| 
 | 
 | ||||||
| 		if provider != currentSession.OauthProvider { | 		if provider != currentSession.OauthProvider { | ||||||
|  | 			slog.Debug("invalid oauth provider in callback", | ||||||
|  | 				"expected", currentSession.OauthProvider, "got", provider, "state", oauthState) | ||||||
| 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
|  | @ -315,6 +320,8 @@ func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		if oauthState != currentSession.OauthState { | 		if oauthState != currentSession.OauthState { | ||||||
|  | 			slog.Debug("invalid oauth state in callback", | ||||||
|  | 				"expected", currentSession.OauthState, "got", oauthState, "provider", provider) | ||||||
| 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
|  | @ -324,11 +331,13 @@ func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		loginCtx, cancel := context.WithTimeout(context.Background(), 1000*time.Second) | 		loginCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // avoid long waits
 | ||||||
| 		user, err := e.authService.OauthLoginStep2(loginCtx, provider, currentSession.OauthNonce, | 		user, err := e.authService.OauthLoginStep2(loginCtx, provider, currentSession.OauthNonce, | ||||||
| 			oauthCode) | 			oauthCode) | ||||||
| 		cancel() | 		cancel() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | 			slog.Debug("failed to process oauth code", | ||||||
|  | 				"provider", provider, "state", oauthState, "error", err) | ||||||
| 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | 			if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { | ||||||
| 				redirectToReturn() | 				redirectToReturn() | ||||||
| 			} else { | 			} else { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue