Skip to content

Commit e1bba9c

Browse files
authored
Improve oauth2 error handling (#33969)
Show the callback error to end users, it should be safe. Fix #33967
1 parent 1c5c13a commit e1bba9c

File tree

4 files changed

+32
-18
lines changed

4 files changed

+32
-18
lines changed

Diff for: options/locale/locale_en-US.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ oauth_signup_submit = Complete Account
457457
oauth_signin_tab = Link to Existing Account
458458
oauth_signin_title = Sign In to Authorize Linked Account
459459
oauth_signin_submit = Link Account
460-
oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator.
460+
oauth.signin.error.general = There was an error processing the authorization request: %s. If this error persists, please contact the site administrator.
461461
oauth.signin.error.access_denied = The authorization request was denied.
462462
oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later.
463463
oauth_callback_unable_auto_reg = Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically, please create or link to an account, or contact the site administrator.

Diff for: routers/web/auth/auth_test.go

+26-14
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,35 @@ func TestUserLogin(t *testing.T) {
6161
assert.Equal(t, "/", test.RedirectURL(resp))
6262
}
6363

64-
func TestSignUpOAuth2ButMissingFields(t *testing.T) {
64+
func TestSignUpOAuth2Login(t *testing.T) {
6565
defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
66-
defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
67-
return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
68-
})()
6966

7067
addOAuth2Source(t, "dummy-auth-source", oauth2.Source{})
7168

72-
mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
73-
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt)
74-
ctx.SetPathParam("provider", "dummy-auth-source")
75-
SignInOAuthCallback(ctx)
76-
assert.Equal(t, http.StatusSeeOther, resp.Code)
77-
assert.Equal(t, "/user/link_account", test.RedirectURL(resp))
69+
t.Run("OAuth2MissingField", func(t *testing.T) {
70+
defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
71+
return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
72+
})()
73+
mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
74+
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt)
75+
ctx.SetPathParam("provider", "dummy-auth-source")
76+
SignInOAuthCallback(ctx)
77+
assert.Equal(t, http.StatusSeeOther, resp.Code)
78+
assert.Equal(t, "/user/link_account", test.RedirectURL(resp))
79+
80+
// then the user will be redirected to the link account page, and see a message about the missing fields
81+
ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt)
82+
LinkAccount(ctx)
83+
assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"])
84+
})
7885

79-
// then the user will be redirected to the link account page, and see a message about the missing fields
80-
ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt)
81-
LinkAccount(ctx)
82-
assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"])
86+
t.Run("OAuth2CallbackError", func(t *testing.T) {
87+
mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
88+
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback", mockOpt)
89+
ctx.SetPathParam("provider", "dummy-auth-source")
90+
SignInOAuthCallback(ctx)
91+
assert.Equal(t, http.StatusSeeOther, resp.Code)
92+
assert.Equal(t, "/user/login", test.RedirectURL(resp))
93+
assert.Contains(t, ctx.Flash.ErrorMsg, "auth.oauth.signin.error.general")
94+
})
8395
}

Diff for: routers/web/auth/oauth.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func SignInOAuthCallback(ctx *context.Context) {
115115
case "temporarily_unavailable":
116116
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.temporarily_unavailable"))
117117
default:
118-
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error"))
118+
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.general", callbackErr.Description))
119119
}
120120
ctx.Redirect(setting.AppSubURL + "/user/login")
121121
return
@@ -431,8 +431,10 @@ func oAuth2UserLoginCallback(ctx *context.Context, authSource *auth.Source, requ
431431
gothUser, err := oauth2Source.Callback(request, response)
432432
if err != nil {
433433
if err.Error() == "securecookie: the value is too long" || strings.Contains(err.Error(), "Data too long") {
434-
log.Error("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
435434
err = fmt.Errorf("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
435+
log.Error("oauth2Source.Callback failed: %v", err)
436+
} else {
437+
err = errCallback{Code: "internal", Description: err.Error()}
436438
}
437439
return nil, goth.User{}, err
438440
}

Diff for: tests/integration/oauth_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"code.gitea.io/gitea/modules/json"
2020
"code.gitea.io/gitea/modules/setting"
2121
api "code.gitea.io/gitea/modules/structs"
22-
oauth2_provider "code.gitea.io/gitea/services/oauth2_provider"
22+
"code.gitea.io/gitea/services/oauth2_provider"
2323
"code.gitea.io/gitea/tests"
2424

2525
"github.com/stretchr/testify/assert"

0 commit comments

Comments
 (0)