fix: Add route for user to change own password (#1812)

This commit is contained in:
Garrett Delfosse
2022-05-27 17:29:55 +00:00
committed by GitHub
parent 608eb322a8
commit 24d1a6744a
6 changed files with 99 additions and 13 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ func (api *API) assignableOrgRoles(rw http.ResponseWriter, r *http.Request) {
func (api *API) checkPermissions(rw http.ResponseWriter, r *http.Request) {
user := httpmw.UserParam(r)
if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceUser.WithOwner(user.ID.String())) {
if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceUser.WithID(user.ID.String())) {
return
}
+16
View File
@@ -121,3 +121,19 @@ func hashWithSaltAndIter(password string, salt []byte, iter int) string {
return fmt.Sprintf("$%s$%d$%s$%s", hashScheme, iter, encSalt, encHash)
}
// Validate checks that the plain text password meets the minimum password requirements.
// It returns properly formatted errors for detailed form validation on the client.
func Validate(password string) error {
const (
minLength = 8
maxLength = 64
)
if len(password) < minLength {
return xerrors.Errorf("Password must be at least %d characters.", minLength)
}
if len(password) > maxLength {
return xerrors.Errorf("Password must be no more than %d characters.", maxLength)
}
return nil
}
+38
View File
@@ -355,6 +355,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) {
var (
user = httpmw.UserParam(r)
apiKey = httpmw.APIKey(r)
params codersdk.UpdateUserPasswordRequest
)
@@ -366,6 +367,43 @@ func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) {
return
}
err := userpassword.Validate(params.Password)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Errors: []httpapi.Error{
{
Field: "password",
Detail: err.Error(),
},
},
})
return
}
// we want to require old_password field if the user is changing their
// own password. This is to prevent a compromised session from being able
// to change password and lock out the user.
if user.ID == apiKey.UserID {
ok, err := userpassword.Compare(string(user.HashedPassword), params.OldPassword)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("compare user password: %s", err.Error()),
})
return
}
if !ok {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Errors: []httpapi.Error{
{
Field: "old_password",
Detail: "Old password is incorrect.",
},
},
})
return
}
}
hashedPassword, err := userpassword.Hash(params.Password)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
+30
View File
@@ -324,6 +324,36 @@ func TestUpdateUserPassword(t *testing.T) {
})
require.NoError(t, err, "member should login successfully with the new password")
})
t.Run("MemberCanUpdateOwnPassword", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
admin := coderdtest.CreateFirstUser(t, client)
member := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
err := member.UpdateUserPassword(context.Background(), "me", codersdk.UpdateUserPasswordRequest{
OldPassword: "testpass",
Password: "newpassword",
})
require.NoError(t, err, "member should be able to update own password")
})
t.Run("MemberCantUpdateOwnPasswordWithoutOldPassword", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
admin := coderdtest.CreateFirstUser(t, client)
member := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
err := member.UpdateUserPassword(context.Background(), "me", codersdk.UpdateUserPasswordRequest{
Password: "newpassword",
})
require.Error(t, err, "member should not be able to update own password without providing old password")
})
t.Run("AdminCantUpdateOwnPasswordWithoutOldPassword", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
err := client.UpdateUserPassword(context.Background(), "me", codersdk.UpdateUserPasswordRequest{
Password: "newpassword",
})
require.Error(t, err, "admin should not be able to update own password without providing old password")
})
}
func TestGrantRoles(t *testing.T) {