diff options
Diffstat (limited to 'api4')
-rw-r--r-- | api4/apitestlib.go | 6 | ||||
-rw-r--r-- | api4/user.go | 38 | ||||
-rw-r--r-- | api4/user_test.go | 77 |
3 files changed, 117 insertions, 4 deletions
diff --git a/api4/apitestlib.go b/api4/apitestlib.go index f647ffa9c..2eaed4fd0 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -61,6 +61,8 @@ func Setup() *TestHelper { } func TearDown() { + utils.DisableDebugLogForTest() + options := map[string]bool{} options[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME] = true if result := <-app.Srv.Store.User().Search("", "fakeuser", options); result.Err != nil { @@ -86,6 +88,8 @@ func TearDown() { } } } + + utils.EnableDebugLogForTest() } func (me *TestHelper) InitBasic() *TestHelper { @@ -208,7 +212,7 @@ func (me *TestHelper) LoginBasicWithClient(client *model.Client4) { func (me *TestHelper) LoginBasic2WithClient(client *model.Client4) { utils.DisableDebugLogForTest() - client.Login(me.BasicUser.Email, me.BasicUser.Password) + client.Login(me.BasicUser2.Email, me.BasicUser2.Password) utils.EnableDebugLogForTest() } diff --git a/api4/user.go b/api4/user.go index cf9bb4ead..56cfc5d90 100644 --- a/api4/user.go +++ b/api4/user.go @@ -23,6 +23,7 @@ func InitUser() { BaseRoutes.User.Handle("", ApiSessionRequired(updateUser)).Methods("PUT") BaseRoutes.User.Handle("", ApiSessionRequired(deleteUser)).Methods("DELETE") BaseRoutes.User.Handle("/roles", ApiSessionRequired(updateUserRoles)).Methods("PUT") + BaseRoutes.User.Handle("/password", ApiSessionRequired(updatePassword)).Methods("PUT") BaseRoutes.Users.Handle("/login", ApiHandler(login)).Methods("POST") BaseRoutes.Users.Handle("/logout", ApiHandler(logout)).Methods("POST") @@ -281,6 +282,43 @@ func updateUserRoles(c *Context, w http.ResponseWriter, r *http.Request) { ReturnStatusOK(w) } +func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireUserId() + if c.Err != nil { + return + } + + props := model.MapFromJson(r.Body) + + newPassword := props["new_password"] + + c.LogAudit("attempted") + + var err *model.AppError + if c.Params.UserId == c.Session.UserId { + currentPassword := props["current_password"] + if len(currentPassword) <= 0 { + c.SetInvalidParam("current_password") + return + } + + err = app.UpdatePasswordAsUser(c.Params.UserId, currentPassword, newPassword, c.GetSiteURL()) + } else if app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { + err = app.UpdatePasswordByUserIdSendEmail(c.Params.UserId, newPassword, c.T("api.user.reset_password.method"), c.GetSiteURL()) + } else { + err = model.NewAppError("updatePassword", "api.user.update_password.context.app_error", nil, "", http.StatusForbidden) + } + + if err != nil { + c.LogAudit("failed") + c.Err = err + return + } else { + c.LogAudit("completed") + ReturnStatusOK(w) + } +} + func login(c *Context, w http.ResponseWriter, r *http.Request) { props := model.MapFromJson(r.Body) diff --git a/api4/user_test.go b/api4/user_test.go index dc8a82310..bf4612635 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -149,7 +149,6 @@ func TestGetUserByEmail(t *testing.T) { ruser, resp = Client.GetUserByEmail(user.Email, resp.Etag) CheckEtag(t, ruser, resp) - _, resp = Client.GetUserByEmail(GenerateTestUsername(), "") CheckBadRequestStatus(t, resp) @@ -287,7 +286,7 @@ func TestUpdateUser(t *testing.T) { func TestDeleteUser(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() Client := th.Client - + user := th.BasicUser th.LoginBasic() @@ -296,7 +295,7 @@ func TestDeleteUser(t *testing.T) { CheckForbiddenStatus(t, resp) Client.Logout() - + _, resp = Client.DeleteUser(user.Id) CheckUnauthorizedStatus(t, resp) @@ -510,3 +509,75 @@ func TestGetUsersNotInChannel(t *testing.T) { _, resp = th.SystemAdminClient.GetUsersNotInChannel(teamId, channelId, 0, 60, "") CheckNoError(t, resp) } + +func TestUpdateUserPassword(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + + password := "newpassword1" + pass, resp := Client.UpdateUserPassword(th.BasicUser.Id, th.BasicUser.Password, password) + CheckNoError(t, resp) + + if !pass { + t.Fatal("should have returned true") + } + + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, password, "") + CheckBadRequestStatus(t, resp) + + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, password, "junk") + CheckBadRequestStatus(t, resp) + + _, resp = Client.UpdateUserPassword("junk", password, password) + CheckBadRequestStatus(t, resp) + + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, "", password) + CheckBadRequestStatus(t, resp) + + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, "junk", password) + CheckBadRequestStatus(t, resp) + + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, password, th.BasicUser.Password) + CheckNoError(t, resp) + + Client.Logout() + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, password, password) + CheckUnauthorizedStatus(t, resp) + + th.LoginBasic2() + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, password, password) + CheckForbiddenStatus(t, resp) + + th.LoginBasic() + + // Test lockout + passwordAttempts := utils.Cfg.ServiceSettings.MaximumLoginAttempts + defer func() { + utils.Cfg.ServiceSettings.MaximumLoginAttempts = passwordAttempts + }() + utils.Cfg.ServiceSettings.MaximumLoginAttempts = 2 + + // Fail twice + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, "badpwd", "newpwd") + CheckBadRequestStatus(t, resp) + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, "badpwd", "newpwd") + CheckBadRequestStatus(t, resp) + + // Should fail because account is locked out + _, resp = Client.UpdateUserPassword(th.BasicUser.Id, th.BasicUser.Password, "newpwd") + CheckErrorMessage(t, resp, "api.user.check_user_login_attempts.too_many.app_error") + CheckForbiddenStatus(t, resp) + + // System admin can update another user's password + adminSetPassword := "pwdsetbyadmin" + pass, resp = th.SystemAdminClient.UpdateUserPassword(th.BasicUser.Id, "", adminSetPassword) + CheckNoError(t, resp) + + if !pass { + t.Fatal("should have returned true") + } + + _, resp = Client.Login(th.BasicUser.Email, adminSetPassword) + CheckNoError(t, resp) +} |