From 41c9b83b062562532390eef85f72d4c5e74e231e Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 11 Jul 2023 12:52:53 +0000 Subject: [PATCH] fix(coderd/httpmw): handle oauth config removed for existing auth This commit fixes an edge case tied to unexpired oauth logins where the oauth provider is removed, the server restarted, and the users auth expiring after the fact. Refs #8351, #8352, #8390 --- coderd/httpmw/apikey.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/coderd/httpmw/apikey.go b/coderd/httpmw/apikey.go index e103ddc0856e4..65732b0fcab92 100644 --- a/coderd/httpmw/apikey.go +++ b/coderd/httpmw/apikey.go @@ -77,6 +77,13 @@ type OAuth2Configs struct { OIDC OAuth2Config } +func (c *OAuth2Configs) IsZero() bool { + if c == nil { + return true + } + return c.Github == nil && c.OIDC == nil +} + const ( SignedOutErrorMessage = "You are signed out or your session has expired. Please sign in again to continue." internalErrorMessage = "An internal error occurred. Please try again or contact the system administrator." @@ -237,13 +244,14 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon } // Check if the OAuth token is expired if link.OAuthExpiry.Before(now) && !link.OAuthExpiry.IsZero() && link.OAuthRefreshToken != "" { - if cfg.OAuth2Configs == nil { + if cfg.OAuth2Configs.IsZero() { return write(http.StatusInternalServerError, codersdk.Response{ Message: internalErrorMessage, Detail: fmt.Sprintf("Unable to refresh OAuth token for login type %q. "+ "No OAuth2Configs provided. Contact an administrator to configure this login type.", key.LoginType), }) } + var oauthConfig OAuth2Config switch key.LoginType { case database.LoginTypeGithub: @@ -256,6 +264,19 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon Detail: fmt.Sprintf("Unexpected authentication type %q.", key.LoginType), }) } + + // It's possible for cfg.OAuth2Configs to be non-nil, but still + // missing this type. For example, if a user logged in with GitHub, + // but the administrator later removed GitHub and replaced it with + // OIDC. + if oauthConfig == nil { + return write(http.StatusInternalServerError, codersdk.Response{ + Message: internalErrorMessage, + Detail: fmt.Sprintf("Unable to refresh OAuth token for login type %q. "+ + "OAuth2Config not provided. Contact an administrator to configure this login type.", key.LoginType), + }) + } + // If it is, let's refresh it from the provided config token, err := oauthConfig.TokenSource(r.Context(), &oauth2.Token{ AccessToken: link.OAuthAccessToken,