[MM-58560] Configurable session revocation during password resets (#27286)
* [MM-58560] Allow for configurable session revocation during password reset * Missing i18n additions * Update Settings Wording * Update Settings Wording #2 * Update default_config.ts for Session Termination --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
cbd5d95bbb
Коммит
1bbc3b4e83
@@ -1453,6 +1453,31 @@ func (a *App) UpdatePassword(rctx request.CTX, user *model.User, newPassword str
|
||||
|
||||
a.InvalidateCacheForUser(user.Id)
|
||||
|
||||
if *a.Config().ServiceSettings.TerminateSessionsOnPasswordChange {
|
||||
// Get currently active sessions if request is user-initiated to retain it
|
||||
currentSession := ""
|
||||
if rctx.Session() != nil && rctx.Session().UserId == user.Id {
|
||||
currentSession = rctx.Session().Id
|
||||
}
|
||||
|
||||
sessions, err := a.GetSessions(rctx, user.Id)
|
||||
if err != nil {
|
||||
return model.NewAppError("UpdatePassword", "api.user.update_password.failed.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
// Revoke all but current session
|
||||
for _, session := range sessions {
|
||||
if session.Id == currentSession {
|
||||
continue
|
||||
}
|
||||
|
||||
err := a.RevokeSessionById(rctx, session.Id)
|
||||
if err != nil {
|
||||
return model.NewAppError("UpdatePassword", "api.user.update_password.failed.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1210,6 +1210,153 @@ func TestInvalidatePasswordRecoveryTokens(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestPasswordChangeSessionTermination(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
t.Run("user-initiated password change with termination enabled", func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(c *model.Config) {
|
||||
*c.ServiceSettings.TerminateSessionsOnPasswordChange = true
|
||||
})
|
||||
|
||||
session, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
session2, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
th.Context.Session().UserId = th.BasicUser2.Id
|
||||
th.Context.Session().Id = session.Id
|
||||
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password2")
|
||||
require.Nil(t, err)
|
||||
|
||||
session, err = th.App.GetSession(session.Token)
|
||||
require.Nil(t, err)
|
||||
require.False(t, session.IsExpired())
|
||||
|
||||
session2, err = th.App.GetSession(session2.Token)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, session2)
|
||||
|
||||
// Cleanup
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password1")
|
||||
require.Nil(t, err)
|
||||
th.Context.Session().UserId = ""
|
||||
th.Context.Session().Id = ""
|
||||
})
|
||||
|
||||
t.Run("user-initiated password change with termination disabled", func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(c *model.Config) {
|
||||
*c.ServiceSettings.TerminateSessionsOnPasswordChange = false
|
||||
})
|
||||
|
||||
session, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
session2, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
th.Context.Session().UserId = th.BasicUser2.Id
|
||||
th.Context.Session().Id = session.Id
|
||||
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password2")
|
||||
require.Nil(t, err)
|
||||
|
||||
session, err = th.App.GetSession(session.Token)
|
||||
require.Nil(t, err)
|
||||
require.False(t, session.IsExpired())
|
||||
|
||||
session2, err = th.App.GetSession(session2.Token)
|
||||
require.Nil(t, err)
|
||||
require.False(t, session2.IsExpired())
|
||||
|
||||
// Cleanup
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password1")
|
||||
require.Nil(t, err)
|
||||
th.Context.Session().UserId = ""
|
||||
th.Context.Session().Id = ""
|
||||
})
|
||||
|
||||
t.Run("admin-initiated password change with termination enabled", func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(c *model.Config) {
|
||||
*c.ServiceSettings.TerminateSessionsOnPasswordChange = true
|
||||
})
|
||||
|
||||
session, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
session2, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password2")
|
||||
require.Nil(t, err)
|
||||
|
||||
session, err = th.App.GetSession(session.Token)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, session)
|
||||
|
||||
session2, err = th.App.GetSession(session2.Token)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, session2)
|
||||
|
||||
// Cleanup
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password1")
|
||||
require.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("admin-initiated password change with termination disabled", func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(c *model.Config) {
|
||||
*c.ServiceSettings.TerminateSessionsOnPasswordChange = false
|
||||
})
|
||||
|
||||
session, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
session2, err := th.App.CreateSession(th.Context, &model.Session{
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password2")
|
||||
require.Nil(t, err)
|
||||
|
||||
session, err = th.App.GetSession(session.Token)
|
||||
require.Nil(t, err)
|
||||
require.False(t, session.IsExpired())
|
||||
|
||||
session2, err = th.App.GetSession(session2.Token)
|
||||
require.Nil(t, err)
|
||||
require.False(t, session2.IsExpired())
|
||||
|
||||
// Cleanup
|
||||
err = th.App.UpdatePassword(th.Context, th.BasicUser2, "Password1")
|
||||
require.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetViewUsersRestrictions(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
Ссылка в новой задаче
Block a user