User: use update function for password updates (#86419)
* Update password through Update function instead * Remove duplicated to lower * Refactor password code
This commit is contained in:
@@ -28,7 +28,6 @@ type store interface {
|
||||
GetByLogin(context.Context, *user.GetUserByLoginQuery) (*user.User, error)
|
||||
GetByEmail(context.Context, *user.GetUserByEmailQuery) (*user.User, error)
|
||||
Update(context.Context, *user.UpdateUserCommand) error
|
||||
ChangePassword(context.Context, *user.ChangeUserPasswordCommand) error
|
||||
UpdateLastSeenAt(context.Context, *user.UpdateUserLastSeenAtCommand) error
|
||||
GetSignedInUser(context.Context, *user.GetSignedInUserQuery) (*user.SignedInUser, error)
|
||||
UpdateUser(context.Context, *user.User) error
|
||||
@@ -300,20 +299,21 @@ func (ss *sqlStore) loginConflict(ctx context.Context, sess *db.Session, login,
|
||||
}
|
||||
|
||||
func (ss *sqlStore) Update(ctx context.Context, cmd *user.UpdateUserCommand) error {
|
||||
cmd.Login = strings.ToLower(cmd.Login)
|
||||
cmd.Email = strings.ToLower(cmd.Email)
|
||||
|
||||
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
user := user.User{
|
||||
Name: cmd.Name,
|
||||
Email: cmd.Email,
|
||||
Login: cmd.Login,
|
||||
Email: strings.ToLower(cmd.Email),
|
||||
Login: strings.ToLower(cmd.Login),
|
||||
Theme: cmd.Theme,
|
||||
Updated: time.Now(),
|
||||
}
|
||||
|
||||
q := sess.ID(cmd.UserID).Where(ss.notServiceAccountFilter())
|
||||
|
||||
if cmd.Password != nil {
|
||||
user.Password = *cmd.Password
|
||||
}
|
||||
|
||||
if cmd.IsDisabled != nil {
|
||||
sess.UseBool("is_disabled")
|
||||
user.IsDisabled = *cmd.IsDisabled
|
||||
@@ -352,18 +352,6 @@ func (ss *sqlStore) Update(ctx context.Context, cmd *user.UpdateUserCommand) err
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *sqlStore) ChangePassword(ctx context.Context, cmd *user.ChangeUserPasswordCommand) error {
|
||||
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
user := user.User{
|
||||
Password: cmd.NewPassword,
|
||||
Updated: time.Now(),
|
||||
}
|
||||
|
||||
_, err := sess.ID(cmd.UserID).Where(ss.notServiceAccountFilter()).Update(&user)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *sqlStore) UpdateLastSeenAt(ctx context.Context, cmd *user.UpdateUserLastSeenAtCommand) error {
|
||||
if cmd.UserID <= 0 {
|
||||
return user.ErrUpdateInvalidID
|
||||
|
||||
@@ -419,8 +419,31 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Change user password", func(t *testing.T) {
|
||||
err := userStore.ChangePassword(context.Background(), &user.ChangeUserPasswordCommand{})
|
||||
id, err := userStore.Insert(context.Background(), &user.User{
|
||||
Email: "password@test.com",
|
||||
Name: "password",
|
||||
Login: "password",
|
||||
Password: "password",
|
||||
Salt: "salt",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = userStore.Update(context.Background(), &user.UpdateUserCommand{
|
||||
UserID: id,
|
||||
Password: passwordPtr("updated"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
updated, err := userStore.GetByID(context.Background(), id)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, updated.Salt, "salt")
|
||||
assert.Equal(t, updated.Name, "password")
|
||||
assert.Equal(t, updated.Login, "password")
|
||||
assert.Equal(t, updated.Email, "password@test.com")
|
||||
assert.Equal(t, updated.Password, user.Password("updated"))
|
||||
})
|
||||
|
||||
t.Run("update last seen at", func(t *testing.T) {
|
||||
@@ -956,8 +979,8 @@ func TestIntegrationUserUpdate(t *testing.T) {
|
||||
require.Equal(t, "Change Name", result.Name)
|
||||
|
||||
// Unchanged
|
||||
require.Equal(t, "loginUSER3", result.Login)
|
||||
require.Equal(t, "USER3@test.com", result.Email)
|
||||
require.Equal(t, "loginuser3", result.Login)
|
||||
require.Equal(t, "user3@test.com", result.Email)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1034,6 +1057,11 @@ func createOrgAndUserSvc(t *testing.T, store db.DB, cfg *setting.Cfg) (org.Servi
|
||||
return orgService, usrSvc
|
||||
}
|
||||
|
||||
func passwordPtr(s string) *user.Password {
|
||||
password := user.Password(s)
|
||||
return &password
|
||||
}
|
||||
|
||||
func boolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
@@ -134,9 +134,9 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
// create user
|
||||
usr := &user.User{
|
||||
UID: cmd.UID,
|
||||
Email: cmd.Email,
|
||||
Email: strings.ToLower(cmd.Email),
|
||||
Name: cmd.Name,
|
||||
Login: cmd.Login,
|
||||
Login: strings.ToLower(cmd.Login),
|
||||
Company: cmd.Company,
|
||||
IsAdmin: cmd.IsAdmin,
|
||||
IsDisabled: cmd.IsDisabled,
|
||||
@@ -160,11 +160,14 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
usr.Rands = rands
|
||||
|
||||
if len(cmd.Password) > 0 {
|
||||
encodedPassword, err := util.EncodePassword(string(cmd.Password), usr.Salt)
|
||||
if err := cmd.Password.Validate(s.cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
usr.Password, err = cmd.Password.Hash(usr.Salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usr.Password = user.Password(encodedPassword)
|
||||
}
|
||||
|
||||
_, err = s.store.Insert(ctx, usr)
|
||||
@@ -220,16 +223,37 @@ func (s *Service) GetByEmail(ctx context.Context, query *user.GetUserByEmailQuer
|
||||
}
|
||||
|
||||
func (s *Service) Update(ctx context.Context, cmd *user.UpdateUserCommand) error {
|
||||
cmd.Login = strings.ToLower(cmd.Login)
|
||||
cmd.Email = strings.ToLower(cmd.Email)
|
||||
usr, err := s.store.GetByID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cmd.OldPassword != nil {
|
||||
old, err := cmd.OldPassword.Hash(usr.Salt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if old != usr.Password {
|
||||
return user.ErrPasswordMissmatch.Errorf("old password does not match stored password")
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.Password != nil {
|
||||
if err := cmd.Password.Validate(s.cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hashed, err := cmd.Password.Hash(usr.Salt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Password = &hashed
|
||||
}
|
||||
|
||||
return s.store.Update(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *Service) ChangePassword(ctx context.Context, cmd *user.ChangeUserPasswordCommand) error {
|
||||
return s.store.ChangePassword(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateLastSeenAt(ctx context.Context, cmd *user.UpdateUserLastSeenAtCommand) error {
|
||||
u, err := s.GetSignedInUserWithCacheCtx(ctx, &user.GetSignedInUserQuery{
|
||||
UserID: cmd.UserID,
|
||||
|
||||
@@ -154,6 +154,32 @@ func TestUserService(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_Update(t *testing.T) {
|
||||
t.Run("should return error if old password does not match stored password", func(t *testing.T) {
|
||||
stored, err := user.Password("test").Hash("salt")
|
||||
require.NoError(t, err)
|
||||
service := &Service{store: &FakeUserStore{ExpectedUser: &user.User{Password: stored, Salt: "salt"}}}
|
||||
|
||||
err = service.Update(context.Background(), &user.UpdateUserCommand{
|
||||
OldPassword: passwordPtr("test123"),
|
||||
})
|
||||
|
||||
assert.ErrorIs(t, err, user.ErrPasswordMissmatch)
|
||||
})
|
||||
|
||||
t.Run("should return error new password is not valid", func(t *testing.T) {
|
||||
stored, err := user.Password("test").Hash("salt")
|
||||
require.NoError(t, err)
|
||||
service := &Service{cfg: setting.NewCfg(), store: &FakeUserStore{ExpectedUser: &user.User{Password: stored, Salt: "salt"}}}
|
||||
|
||||
err = service.Update(context.Background(), &user.UpdateUserCommand{
|
||||
OldPassword: passwordPtr("test"),
|
||||
Password: passwordPtr("asd"),
|
||||
})
|
||||
require.ErrorIs(t, err, user.ErrPasswordTooShort)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMetrics(t *testing.T) {
|
||||
userStore := newUserStoreFake()
|
||||
orgService := orgtest.NewOrgServiceFake()
|
||||
@@ -234,10 +260,6 @@ func (f *FakeUserStore) Update(ctx context.Context, cmd *user.UpdateUserCommand)
|
||||
return f.ExpectedError
|
||||
}
|
||||
|
||||
func (f *FakeUserStore) ChangePassword(ctx context.Context, cmd *user.ChangeUserPasswordCommand) error {
|
||||
return f.ExpectedError
|
||||
}
|
||||
|
||||
func (f *FakeUserStore) UpdateLastSeenAt(ctx context.Context, cmd *user.UpdateUserLastSeenAtCommand) error {
|
||||
return f.ExpectedError
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user