Require user to provide current password to be able to change it
Admins can change other users' password without providing the current one, but not when changing their own
This commit is contained in:
@@ -50,6 +50,7 @@ func (r *userRepository) Put(u *model.User) error {
|
||||
}
|
||||
u.UpdatedAt = time.Now()
|
||||
values, _ := toSqlArgs(*u)
|
||||
delete(values, "current_password")
|
||||
update := Update(r.tableName).Where(Eq{"id": u.ID}).SetMap(values)
|
||||
count, err := r.executeSQL(update)
|
||||
if err != nil {
|
||||
@@ -153,6 +154,9 @@ func (r *userRepository) Update(entity interface{}, cols ...string) error {
|
||||
u.IsAdmin = false
|
||||
u.UserName = usr.UserName
|
||||
}
|
||||
if err := validatePasswordChange(u, usr); err != nil {
|
||||
return err
|
||||
}
|
||||
err := r.Put(u)
|
||||
if err == model.ErrNotFound {
|
||||
return rest.ErrNotFound
|
||||
@@ -160,6 +164,28 @@ func (r *userRepository) Update(entity interface{}, cols ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func validatePasswordChange(newUser *model.User, logged *model.User) error {
|
||||
err := &rest.ValidationError{Errors: map[string]string{}}
|
||||
if logged.IsAdmin && newUser.ID != logged.ID {
|
||||
return nil
|
||||
}
|
||||
if newUser.NewPassword != "" && newUser.CurrentPassword == "" {
|
||||
err.Errors["currentPassword"] = "ra.validation.required"
|
||||
}
|
||||
if newUser.CurrentPassword != "" {
|
||||
if newUser.NewPassword == "" {
|
||||
err.Errors["password"] = "ra.validation.required"
|
||||
}
|
||||
if newUser.CurrentPassword != logged.Password {
|
||||
err.Errors["currentPassword"] = "ra.validation.passwordDoesNotMatch"
|
||||
}
|
||||
}
|
||||
if len(err.Errors) > 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *userRepository) Delete(id string) error {
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/deluan/rest"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
. "github.com/onsi/ginkgo"
|
||||
@@ -41,4 +42,106 @@ var _ = Describe("UserRepository", func() {
|
||||
Expect(actual.Name).To(Equal("Admin"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("validatePasswordChange", func() {
|
||||
var loggedUser *model.User
|
||||
|
||||
BeforeEach(func() {
|
||||
loggedUser = &model.User{ID: "1", UserName: "logan"}
|
||||
})
|
||||
|
||||
It("does nothing if passwords are not specified", func() {
|
||||
user := &model.User{ID: "2", UserName: "johndoe"}
|
||||
err := validatePasswordChange(user, loggedUser)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
Context("Logged User is admin", func() {
|
||||
BeforeEach(func() {
|
||||
loggedUser.IsAdmin = true
|
||||
})
|
||||
It("can change other user's passwords without currentPassword", func() {
|
||||
user := &model.User{ID: "2", UserName: "johndoe"}
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(user, loggedUser)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
It("requires currentPassword to change its own", func() {
|
||||
user := *loggedUser
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
verr := err.(*rest.ValidationError)
|
||||
Expect(verr.Errors).To(HaveLen(1))
|
||||
Expect(verr.Errors).To(HaveKeyWithValue("currentPassword", "ra.validation.required"))
|
||||
})
|
||||
It("does not allow to change password to empty string", func() {
|
||||
loggedUser.Password = "abc123"
|
||||
user := *loggedUser
|
||||
user.CurrentPassword = "abc123"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
verr := err.(*rest.ValidationError)
|
||||
Expect(verr.Errors).To(HaveLen(1))
|
||||
Expect(verr.Errors).To(HaveKeyWithValue("password", "ra.validation.required"))
|
||||
})
|
||||
It("fails if currentPassword does not match", func() {
|
||||
loggedUser.Password = "abc123"
|
||||
user := *loggedUser
|
||||
user.CurrentPassword = "current"
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
verr := err.(*rest.ValidationError)
|
||||
Expect(verr.Errors).To(HaveLen(1))
|
||||
Expect(verr.Errors).To(HaveKeyWithValue("currentPassword", "ra.validation.passwordDoesNotMatch"))
|
||||
})
|
||||
It("can change own password if requirements are met", func() {
|
||||
loggedUser.Password = "abc123"
|
||||
user := *loggedUser
|
||||
user.CurrentPassword = "abc123"
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Logged User is a regular user", func() {
|
||||
BeforeEach(func() {
|
||||
loggedUser.IsAdmin = false
|
||||
})
|
||||
It("requires currentPassword", func() {
|
||||
user := *loggedUser
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
verr := err.(*rest.ValidationError)
|
||||
Expect(verr.Errors).To(HaveLen(1))
|
||||
Expect(verr.Errors).To(HaveKeyWithValue("currentPassword", "ra.validation.required"))
|
||||
})
|
||||
It("does not allow to change password to empty string", func() {
|
||||
loggedUser.Password = "abc123"
|
||||
user := *loggedUser
|
||||
user.CurrentPassword = "abc123"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
verr := err.(*rest.ValidationError)
|
||||
Expect(verr.Errors).To(HaveLen(1))
|
||||
Expect(verr.Errors).To(HaveKeyWithValue("password", "ra.validation.required"))
|
||||
})
|
||||
It("fails if currentPassword does not match", func() {
|
||||
loggedUser.Password = "abc123"
|
||||
user := *loggedUser
|
||||
user.CurrentPassword = "current"
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
verr := err.(*rest.ValidationError)
|
||||
Expect(verr.Errors).To(HaveLen(1))
|
||||
Expect(verr.Errors).To(HaveKeyWithValue("currentPassword", "ra.validation.passwordDoesNotMatch"))
|
||||
})
|
||||
It("can change own password if requirements are met", func() {
|
||||
loggedUser.Password = "abc123"
|
||||
user := *loggedUser
|
||||
user.CurrentPassword = "abc123"
|
||||
user.NewPassword = "new"
|
||||
err := validatePasswordChange(&user, loggedUser)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user