fix(oauth2): persist linkAccountData during auto-link 2FA flow (#38274)

Fixes HTTP 500 when OIDC auto account linking (`ACCOUNT_LINKING=auto`)
requires local 2FA. `oauth2LinkAccount` set `linkAccount` in the session
before redirecting to 2FA but did not persist `linkAccountData`, so
`TwoFactorPost` failed with `not in LinkAccount session`. The manual
linking flow already stored both, this aligns auto-link with that
behavior.

Closes #38171

---------

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Aidan Fahey
2026-07-01 10:03:38 +00:00
committed by GitHub
co-authored by bircni wxiaoguang
parent 458c11bd68
commit 77e221ffaf
6 changed files with 89 additions and 12 deletions
+3
View File
@@ -147,6 +147,9 @@ func MustInitSessioner() func(next http.Handler) http.Handler {
Secure: setting.SessionConfig.Secure,
SameSite: setting.SessionConfig.SameSite,
Domain: setting.SessionConfig.Domain,
// in the future, if websocket is used, the websocket handler should manage its own session sync (release)
IgnoreReleaseForWebSocket: true,
})
if err != nil {
log.Fatal("common.Sessioner failed: %v", err)
+5 -5
View File
@@ -118,7 +118,7 @@ func autoSignIn(ctx *context.Context) (bool, error) {
ctx.SetSiteCookie(setting.CookieRememberName, nt.ID+":"+token, setting.LogInRememberDays*timeutil.Day)
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
@@ -357,7 +357,7 @@ func SignInPost(ctx *context.Context) {
// User will need to use WebAuthn, save data
updates["totpEnrolled"] = u.ID
}
if err := updateSession(ctx, nil, updates); err != nil {
if err := regenerateSession(ctx, nil, updates); err != nil {
ctx.ServerError("UserSignIn: Unable to update session", err)
return
}
@@ -398,7 +398,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember bool) {
return
}
if err := updateSession(ctx, []string{
if err := regenerateSession(ctx, []string{
// Delete the openid, 2fa and link_account data
"openid_verified_uri",
"openid_signin_remember",
@@ -884,7 +884,7 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) {
log.Trace("User activated: %s", user.Name)
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
"uid": user.ID,
"uname": user.Name,
}); err != nil {
@@ -936,7 +936,7 @@ func ActivateEmail(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
}
func updateSession(ctx *context.Context, deletes []string, updates map[string]any) error {
func regenerateSession(ctx *context.Context, deletes []string, updates map[string]any) error {
if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil {
return fmt.Errorf("regenerate session: %w", err)
}
+6 -1
View File
@@ -164,7 +164,12 @@ func oauth2LinkAccount(ctx *context.Context, u *user_model.User, linkAccountData
return
}
if err := updateSession(ctx, nil, map[string]any{
if err := Oauth2SetLinkAccountData(ctx, *linkAccountData); err != nil {
ctx.ServerError("Oauth2SetLinkAccountData", err)
return
}
if err := regenerateSession(ctx, nil, map[string]any{
// User needs to use 2FA, save data and redirect to 2FA page.
"twofaUid": u.ID,
"twofaRemember": remember,
+3 -5
View File
@@ -285,9 +285,7 @@ func oauth2GetLinkAccountData(ctx *context.Context) *LinkAccountData {
}
func Oauth2SetLinkAccountData(ctx *context.Context, linkAccountData LinkAccountData) error {
return updateSession(ctx, nil, map[string]any{
"linkAccountData": linkAccountData,
})
return ctx.Session.Set("linkAccountData", linkAccountData)
}
func showLinkingLogin(ctx *context.Context, authSourceID int64, gothUser goth.User) {
@@ -409,7 +407,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
return
}
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
@@ -434,7 +432,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
}
}
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
// User needs to use 2FA, save data and redirect to 2FA page.
"twofaUid": u.ID,
"twofaRemember": false,
+1 -1
View File
@@ -213,7 +213,7 @@ func signInOpenIDVerify(ctx *context.Context) {
if u != nil {
nickname = u.LowerName
}
if err := updateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, nil, map[string]any{
"openid_verified_uri": id,
"openid_determined_email": email,
"openid_determined_username": nickname,