PasswordResetEndpoint { @RequestMapping(value = "/password_change", method = RequestMethod.POST) public ResponseEntity<LostPasswordChangeResponse> changePassword(@RequestBody LostPasswordChangeRequest passwordChangeRequest) { ResponseEntity<LostPasswordChangeResponse> responseEntity; if (passwordChangeRequest.getChangeCode() != null) { try { ExpiringCode expiringCode = getExpiringCode(passwordChangeRequest.getChangeCode()); ResetPasswordService.ResetPasswordResponse reset = resetPasswordService.resetPassword(expiringCode, passwordChangeRequest.getNewPassword()); ScimUser user = reset.getUser(); ExpiringCode loginCode = getCode(user.getId(), user.getUserName(), reset.getClientId()); LostPasswordChangeResponse response = new LostPasswordChangeResponse(); response.setUserId(user.getId()); response.setUsername(user.getUserName()); response.setEmail(user.getPrimaryEmail()); response.setLoginCode(loginCode.getCode()); return new ResponseEntity<>(response, OK); } catch (BadCredentialsException e) { return new ResponseEntity<>(UNAUTHORIZED); } catch (ScimResourceNotFoundException e) { return new ResponseEntity<>(NOT_FOUND); } catch (InvalidPasswordException | InvalidCodeException e) { throw e; } catch (Exception e) { return new ResponseEntity<>(INTERNAL_SERVER_ERROR); } } else { responseEntity = new ResponseEntity<>(BAD_REQUEST); } return responseEntity; } PasswordResetEndpoint(
            final ResetPasswordService resetPasswordService,
            final ExpiringCodeStore codeStore,
            final IdentityZoneManager identityZoneManager); @RequestMapping(value = "/password_resets", method = RequestMethod.POST) ResponseEntity<PasswordResetResponse> resetPassword(@RequestBody String email,
                                                               @RequestParam(required = false, value = "client_id") String clientId,
                                                               @RequestParam(required = false, value = "redirect_uri") String redirectUri); @RequestMapping(value = "/password_change", method = RequestMethod.POST) ResponseEntity<LostPasswordChangeResponse> changePassword(@RequestBody LostPasswordChangeRequest passwordChangeRequest); @ExceptionHandler(InvalidPasswordException.class) View handleException(InvalidPasswordException t); @ExceptionHandler(InvalidCodeException.class) View handleCodeException(InvalidCodeException t);  }
@Test void changingAPasswordWithAValidCode() 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); when(mockExpiringCodeStore.retrieveCode("secret_code", currentZoneId)).thenReturn(code); 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)); scimUser.addEmail("user@example.com"); when(mockScimUserProvisioning.retrieve("eyedee", currentZoneId)).thenReturn(scimUser); ExpiringCode autologinCode = new ExpiringCode("autologin-code", new Timestamp(System.currentTimeMillis() + 5 * 60 * 1000), "data", AUTOLOGIN.name()); when(mockExpiringCodeStore.generateCode(anyString(), any(Timestamp.class), eq(AUTOLOGIN.name()), anyString())).thenReturn(autologinCode); MockHttpServletRequestBuilder post = post("/password_change") .contentType(APPLICATION_JSON) .content("{\"code\":\"secret_code\",\"new_password\":\"new_secret\"}") .accept(APPLICATION_JSON); SecurityContextHolder.getContext().setAuthentication(new MockAuthentication()); mockMvc.perform(post) .andExpect(status().isOk()) .andExpect(jsonPath("$.user_id").value("eyedee")) .andExpect(jsonPath("$.username").value("user@example.com")); verify(mockScimUserProvisioning).changePassword("eyedee", null, "new_secret", currentZoneId); }
@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); when(mockExpiringCodeStore.retrieveCode("secret_code", currentZoneId)).thenReturn(code); 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)); scimUser.addEmail("user@example.com"); scimUser.setVerified(false); when(mockScimUserProvisioning.retrieve("eyedee", currentZoneId)).thenReturn(scimUser); ExpiringCode autologinCode = new ExpiringCode("autologin-code", new Timestamp(System.currentTimeMillis() + 5 * 60 * 1000), "data", AUTOLOGIN.name()); when(mockExpiringCodeStore.generateCode(anyString(), any(Timestamp.class), eq(AUTOLOGIN.name()), anyString())).thenReturn(autologinCode); MockHttpServletRequestBuilder post = post("/password_change") .contentType(APPLICATION_JSON) .content("{\"code\":\"secret_code\",\"new_password\":\"new_secret\"}") .accept(APPLICATION_JSON); SecurityContextHolder.getContext().setAuthentication(new MockAuthentication()); mockMvc.perform(post) .andExpect(status().isOk()) .andExpect(jsonPath("$.user_id").value("eyedee")) .andExpect(jsonPath("$.username").value("user@example.com")); verify(mockScimUserProvisioning).changePassword("eyedee", null, "new_secret", currentZoneId); verify(mockScimUserProvisioning).verifyUser(scimUser.getId(), -1, currentZoneId); }