@Test public void testUnlockAccount() throws Exception { ScimUser userToLockout = createUser(uaaAdminToken); attemptFailedLogin(5, userToLockout.getUserName(), ""); UserAccountStatus alteredAccountStatus = new UserAccountStatus(); alteredAccountStatus.setLocked(false); String jsonStatus = JsonUtils.writeValueAsString(alteredAccountStatus); getMockMvc() .perform( patch("/Users/" + userToLockout.getId() + "/status") .header("Authorization", "Bearer " + uaaAdminToken) .accept(APPLICATION_JSON) .contentType(APPLICATION_JSON) .content(jsonStatus)) .andExpect(status().isOk()) .andExpect(content().json(jsonStatus)); getMockMvc() .perform( post("/login.do") .with(cookieCsrf()) .param("username", userToLockout.getUserName()) .param("password", userToLockout.getPassword())) .andExpect(redirectedUrl("/")); }
@Test public void validateOriginAndExternalIDDuringCreateAndUpdate() { String origin = "test"; String externalId = "testId"; ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.setOrigin(origin); user.setExternalId(externalId); user.addEmail("*****@*****.**"); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertNotSame(user.getId(), created.getId()); Map<String, Object> map = template.queryForMap("select * from users where id=?", created.getId()); assertEquals(user.getUserName(), map.get("userName")); assertEquals(user.getUserType(), map.get(UaaAuthority.UAA_USER.getUserType())); assertNull(created.getGroups()); assertEquals(origin, created.getOrigin()); assertEquals(externalId, created.getExternalId()); String origin2 = "test2"; String externalId2 = "testId2"; created.setOrigin(origin2); created.setExternalId(externalId2); ScimUser updated = db.update(created.getId(), created); assertEquals(origin2, updated.getOrigin()); assertEquals(externalId2, updated.getExternalId()); }
@Override public ScimUser create(final ScimUser user) { validate(user); logger.debug("Creating new user: "******"userName eq \"" + user.getUserName() + "\" and origin eq \"" + (StringUtils.hasText(user.getOrigin()) ? user.getOrigin() : OriginKeys.UAA) + "\"") .get(0); Map<String, Object> userDetails = new HashMap<>(); userDetails.put("active", existingUser.isActive()); userDetails.put("verified", existingUser.isVerified()); userDetails.put("user_id", existingUser.getId()); throw new ScimResourceAlreadyExistsException( "Username already in use: " + existingUser.getUserName(), userDetails); } return retrieve(id); }
@Test public void canCreateUserWithoutGivenNameAndFamilyName() { ScimUser user = new ScimUser(null, "*****@*****.**", null, null); user.addEmail("*****@*****.**"); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertNotSame(user.getId(), created.getId()); Map<String, Object> map = template.queryForMap("select * from users where id=?", created.getId()); assertEquals(user.getUserName(), map.get("userName")); assertEquals(user.getUserType(), map.get(UaaAuthority.UAA_USER.getUserType())); assertNull(created.getGroups()); }
protected ScimUser updateUser(String token, int status, ScimUser user) throws Exception { MockHttpServletRequestBuilder put = put("/Users/" + user.getId()) .header("Authorization", "Bearer " + token) .header("If-Match", "\"" + user.getVersion() + "\"") .accept(APPLICATION_JSON) .contentType(APPLICATION_JSON) .content(JsonUtils.writeValueAsBytes(user)); if (status == HttpStatus.OK.value()) { String json = getMockMvc() .perform(put) .andExpect(status().isOk()) .andExpect(header().string("ETag", "\"1\"")) .andExpect(jsonPath("$.userName").value(user.getUserName())) .andExpect(jsonPath("$.emails[0].value").value(user.getPrimaryEmail())) .andExpect(jsonPath("$.name.givenName").value(user.getGivenName())) .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName())) .andReturn() .getResponse() .getContentAsString(); return JsonUtils.readValue(json, ScimUser.class); } else { getMockMvc().perform(put).andExpect(status().is(status)); return null; } }
@Test public void test_cannot_delete_uaa_zone_users() throws Exception { ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.addEmail("*****@*****.**"); user.setOrigin(UAA); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertEquals(UAA, created.getOrigin()); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {UAA, IdentityZone.getUaa().getId()}, Integer.class), is(3)); IdentityProvider loginServer = new IdentityProvider().setOriginKey(UAA).setIdentityZoneId(IdentityZone.getUaa().getId()); db.onApplicationEvent(new EntityDeletedEvent<>(loginServer)); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {UAA, IdentityZone.getUaa().getId()}, Integer.class), is(3)); }
@Test public void test_cannot_delete_uaa_provider_users_in_other_zone() throws Exception { String id = generator.generate(); IdentityZone zone = MultitenancyFixture.identityZone(id, id); IdentityZoneHolder.set(zone); ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.addEmail("*****@*****.**"); user.setOrigin(UAA); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertEquals(UAA, created.getOrigin()); assertEquals(zone.getId(), created.getZoneId()); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {UAA, zone.getId()}, Integer.class), is(1)); IdentityProvider loginServer = new IdentityProvider().setOriginKey(UAA).setIdentityZoneId(zone.getId()); db.onApplicationEvent(new EntityDeletedEvent<>(loginServer)); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {UAA, zone.getId()}, Integer.class), is(1)); }
@Test @OAuth2ContextConfiguration( resource = OAuth2ContextConfiguration.Implicit.class, initialize = false) public void testUserMustSupplyOldPassword() throws Exception { MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>(); parameters.set("source", "credentials"); parameters.set("username", joe.getUserName()); parameters.set("password", "pas5Word"); context.getAccessTokenRequest().putAll(parameters); PasswordChangeRequest change = new PasswordChangeRequest(); change.setPassword("Newpasswo3d"); HttpHeaders headers = new HttpHeaders(); ResponseEntity<Void> result = client.exchange( serverRunning.getUrl(userEndpoint) + "/{id}/password", HttpMethod.PUT, new HttpEntity<>(change, headers), Void.class, joe.getId()); assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); }
@BeforeOAuth2Context @OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class) public void createAccount() throws Exception { client = serverRunning.getRestTemplate(); ResponseEntity<ScimUser> response = createUser(JOE, "Joe", "User", "*****@*****.**"); joe = response.getBody(); assertEquals(JOE, joe.getUserName()); }
private ScimUser createUser(ScimUser user, String token, String subdomain, String switchZone) throws Exception { String password = hasText(user.getPassword()) ? user.getPassword() : "pas5word"; user.setPassword(password); MvcResult result = createUserAndReturnResult(user, token, subdomain, switchZone) .andExpect(status().isCreated()) .andExpect(header().string("ETag", "\"0\"")) .andExpect(jsonPath("$.userName").value(user.getUserName())) .andExpect(jsonPath("$.emails[0].value").value(user.getUserName())) .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName())) .andExpect(jsonPath("$.name.givenName").value(user.getGivenName())) .andReturn(); user = JsonUtils.readValue(result.getResponse().getContentAsString(), ScimUser.class); user.setPassword(password); return user; }
@Test public void canCreateUserWithExclamationMarkInUsername() { String userName = "******"; ScimUser user = new ScimUser(null, userName, "Jo", "User"); user.addEmail(userName); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals(userName, created.getUserName()); }
@Test(expected = OptimisticLockingFailureException.class) public void updateWithWrongVersionIsError() { ScimUser jo = new ScimUser(null, "josephine", "Jo", "NewUser"); jo.addEmail("*****@*****.**"); jo.setVersion(1); ScimUser joe = db.update(JOE_ID, jo); assertEquals("joe", joe.getUserName()); }
@Test(expected = InvalidScimResourceException.class) public void updateWithBadUsernameIsError() { ScimUser jo = new ScimUser(null, "jo$ephine", "Jo", "NewUser"); jo.addEmail("*****@*****.**"); jo.setVersion(1); ScimUser joe = db.update(JOE_ID, jo); assertEquals("joe", joe.getUserName()); }
// TODO: add cases for username no existing external user with username not email @Test public void accept_invitation_with_external_user_that_does_not_have_email_as_their_username() { String userId = "user-id-001"; String email = "*****@*****.**"; String actualUsername = "******"; ScimUser userBeforeAccept = new ScimUser(userId, email, "first", "last"); userBeforeAccept.setPrimaryEmail(email); userBeforeAccept.setOrigin(Origin.SAML); when(scimUserProvisioning.verifyUser(eq(userId), anyInt())).thenReturn(userBeforeAccept); when(scimUserProvisioning.retrieve(eq(userId))).thenReturn(userBeforeAccept); BaseClientDetails clientDetails = new BaseClientDetails("client-id", null, null, null, null, "http://example.com/redirect"); when(clientDetailsService.loadClientByClientId("acmeClientId")).thenReturn(clientDetails); Map<String, String> userData = new HashMap<>(); userData.put(USER_ID, userBeforeAccept.getId()); userData.put(EMAIL, userBeforeAccept.getPrimaryEmail()); userData.put(REDIRECT_URI, "http://someother/redirect"); userData.put(CLIENT_ID, "acmeClientId"); when(expiringCodeStore.retrieveCode(anyString())) .thenReturn( new ExpiringCode( "code", new Timestamp(System.currentTimeMillis()), JsonUtils.writeValueAsString(userData))); ScimUser userAfterAccept = new ScimUser( userId, actualUsername, userBeforeAccept.getGivenName(), userBeforeAccept.getFamilyName()); userAfterAccept.setPrimaryEmail(email); when(scimUserProvisioning.verifyUser(eq(userId), anyInt())).thenReturn(userAfterAccept); ScimUser acceptedUser = emailInvitationsService.acceptInvitation("code", "password").getUser(); assertEquals(userAfterAccept.getUserName(), acceptedUser.getUserName()); assertEquals(userAfterAccept.getName(), acceptedUser.getName()); assertEquals(userAfterAccept.getPrimaryEmail(), acceptedUser.getPrimaryEmail()); verify(scimUserProvisioning).verifyUser(eq(userId), anyInt()); }
private void validate(final ScimUser user) throws InvalidScimResourceException { if (!usernamePattern.matcher(user.getUserName()).matches()) { throw new InvalidScimResourceException( "Username must match pattern: " + usernamePattern.pattern()); } if (user.getEmails() == null || user.getEmails().isEmpty()) { throw new InvalidScimResourceException("An email must be provided."); } }
private void assertJoe(ScimUser joe) { assertNotNull(joe); assertEquals(JOE_ID, joe.getId()); assertEquals("Joe", joe.getGivenName()); assertEquals("User", joe.getFamilyName()); assertEquals("*****@*****.**", joe.getPrimaryEmail()); assertEquals("joe", joe.getUserName()); assertEquals("+1-222-1234567", joe.getPhoneNumbers().get(0).getValue()); assertNull(joe.getGroups()); }
@Test public void canCreateUserInOtherIdentityZone() { String otherZoneId = "my-zone-id"; createOtherIdentityZone(otherZoneId); String idpId = createOtherIdentityProvider(OriginKeys.UAA, otherZoneId); ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.addEmail("*****@*****.**"); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertNotSame(user.getId(), created.getId()); Map<String, Object> map = jdbcTemplate.queryForMap("select * from users where id=?", created.getId()); assertEquals(user.getUserName(), map.get("userName")); assertEquals(user.getUserType(), map.get(UaaAuthority.UAA_USER.getUserType())); assertNull(created.getGroups()); assertEquals(OriginKeys.UAA, created.getOrigin()); assertEquals("my-zone-id", map.get("identity_zone_id")); }
public void performAuthentication(ScimUser user, boolean success) throws Exception { getMockMvc() .perform( post("/login.do") .accept("text/html") .with(cookieCsrf()) .param("username", user.getUserName()) .param("password", USER_PASSWORD)) .andDo(print()) .andExpect(success ? authenticated() : unauthenticated()); }
@Test public void canCreateUserInDefaultIdentityZone() { ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.addEmail("*****@*****.**"); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertNotSame(user.getId(), created.getId()); Map<String, Object> map = jdbcTemplate.queryForMap("select * from users where id=?", created.getId()); assertEquals(user.getUserName(), map.get("userName")); assertEquals(user.getUserType(), map.get(UaaAuthority.UAA_USER.getUserType())); assertNull(created.getGroups()); assertEquals(OriginKeys.UAA, created.getOrigin()); assertEquals("uaa", map.get("identity_zone_id")); assertNull(user.getPasswordLastModified()); assertNotNull(created.getPasswordLastModified()); assertEquals( (created.getMeta().getCreated().getTime() / 1000l) * 1000l, created.getPasswordLastModified().getTime()); }
@Test public void test_can_delete_zone_users() throws Exception { String id = generator.generate(); IdentityZone zone = MultitenancyFixture.identityZone(id, id); IdentityZoneHolder.set(zone); ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.addEmail("*****@*****.**"); user.setOrigin(UAA); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertEquals(UAA, created.getOrigin()); assertEquals(zone.getId(), created.getZoneId()); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {UAA, zone.getId()}, Integer.class), is(1)); addApprovalAndMembership(created.getId(), created.getOrigin()); assertThat( jdbcTemplate.queryForObject( "select count(*) from authz_approvals where user_id=?", new Object[] {created.getId()}, Integer.class), is(1)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where member_id=?", new Object[] {created.getId()}, Integer.class), is(1)); db.onApplicationEvent(new EntityDeletedEvent<>(zone)); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {UAA, zone.getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from authz_approvals where user_id=?", new Object[] {created.getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where member_id=?", new Object[] {created.getId()}, Integer.class), is(0)); }
@Test public void test_can_delete_provider_users_in_default_zone() throws Exception { ScimUser user = new ScimUser(null, "*****@*****.**", "Jo", "User"); user.addEmail("*****@*****.**"); user.setOrigin(LOGIN_SERVER); ScimUser created = db.createUser(user, "j7hyqpassX"); assertEquals("*****@*****.**", created.getUserName()); assertNotNull(created.getId()); assertEquals(LOGIN_SERVER, created.getOrigin()); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {LOGIN_SERVER, IdentityZone.getUaa().getId()}, Integer.class), is(1)); addApprovalAndMembership(created.getId(), created.getOrigin()); assertThat( jdbcTemplate.queryForObject( "select count(*) from authz_approvals where user_id=?", new Object[] {created.getId()}, Integer.class), is(1)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where member_id=?", new Object[] {created.getId()}, Integer.class), is(1)); IdentityProvider loginServer = new IdentityProvider() .setOriginKey(LOGIN_SERVER) .setIdentityZoneId(IdentityZone.getUaa().getId()); db.onApplicationEvent(new EntityDeletedEvent<>(loginServer)); assertThat( jdbcTemplate.queryForObject( "select count(*) from users where origin=? and identity_zone_id=?", new Object[] {LOGIN_SERVER, IdentityZone.getUaa().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from authz_approvals where user_id=?", new Object[] {created.getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where member_id=?", new Object[] {created.getId()}, Integer.class), is(0)); }
@Test public void testUserSelfAccess_Get_and_Post() throws Exception { ScimUser user = getScimUser(); user.setPassword("secret"); user = createUser(user, scimReadWriteToken, IdentityZone.getUaa().getSubdomain()); String selfToken = testClient.getUserOAuthAccessToken("cf", "", user.getUserName(), "secret", ""); user.setName(new ScimUser.Name("Given1", "Family1")); user = updateUser(selfToken, HttpStatus.OK.value(), user); user = getAndReturnUser(HttpStatus.OK.value(), user, selfToken); }
private void validateToken(String paramName, Map params, String[] scopes, String[] aud) throws java.io.IOException { Jwt access_token = JwtHelper.decode((String) params.get(paramName)); Map<String, Object> claims = JsonUtils.readValue(access_token.getClaims(), new TypeReference<Map<String, Object>>() {}); Assert.assertThat(claims.get("jti"), is(params.get("jti"))); Assert.assertThat(claims.get("client_id"), is("cf")); Assert.assertThat(claims.get("cid"), is("cf")); Assert.assertThat(claims.get("user_name"), is(user.getUserName())); Assert.assertThat(((List<String>) claims.get(Claims.SCOPE)), containsInAnyOrder(scopes)); Assert.assertThat(((List<String>) claims.get(Claims.AUD)), containsInAnyOrder(aud)); }
@Test public void testDeleteUserWithUaaAdminToken() throws Exception { ScimUser user = setUpScimUser(); getMockMvc() .perform( (delete("/Users/" + user.getId())) .header("Authorization", "Bearer " + uaaAdminToken) .contentType(APPLICATION_JSON) .content(JsonUtils.writeValueAsBytes(user))) .andExpect(status().isOk()) .andExpect(jsonPath("$.userName").value(user.getUserName())) .andExpect(jsonPath("$.emails[0].value").value(user.getPrimaryEmail())) .andExpect(jsonPath("$.name.givenName").value(user.getGivenName())) .andExpect(jsonPath("$.name.familyName").value(user.getFamilyName())); }
@Test public void testImplicitGrant() throws Exception { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); LinkedMultiValueMap<String, String> postBody = new LinkedMultiValueMap<>(); postBody.add("client_id", "cf"); postBody.add("redirect_uri", "https://uaa.cloudfoundry.com/redirect/cf"); postBody.add("response_type", "token id_token"); postBody.add("source", "credentials"); postBody.add("username", user.getUserName()); postBody.add("password", secret); ResponseEntity<Void> responseEntity = restOperations.exchange( loginUrl + "/oauth/authorize", HttpMethod.POST, new HttpEntity<>(postBody, headers), Void.class); Assert.assertEquals(HttpStatus.FOUND, responseEntity.getStatusCode()); UriComponents locationComponents = UriComponentsBuilder.fromUri(responseEntity.getHeaders().getLocation()).build(); Assert.assertEquals("uaa.cloudfoundry.com", locationComponents.getHost()); Assert.assertEquals("/redirect/cf", locationComponents.getPath()); MultiValueMap<String, String> params = parseFragmentParams(locationComponents); Assert.assertThat(params.get("jti"), not(empty())); Assert.assertEquals("bearer", params.getFirst("token_type")); Assert.assertThat(Integer.parseInt(params.getFirst("expires_in")), Matchers.greaterThan(40000)); String[] scopes = UriUtils.decode(params.getFirst("scope"), "UTF-8").split(" "); Assert.assertThat( Arrays.asList(scopes), containsInAnyOrder( "scim.userids", "password.write", "cloud_controller.write", "openid", "cloud_controller.read", "uaa.user")); validateToken("access_token", params.toSingleValueMap(), scopes, aud); validateToken("id_token", params.toSingleValueMap(), openid, new String[] {"cf"}); }
@Test public void updateModifiesExpectedData() { ScimUser jo = new ScimUser(null, "josephine", "Jo", "NewUser"); jo.addEmail("*****@*****.**"); jo.setUserType(UaaAuthority.UAA_ADMIN.getUserType()); ScimUser joe = db.update(JOE_ID, jo); // Can change username assertEquals("josephine", joe.getUserName()); assertEquals("*****@*****.**", joe.getPrimaryEmail()); assertEquals("Jo", joe.getGivenName()); assertEquals("NewUser", joe.getFamilyName()); assertEquals(1, joe.getVersion()); assertEquals(JOE_ID, joe.getId()); assertNull(joe.getGroups()); }
@Test public void testPasswordGrant() throws Exception { String basicDigestHeaderValue = "Basic " + new String(Base64.encodeBase64(("cf:").getBytes())); HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); headers.set("Authorization", basicDigestHeaderValue); LinkedMultiValueMap<String, String> postBody = new LinkedMultiValueMap<>(); postBody.add("client_id", "cf"); postBody.add("redirect_uri", "https://uaa.cloudfoundry.com/redirect/cf"); postBody.add("response_type", "token id_token"); postBody.add("grant_type", "password"); postBody.add("username", user.getUserName()); postBody.add("password", secret); ResponseEntity<Map> responseEntity = restOperations.exchange( loginUrl + "/oauth/token", HttpMethod.POST, new HttpEntity<>(postBody, headers), Map.class); Assert.assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); Map<String, Object> params = responseEntity.getBody(); Assert.assertTrue(params.get("jti") != null); Assert.assertEquals("bearer", params.get("token_type")); Assert.assertThat((Integer) params.get("expires_in"), Matchers.greaterThan(40000)); String[] scopes = UriUtils.decode((String) params.get("scope"), "UTF-8").split(" "); Assert.assertThat( Arrays.asList(scopes), containsInAnyOrder( "scim.userids", "password.write", "cloud_controller.write", "openid", "cloud_controller.read", "uaa.user")); validateToken("access_token", params, scopes, aud); validateToken("id_token", params, openid, new String[] {"cf"}); }
@Test public void testInvalidAppRedirectDisplaysError() throws Exception { ScimUser user = createUnapprovedUser(); // given we vist the app (specifying an invalid redirect - incorrect protocol https) webDriver.get(appUrl + "?redirect_uri=https://localhost:8080/app/"); // Sign in to login server webDriver.findElement(By.name("username")).sendKeys(user.getUserName()); webDriver.findElement(By.name("password")).sendKeys(user.getPassword()); webDriver.findElement(By.xpath("//input[@value='Sign in']")).click(); // Authorize the app for some scopes assertThat( webDriver.findElement(By.className("alert-error")).getText(), RegexMatcher.matchesRegex( "^Invalid redirect (.*) did not match one of the registered values")); }
@Override public ScimUser update(final String id, final ScimUser user) throws InvalidScimResourceException { validate(user); logger.debug("Updating user " + user.getUserName()); final String origin = StringUtils.hasText(user.getOrigin()) ? user.getOrigin() : OriginKeys.UAA; final String zoneId = IdentityZoneHolder.get().getId(); int updated = jdbcTemplate.update( UPDATE_USER_SQL, new PreparedStatementSetter() { @Override public void setValues(PreparedStatement ps) throws SQLException { int pos = 1; Timestamp t = new Timestamp(new Date().getTime()); ps.setInt(pos++, user.getVersion() + 1); ps.setTimestamp(pos++, t); ps.setString(pos++, user.getUserName()); ps.setString(pos++, user.getPrimaryEmail()); ps.setString(pos++, user.getName().getGivenName()); ps.setString(pos++, user.getName().getFamilyName()); ps.setBoolean(pos++, user.isActive()); ps.setString(pos++, extractPhoneNumber(user)); ps.setBoolean(pos++, user.isVerified()); ps.setString(pos++, origin); ps.setString( pos++, StringUtils.hasText(user.getExternalId()) ? user.getExternalId() : null); ps.setString(pos++, user.getSalt()); ps.setString(pos++, id); ps.setInt(pos++, user.getVersion()); ps.setString(pos++, zoneId); } }); ScimUser result = retrieve(id); if (updated == 0) { throw new OptimisticLockingFailureException( String.format( "Attempt to update a user (%s) with wrong version: expected=%d but found=%d", id, result.getVersion(), user.getVersion())); } if (updated > 1) { throw new IncorrectResultSizeDataAccessException(1); } return result; }
@Test public void canModifyPassword() throws Exception { ScimUser user = new ScimUser(null, generator.generate() + "@foo.com", "Jo", "User"); user.addEmail(user.getUserName()); ScimUser created = db.createUser(user, "j7hyqpassX"); assertNull(user.getPasswordLastModified()); assertNotNull(created.getPasswordLastModified()); assertEquals( (created.getMeta().getCreated().getTime() / 1000l) * 1000l, created.getPasswordLastModified().getTime()); Thread.sleep(10); db.changePassword(created.getId(), "j7hyqpassX", "j7hyqpassXXX"); user = db.retrieve(created.getId()); assertNotNull(user.getPasswordLastModified()); assertEquals( (user.getMeta().getLastModified().getTime() / 1000l) * 1000l, user.getPasswordLastModified().getTime()); }