feat: admin impersonates a user (#38614)

* fix #3631
* fix #21599

by the way, refactored the "profile avatar card" to simplify the code.
This commit is contained in:
wxiaoguang
2026-07-26 17:26:02 +00:00
committed by GitHub
parent 470d34b1de
commit a3caf21440
18 changed files with 278 additions and 238 deletions
+16 -25
View File
@@ -118,9 +118,8 @@ func autoSignIn(ctx *context.Context) (bool, error) {
ctx.SetSiteCookie(setting.CookieRememberName, nt.ID+":"+token, setting.LogInRememberDays*timeutil.Day)
if err := regenerateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
}); err != nil {
return false, fmt.Errorf("unable to updateSession: %w", err)
@@ -357,7 +356,7 @@ func SignInPost(ctx *context.Context) {
// User will need to use WebAuthn, save data
updates["totpEnrolled"] = u.ID
}
if err := regenerateSession(ctx, nil, updates); err != nil {
if err := regenerateSession(ctx, updates); err != nil {
ctx.ServerError("UserSignIn: Unable to update session", err)
return
}
@@ -398,19 +397,9 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember bool) {
return
}
if err := regenerateSession(ctx, []string{
// Delete the openid, 2fa and link_account data
"openid_verified_uri",
"openid_signin_remember",
"openid_determined_email",
"openid_determined_username",
"twofaUid",
"twofaRemember",
"linkAccount",
"linkAccountData",
}, map[string]any{
auth_service.ClearSessionKeysForSignIn(ctx.Session)
if err := regenerateSession(ctx, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
}); err != nil {
ctx.ServerError("RegenerateSession", err)
@@ -477,6 +466,16 @@ func SignOut(ctx *context.Context) {
})
}
exitedImpersonated, err := auth_service.ExitImpersonatedUser(ctx.Session)
if err != nil {
ctx.ServerError("ExitImpersonatedUser", err)
return
}
if exitedImpersonated {
ctx.Redirect(setting.AppSubURL + "/-/admin")
return
}
// prepare the sign-out URL before destroying the session
redirectTo := buildSignOutRedirectURL(ctx)
HandleSignOut(ctx)
@@ -884,10 +883,7 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) {
log.Trace("User activated: %s", user.Name)
if err := regenerateSession(ctx, nil, map[string]any{
"uid": user.ID,
"uname": user.Name,
}); err != nil {
if err := regenerateSession(ctx, map[string]any{session.KeyUID: user.ID}); err != nil {
log.Error("Unable to regenerate session for user: %-v with email: %s: %v", user, user.Email, err)
ctx.ServerError("ActivateUserEmail", err)
return
@@ -936,17 +932,12 @@ func ActivateEmail(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
}
func regenerateSession(ctx *context.Context, deletes []string, updates map[string]any) error {
func regenerateSession(ctx *context.Context, updates map[string]any) error {
if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil {
return fmt.Errorf("regenerate session: %w", err)
}
sess := ctx.Session
sessID := sess.ID()
for _, k := range deletes {
if err := sess.Delete(k); err != nil {
return fmt.Errorf("delete %v in session[%s]: %w", k, sessID, err)
}
}
for k, v := range updates {
if err := sess.Set(k, v); err != nil {
return fmt.Errorf("set %v in session[%s]: %w", k, sessID, err)
+1 -1
View File
@@ -169,7 +169,7 @@ func oauth2LinkAccount(ctx *context.Context, u *user_model.User, linkAccountData
return
}
if err := regenerateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, map[string]any{
// User needs to use 2FA, save data and redirect to 2FA page.
"twofaUid": u.ID,
"twofaRemember": remember,
+2 -3
View File
@@ -428,9 +428,8 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
return
}
if err := regenerateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, map[string]any{
session.KeyUID: u.ID,
session.KeyUname: u.Name,
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
}); err != nil {
ctx.ServerError("updateSession", err)
@@ -453,7 +452,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
}
}
if err := regenerateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, 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 := regenerateSession(ctx, nil, map[string]any{
if err := regenerateSession(ctx, map[string]any{
"openid_verified_uri": id,
"openid_determined_email": email,
"openid_determined_username": nickname,