diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/account/ResetPasswordController.java b/server/src/main/java/org/cloudfoundry/identity/uaa/account/ResetPasswordController.java index 360dc613fc5..b10f38d66b7 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/account/ResetPasswordController.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/account/ResetPasswordController.java @@ -38,6 +38,7 @@ import java.sql.Timestamp; import java.util.Map; +import static org.cloudfoundry.identity.uaa.account.UaaResetPasswordService.FORGOT_PASSWORD_INTENT_PREFIX; import static org.springframework.util.StringUtils.hasText; @Controller @@ -197,6 +198,11 @@ private ExpiringCode checkIfUserExists(ExpiringCode code) { logger.debug("reset_password ExpiringCode object is null. Aborting."); return null; } + String intent = code.getIntent(); + if (intent == null || !intent.startsWith(FORGOT_PASSWORD_INTENT_PREFIX)) { + logger.debug("reset_password ExpiringCode intent is not a forgot-password intent. Aborting."); + return null; + } if (!hasText(code.getData())) { logger.debug("reset_password ExpiringCode[{}] data string is null or empty. Aborting.", code.getCode()); return null; @@ -208,6 +214,10 @@ private ExpiringCode checkIfUserExists(ExpiringCode code) { return null; } String userId = data.get("user_id"); + if (!intent.equals(FORGOT_PASSWORD_INTENT_PREFIX + userId)) { + logger.debug("reset_password ExpiringCode intent does not match user_id. Aborting."); + return null; + } try { userDatabase.retrieveUserById(userId); } catch (UsernameNotFoundException _) { diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/account/UaaResetPasswordService.java b/server/src/main/java/org/cloudfoundry/identity/uaa/account/UaaResetPasswordService.java index b0256990e4f..912b9a5d304 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/account/UaaResetPasswordService.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/account/UaaResetPasswordService.java @@ -88,6 +88,10 @@ public void resetUserPassword(String userId, String password) { } private ResetPasswordResponse changePasswordCodeAuthenticated(ExpiringCode expiringCode, String newPassword) { + String intent = expiringCode.getIntent(); + if (intent == null || !intent.startsWith(FORGOT_PASSWORD_INTENT_PREFIX)) { + throw new InvalidCodeException("invalid_code", "Sorry, your reset password link is no longer valid. Please request a new one", UNPROCESSABLE_ENTITY.value()); + } String userId; String userName; Date passwordLastModified; @@ -97,9 +101,12 @@ private ResetPasswordResponse changePasswordCodeAuthenticated(ExpiringCode expir try { change = JsonUtils.readValue(expiringCode.getData(), PasswordChange.class); } catch (JsonUtils.JsonUtilException _) { - throw new InvalidCodeException("invalid_code", "Sorry, your reset password link is no longer valid. Please request a new one", 422); + throw new InvalidCodeException("invalid_code", "Sorry, your reset password link is no longer valid. Please request a new one", UNPROCESSABLE_ENTITY.value()); } userId = change.getUserId(); + if (!intent.equals(FORGOT_PASSWORD_INTENT_PREFIX + userId)) { + throw new InvalidCodeException("invalid_code", "Sorry, your reset password link is no longer valid. Please request a new one", UNPROCESSABLE_ENTITY.value()); + } userName = change.getUsername(); passwordLastModified = change.getPasswordModifiedTime(); clientId = change.getClientId(); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordResetEndpointTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordResetEndpointTest.java index 956354f892c..03e0e1c65af 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordResetEndpointTest.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/account/PasswordResetEndpointTest.java @@ -36,7 +36,9 @@ import java.util.Date; import static org.assertj.core.api.Assertions.assertThat; +import static org.cloudfoundry.identity.uaa.account.UaaResetPasswordService.FORGOT_PASSWORD_INTENT_PREFIX; import static org.cloudfoundry.identity.uaa.codestore.ExpiringCodeType.AUTOLOGIN; +import static org.cloudfoundry.identity.uaa.codestore.ExpiringCodeType.INVITATION; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -275,7 +277,8 @@ void creatingAPasswordResetWithAUsernameContainingSpecialCharacters() throws Exc @ValueSource(strings = {"/password_change", "/password_change/"}) void changingAPasswordWithAValidCode(String url) throws Exception { ExpiringCode code = new ExpiringCode("secret_code", new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), - "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", null); + "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", + FORGOT_PASSWORD_INTENT_PREFIX + "eyedee"); when(mockExpiringCodeStore.retrieveCode("secret_code", currentZoneId)).thenReturn(code); ScimUser scimUser = new ScimUser("eyedee", "user@example.com", "User", "Man"); @@ -323,7 +326,8 @@ void changingPasswordWithInvalidCode() throws Exception { @Test void changingAPasswordForUnverifiedUser() throws Exception { ExpiringCode code = new ExpiringCode("secret_code", new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), - "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", null); + "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", + FORGOT_PASSWORD_INTENT_PREFIX + "eyedee"); when(mockExpiringCodeStore.retrieveCode("secret_code", currentZoneId)).thenReturn(code); ScimUser scimUser = new ScimUser("eyedee", "user@example.com", "User", "Man"); @@ -369,7 +373,7 @@ void passwordsMustSatisfyPolicy() throws Exception { when(mockExpiringCodeStore.retrieveCode("emailed_code", currentZoneId)) .thenReturn(new ExpiringCode("emailed_code", new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", - null)); + FORGOT_PASSWORD_INTENT_PREFIX + "eyedee")); MockHttpServletRequestBuilder post = post("/password_change") .contentType(APPLICATION_JSON) @@ -391,7 +395,7 @@ void changePassword_Returns422UnprocessableEntity_NewPasswordSameAsOld() throws when(mockExpiringCodeStore.retrieveCode("emailed_code", currentZoneId)) .thenReturn(new ExpiringCode("emailed_code", new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", - null)); + FORGOT_PASSWORD_INTENT_PREFIX + "eyedee")); ScimUser scimUser = new ScimUser("eyedee", "user@example.com", "User", "Man"); scimUser.setMeta(new ScimMeta(new Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24)), new Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24)), 0)); @@ -414,4 +418,49 @@ void changePassword_Returns422UnprocessableEntity_NewPasswordSameAsOld() throws assertThat(JsonUtils.readTree(result.getResponse().getContentAsString())) .isEqualTo(JsonUtils.readTree(new JSONObject().put("error_description", "Your new password cannot be the same as the old password.").put("message", "Your new password cannot be the same as the old password.").put("error", "invalid_password").toString())); } + + @Test + void changingPasswordWithInvitationCodeReturns422() throws Exception { + String inviteData = "{\"user_id\":\"eyedee\",\"client_id\":\"invite-client\",\"created_new_user\":\"false\"}"; + ExpiringCode inviteCode = new ExpiringCode("invite_code", new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), + inviteData, INVITATION.name()); + when(mockExpiringCodeStore.retrieveCode("invite_code", currentZoneId)).thenReturn(inviteCode); + + MockHttpServletRequestBuilder post = post("/password_change") + .contentType(APPLICATION_JSON) + .content("{\"code\":\"invite_code\",\"new_password\":\"new_secret\"}") + .accept(APPLICATION_JSON); + + MvcResult result = mockMvc.perform(post) + .andExpect(status().isUnprocessableEntity()) + .andReturn(); + assertThat(JsonUtils.readTree(result.getResponse().getContentAsString())) + .isEqualTo(JsonUtils.readTree(new JSONObject() + .put("error_description", "Sorry, your reset password link is no longer valid. Please request a new one") + .put("message", "Sorry, your reset password link is no longer valid. Please request a new one") + .put("error", "invalid_code") + .toString())); + } + + @Test + void changingPasswordWithNullIntentCodeReturns422() throws Exception { + ExpiringCode nullIntentCode = new ExpiringCode("null_intent_code", new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), + "{\"user_id\":\"eyedee\",\"username\":\"user@example.com\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", null); + when(mockExpiringCodeStore.retrieveCode("null_intent_code", currentZoneId)).thenReturn(nullIntentCode); + + MockHttpServletRequestBuilder post = post("/password_change") + .contentType(APPLICATION_JSON) + .content("{\"code\":\"null_intent_code\",\"new_password\":\"new_secret\"}") + .accept(APPLICATION_JSON); + + MvcResult result = mockMvc.perform(post) + .andExpect(status().isUnprocessableEntity()) + .andReturn(); + assertThat(JsonUtils.readTree(result.getResponse().getContentAsString())) + .isEqualTo(JsonUtils.readTree(new JSONObject() + .put("error_description", "Sorry, your reset password link is no longer valid. Please request a new one") + .put("message", "Sorry, your reset password link is no longer valid. Please request a new one") + .put("error", "invalid_code") + .toString())); + } } diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerTest.java index 31dd93cbdbd..72e63ad0263 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerTest.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerTest.java @@ -51,6 +51,8 @@ import java.sql.Timestamp; import static org.assertj.core.api.Assertions.assertThat; +import static org.cloudfoundry.identity.uaa.account.UaaResetPasswordService.FORGOT_PASSWORD_INTENT_PREFIX; +import static org.cloudfoundry.identity.uaa.codestore.ExpiringCodeType.INVITATION; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.contains; import static org.mockito.Mockito.eq; @@ -290,7 +292,7 @@ void instructions() throws Exception { @Test void resetPasswordPage() throws Exception { - ExpiringCode code = codeStore.generateCode("{\"user_id\" : \"some-user-id\"}", new Timestamp(System.currentTimeMillis() + 1000000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode("{\"user_id\" : \"some-user-id\"}", new Timestamp(System.currentTimeMillis() + 1000000), FORGOT_PASSWORD_INTENT_PREFIX + "some-user-id", IdentityZoneHolder.get().getId()); MvcResult result = mockMvc.perform(get("/reset_password").param("email", "user@example.com").param("code", code.getCode())) .andExpect(status().isOk()) .andDo(print()) @@ -305,7 +307,7 @@ void resetPasswordPage() throws Exception { @Test void resetPasswordPageWithPriorHeadRequest() throws Exception { - ExpiringCode code = codeStore.generateCode("{\"user_id\" : \"some-user-id\"}", new Timestamp(System.currentTimeMillis() + 1000000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode("{\"user_id\" : \"some-user-id\"}", new Timestamp(System.currentTimeMillis() + 1000000), FORGOT_PASSWORD_INTENT_PREFIX + "some-user-id", IdentityZoneHolder.get().getId()); mockMvc.perform(head("/reset_password").param("email", "user@example.com").param("code", code.getCode())) .andExpect(status().isOk()); MvcResult result = mockMvc.perform(get("/reset_password").param("email", "user@example.com").param("code", code.getCode())) @@ -322,7 +324,7 @@ void resetPasswordPageWithPriorHeadRequest() throws Exception { @Test void resetPasswordPageDuplicate() throws Exception { - ExpiringCode code = codeStore.generateCode("{\"user_id\" : \"some-user-id\"}", new Timestamp(System.currentTimeMillis() + 1000000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode("{\"user_id\" : \"some-user-id\"}", new Timestamp(System.currentTimeMillis() + 1000000), FORGOT_PASSWORD_INTENT_PREFIX + "some-user-id", IdentityZoneHolder.get().getId()); mockMvc.perform(get("/reset_password").param("email", "user@example.com").param("code", code.getCode())) .andExpect(status().isOk()) .andExpect(view().name("reset_password")); @@ -339,6 +341,20 @@ void resetPasswordPageWhenExpiringCodeNull() throws Exception { .andExpect(model().attribute("message_code", "bad_code")); } + @Test + void resetPasswordPageWithInvitationCodeReturns422() throws Exception { + ExpiringCode inviteCode = codeStore.generateCode( + "{\"user_id\":\"some-user-id\",\"client_id\":\"invite-client\",\"created_new_user\":\"false\"}", + new Timestamp(System.currentTimeMillis() + 1000000), + INVITATION.name(), + IdentityZoneHolder.get().getId()); + + mockMvc.perform(get("/reset_password").param("code", inviteCode.getCode())) + .andExpect(status().isUnprocessableEntity()) + .andExpect(view().name("forgot_password")) + .andExpect(model().attribute("message_code", "bad_code")); + } + @EnableWebMvc @Import(ThymeleafConfig.class) static class ContextConfiguration implements WebMvcConfigurer { diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/login/UaaResetPasswordServiceTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/login/UaaResetPasswordServiceTests.java index 1240f6d8da0..d91db552a39 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/login/UaaResetPasswordServiceTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/login/UaaResetPasswordServiceTests.java @@ -203,7 +203,8 @@ void resetPassword_InvalidPasswordException_NewPasswordSameAsOld() { user.setMeta(new ScimMeta(new Date(), new Date(), 0)); user.setPrimaryEmail("foo@example.com"); ExpiringCode expiringCode = new ExpiringCode("good_code", - new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), "{\"user_id\":\"user-id\",\"username\":\"username\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", null); + new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), "{\"user_id\":\"user-id\",\"username\":\"username\",\"passwordModifiedTime\":null,\"client_id\":\"\",\"redirect_uri\":\"\"}", + UaaResetPasswordService.FORGOT_PASSWORD_INTENT_PREFIX + "user-id"); when(codeStore.retrieveCode("good_code", currentZoneId)).thenReturn(expiringCode); when(scimUserProvisioning.retrieve("user-id", currentZoneId)).thenReturn(user); when(scimUserProvisioning.checkPasswordMatches("user-id", "Passwo3dAsOld", currentZoneId)) @@ -236,6 +237,18 @@ void resetPassword_InvalidCodeData() { } } + @Test + void resetPassword_rejectsNonForgotPasswordIntent() { + ExpiringCode inviteCode = new ExpiringCode("good_code", + new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), + "{\"user_id\":\"user-id\",\"client_id\":\"invite-client\",\"created_new_user\":\"false\"}", "INVITATION"); + + assertThatThrownBy(() -> uaaResetPasswordService.resetPassword(inviteCode, "new_secret")) + .isInstanceOf(InvalidCodeException.class) + .hasMessage("Sorry, your reset password link is no longer valid. Please request a new one"); + verify(scimUserProvisioning, times(0)).changePassword(anyString(), any(), anyString(), anyString()); + } + @Test void resetPassword_WithInvalidClientId() { ExpiringCode code = setupResetPassword("invalid_client", "redirect.example.com"); @@ -320,7 +333,8 @@ private ExpiringCode setupResetPassword(String clientId, String redirectUri) { String zoneId = currentZoneId; when(scimUserProvisioning.retrieve(eq("usermans-id"), eq(zoneId))).thenReturn(user); ExpiringCode code = new ExpiringCode("code", new Timestamp(System.currentTimeMillis()), - "{\"user_id\":\"usermans-id\",\"username\":\"userman\",\"passwordModifiedTime\":null,\"client_id\":\"" + clientId + "\",\"redirect_uri\":\"" + redirectUri + "\"}", null); + "{\"user_id\":\"usermans-id\",\"username\":\"userman\",\"passwordModifiedTime\":null,\"client_id\":\"" + clientId + "\",\"redirect_uri\":\"" + redirectUri + "\"}", + UaaResetPasswordService.FORGOT_PASSWORD_INTENT_PREFIX + "usermans-id"); when(codeStore.retrieveCode(eq("secret_code"), anyString())).thenReturn(code); SecurityContext securityContext = mock(SecurityContext.class); when(securityContext.getAuthentication()).thenReturn(new MockAuthentication()); diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java index dba525ad069..9aac6697162 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java @@ -83,7 +83,7 @@ void resettingAPasswordUsingUsernameToEnsureNoModification() throws Exception { .hasSize(1); PasswordChange change = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), users.getFirst().getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(users.getFirst(), code, true)) .andExpect(status().isFound()) @@ -99,7 +99,7 @@ void resettingPasswordDoesNotUpdateLastLogonTime() throws Exception { Long lastLogonBeforeReset = users.getFirst().getLastLogonTime(); PasswordChange change = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), users.getFirst().getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(users.getFirst(), code, true)) .andExpect(status().isFound()) @@ -124,7 +124,7 @@ void resettingAPasswordFailsWhenUsernameChanged() throws Exception { ScimUser user = users.getFirst(); PasswordChange change = new PasswordChange(user.getId(), user.getUserName(), user.getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); String formerUsername = user.getUserName(); user.setUserName("newusername"); @@ -319,7 +319,7 @@ void resettingAPasswordFailsWhenPasswordChanged() throws Exception { ScimUserProvisioning userProvisioning = webApplicationContext.getBean(ScimUserProvisioning.class); Thread.sleep(1000 - (System.currentTimeMillis() % 1000) + 10); //because password last modified is second only PasswordChange change = new PasswordChange(user.getId(), user.getUserName(), user.getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); userProvisioning.changePassword(user.getId(), "secret", "secr3t", IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true)) @@ -331,7 +331,8 @@ void resettingAPasswordNoCsrfParameter() throws Exception { List users = webApplicationContext.getBean(ScimUserProvisioning.class).query("username eq \"marissa\"", IdentityZoneHolder.get().getId()); assertThat(users) .hasSize(1); - ExpiringCode code = codeStore.generateCode(users.getFirst().getId(), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + PasswordChange change = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), users.getFirst().getPasswordLastModified(), "", ""); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(users.getFirst(), code, false)) .andExpect(status().isFound()) @@ -344,7 +345,7 @@ void resettingAPasswordUsingTimestampForUserModification() throws Exception { assertThat(users) .hasSize(1); PasswordChange passwordChange = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), null, null, null); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); MockHttpServletRequestBuilder post = createChangePasswordRequest(users.getFirst(), code, true, "newpassw0rD", "newpassw0rD"); @@ -362,10 +363,10 @@ void resetPassword_ReturnsUnprocessableEntity_NewPasswordSameAsOld() throws Exce .hasSize(1); ScimUser user = users.getFirst(); PasswordChange passwordChange = new PasswordChange(user.getId(), user.getUserName(), null, null, null); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "d3faultPasswd", "d3faultPasswd")); - code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "d3faultPasswd", "d3faultPasswd")) .andExpect(status().isUnprocessableEntity()) .andExpect(request().attribute("message", "Your new password cannot be the same as the old password.")) @@ -389,10 +390,10 @@ void resetPassword_ReturnsUnprocessableEntity_NewPasswordNotAccordingToPolicy() .hasSize(1); ScimUser user = users.getFirst(); PasswordChange passwordChange = new PasswordChange(user.getId(), user.getUserName(), null, null, null); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "d3faultPasswd", "d3faultPasswd")); - code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "a", "a")) .andExpect(status().isUnprocessableEntity()) .andExpect(request().attribute("message", "Password must be at least 3 characters in length.")) diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcZonePathTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcZonePathTests.java index d69de878c46..3a7c42c245f 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcZonePathTests.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcZonePathTests.java @@ -97,7 +97,7 @@ void resettingAPasswordUsingUsernameToEnsureNoModification() throws Exception { .hasSize(1); PasswordChange change = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), users.getFirst().getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(users.getFirst(), code, true)) .andExpect(status().isFound()) @@ -113,7 +113,7 @@ void resettingPasswordDoesNotUpdateLastLogonTime() throws Exception { Long lastLogonBeforeReset = users.getFirst().getLastLogonTime(); PasswordChange change = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), users.getFirst().getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(users.getFirst(), code, true)) .andExpect(status().isFound()) @@ -138,7 +138,7 @@ void resettingAPasswordFailsWhenUsernameChanged() throws Exception { ScimUser user = users.getFirst(); PasswordChange change = new PasswordChange(user.getId(), user.getUserName(), user.getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); String formerUsername = user.getUserName(); user.setUserName("newusername"); @@ -333,7 +333,7 @@ void resettingAPasswordFailsWhenPasswordChanged() throws Exception { ScimUserProvisioning userProvisioning = webApplicationContext.getBean(ScimUserProvisioning.class); Thread.sleep(1000 - (System.currentTimeMillis() % 1000) + 10); //because password last modified is second only PasswordChange change = new PasswordChange(user.getId(), user.getUserName(), user.getPasswordLastModified(), "", ""); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + 50000), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); userProvisioning.changePassword(user.getId(), "secret", "secr3t", IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true)) @@ -345,7 +345,8 @@ void resettingAPasswordNoCsrfParameter() throws Exception { List users = webApplicationContext.getBean(ScimUserProvisioning.class).query("username eq \"marissa\"", IdentityZoneHolder.get().getId()); assertThat(users) .hasSize(1); - ExpiringCode code = codeStore.generateCode(users.getFirst().getId(), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + PasswordChange change = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), users.getFirst().getPasswordLastModified(), "", ""); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(users.getFirst(), code, false)) .andExpect(status().isFound()) @@ -358,7 +359,7 @@ void resettingAPasswordUsingTimestampForUserModification() throws Exception { assertThat(users) .hasSize(1); PasswordChange passwordChange = new PasswordChange(users.getFirst().getId(), users.getFirst().getUserName(), null, null, null); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + users.getFirst().getId(), IdentityZoneHolder.get().getId()); MockHttpServletRequestBuilder post = createChangePasswordRequest(users.getFirst(), code, true, "newpassw0rD", "newpassw0rD"); @@ -376,10 +377,10 @@ void resetPassword_ReturnsUnprocessableEntity_NewPasswordSameAsOld() throws Exce .hasSize(1); ScimUser user = users.getFirst(); PasswordChange passwordChange = new PasswordChange(user.getId(), user.getUserName(), null, null, null); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "d3faultPasswd", "d3faultPasswd")); - code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "d3faultPasswd", "d3faultPasswd")) .andExpect(status().isUnprocessableEntity()) .andExpect(request().attribute("message", "Your new password cannot be the same as the old password.")) @@ -403,10 +404,10 @@ void resetPassword_ReturnsUnprocessableEntity_NewPasswordNotAccordingToPolicy() .hasSize(1); ScimUser user = users.getFirst(); PasswordChange passwordChange = new PasswordChange(user.getId(), user.getUserName(), null, null, null); - ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "d3faultPasswd", "d3faultPasswd")); - code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), null, IdentityZoneHolder.get().getId()); + code = codeStore.generateCode(JsonUtils.writeValueAsString(passwordChange), new Timestamp(System.currentTimeMillis() + UaaResetPasswordService.PASSWORD_RESET_LIFETIME), FORGOT_PASSWORD_INTENT_PREFIX + user.getId(), IdentityZoneHolder.get().getId()); mockMvc.perform(createChangePasswordRequest(user, code, true, "a", "a")) .andExpect(status().isUnprocessableEntity()) .andExpect(request().attribute("message", "Password must be at least 3 characters in length."))