@Before public void setUp() throws Exception { String adminToken = testClient.getClientCredentialsOAuthAccessToken( "admin", "adminsecret", "clients.read clients.write clients.secret clients.admin uaa.admin"); String clientId = generator.generate().toLowerCase(); String clientSecret = generator.generate().toLowerCase(); String authorities = "scim.read,scim.write,password.write,oauth.approvals,scim.create,uaa.admin"; clientDetails = utils() .createClient( this.getMockMvc(), adminToken, clientId, clientSecret, Collections.singleton("oauth"), Arrays.asList("foo", "bar"), Collections.singletonList("client_credentials"), authorities); scimReadWriteToken = testClient.getClientCredentialsOAuthAccessToken( clientId, clientSecret, "scim.read scim.write password.write"); scimCreateToken = testClient.getClientCredentialsOAuthAccessToken(clientId, clientSecret, "scim.create"); usersRepository = getWebApplicationContext().getBean(ScimUserProvisioning.class); codeStore = getWebApplicationContext().getBean(ExpiringCodeStore.class); uaaAdminToken = testClient.getClientCredentialsOAuthAccessToken(clientId, clientSecret, "uaa.admin"); }
@Before public void setup() throws Exception { String adminToken = utils() .getClientCredentialsOAuthAccessToken( getMockMvc(), "admin", "adminsecret", "clients.read clients.write clients.secret scim.read scim.write clients.admin", null); domain = generator.generate().toLowerCase() + ".com"; clientId = generator.generate().toLowerCase(); clientSecret = generator.generate().toLowerCase(); authorities = "scim.read,scim.invite"; utils() .createClient( getMockMvc(), adminToken, clientId, clientSecret, null, Arrays.asList("scim.invite"), Arrays.asList(new String[] {"client_credentials"}), authorities); token = utils() .getClientCredentialsOAuthAccessToken( getMockMvc(), clientId, clientSecret, "scim.invite", null, true); }
@Test public void canGetMembers_Fails_In_Other_Zone() throws Exception { addMember("g1", "m1", "USER", "READER"); addMember("g1", "g2", "GROUP", "READER"); addMember("g3", "m2", "USER", "READER,WRITER"); IdentityZoneHolder.set( MultitenancyFixture.identityZone(generator.generate(), generator.generate())); assertEquals(0, dao.getMembers("g1", null, false).size()); }
@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 public void listUsers_in_anotherZone() throws Exception { String subdomain = generator.generate(); MockMvcUtils.IdentityZoneCreationResult result = utils() .createOtherIdentityZoneAndReturnResult( subdomain, getMockMvc(), getWebApplicationContext(), null); String zoneAdminToken = result.getZoneAdminToken(); createUser( getScimUser(), zoneAdminToken, IdentityZone.getUaa().getSubdomain(), result.getIdentityZone().getId()); MockHttpServletRequestBuilder get = MockMvcRequestBuilders.get("/Users") .header("X-Identity-Zone-Subdomain", subdomain) .header("Authorization", "Bearer " + zoneAdminToken) .accept(APPLICATION_JSON); MvcResult mvcResult = getMockMvc().perform(get).andExpect(status().isOk()).andReturn(); SearchResults searchResults = JsonUtils.readValue(mvcResult.getResponse().getContentAsString(), SearchResults.class); MatcherAssert.assertThat(searchResults.getResources().size(), is(1)); }
@Override public ExpiringCode generateCode(String data, Timestamp expiresAt) { cleanExpiredEntries(); if (data == null || expiresAt == null) { throw new NullPointerException(); } if (expiresAt.getTime() < System.currentTimeMillis()) { throw new IllegalArgumentException(); } int count = 0; while (count < 3) { count++; String code = generator.generate(); try { int update = jdbcTemplate.update(insert, code, expiresAt.getTime(), data); if (update == 1) { ExpiringCode expiringCode = new ExpiringCode(code, expiresAt, data); return expiringCode; } else { logger.warn("Unable to store expiring code:" + code); } } catch (DataIntegrityViolationException x) { if (count == 3) { throw x; } } } return null; }
@Test public void test_Create_User_More_Than_One_Email() throws Exception { ScimUser scimUser = getScimUser(); String secondEmail = "joe@" + generator.generate().toLowerCase() + ".com"; scimUser.addEmail(secondEmail); createUserAndReturnResult(scimUser, scimReadWriteToken, null, null) .andExpect(status().isBadRequest()); }
private ScimUser getScimUser() { String email = "joe@" + generator.generate().toLowerCase() + ".com"; ScimUser user = new ScimUser(); user.setUserName(email); user.setName(new ScimUser.Name("Joe", "User")); user.addEmail(email); return user; }
@Test public void testCanCreateUserWithExclamationMark() throws Exception { String email = "joe!!@" + generator.generate().toLowerCase() + ".com"; ScimUser user = getScimUser(); user.getEmails().clear(); user.setUserName(email); user.setPrimaryEmail(email); createUser(user, scimReadWriteToken, null); }
protected ScimUser updateUser(String token, int status) throws Exception { ScimUserProvisioning usersRepository = getWebApplicationContext().getBean(ScimUserProvisioning.class); String email = "otheruser@" + generator.generate().toLowerCase() + ".com"; ScimUser user = new ScimUser(null, email, "Other", "User"); user.addEmail(email); user = usersRepository.createUser(user, "pas5Word"); if (status == HttpStatus.BAD_REQUEST.value()) { user.setUserName(null); } else { String username2 = "ou" + generator.generate().toLowerCase(); user.setUserName(username2); } user.setName(new ScimUser.Name("Joe", "Smith")); return updateUser(token, status, user); }
@Test(expected = ScimResourceNotFoundException.class) public void addMember_In_Different_Zone_Causes_Issues() throws Exception { String subdomain = generator.generate(); IdentityZone otherZone = MultitenancyFixture.identityZone(subdomain, subdomain); IdentityZoneHolder.set(otherZone); ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null); m1.setOrigin(OriginKeys.UAA); dao.addMember("g2", m1); }
@Test(expected = ScimResourceNotFoundException.class) public void canAddMember_Validate_Origin_and_ZoneId() throws Exception { String subdomain = generator.generate(); IdentityZone otherZone = MultitenancyFixture.identityZone(subdomain, subdomain); IdentityZoneHolder.set(otherZone); validateCount(0); ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null); m1.setOrigin(OriginKeys.UAA); dao.addMember("g2", m1); }
@Test public void cannot_Delete_With_Filter_Outside_Zone() throws Exception { String id = generator.generate(); addMembers(); validateCount(4); IdentityZone zone = MultitenancyFixture.identityZone(id, id); IdentityZoneHolder.set(zone); dao.delete("member_id eq \"m3\" and origin eq \"" + OriginKeys.UAA + "\""); IdentityZoneHolder.clear(); validateCount(4); }
@Test public void testCreateUserInZoneUsingAdminClient() throws Exception { String subdomain = generator.generate(); mockMvcUtils.createOtherIdentityZone(subdomain, getMockMvc(), getWebApplicationContext()); String zoneAdminToken = testClient.getClientCredentialsOAuthAccessToken( "admin", "admin-secret", "scim.write", subdomain); createUser(zoneAdminToken, subdomain); }
@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 testCreateUserInZoneUsingZoneAdminUser() throws Exception { String subdomain = generator.generate(); MockMvcUtils.IdentityZoneCreationResult result = utils() .createOtherIdentityZoneAndReturnResult( subdomain, getMockMvc(), getWebApplicationContext(), null); String zoneAdminToken = result.getZoneAdminToken(); createUser( getScimUser(), zoneAdminToken, IdentityZone.getUaa().getSubdomain(), result.getIdentityZone().getId()); }
private ScimUser setUpScimUser(IdentityZone zone) { IdentityZone original = IdentityZoneHolder.get(); try { IdentityZoneHolder.set(zone); String email = "joe@" + generator.generate().toLowerCase() + ".com"; ScimUser joel = new ScimUser(null, email, "Joel", "D'sa"); joel.setVerified(false); joel.addEmail(email); joel = usersRepository.createUser(joel, USER_PASSWORD); return joel; } finally { IdentityZoneHolder.set(original); } }
@Test public void canQuery_Filter_Has_ZoneIn_Effect() throws Exception { addMembers(); validateCount(4); String id = generator.generate(); IdentityZone zone = MultitenancyFixture.identityZone(id, id); IdentityZoneHolder.set(zone); assertEquals(0, dao.query("origin eq \"" + OriginKeys.UAA + "\"").size()); IdentityZoneHolder.clear(); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"").size()); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"", "member_id", true).size()); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"", "1,2", true).size()); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"", "origin", true).size()); }
@Test public void testCreateUserInOtherZoneIsUnauthorized() throws Exception { String subdomain = generator.generate(); mockMvcUtils.createOtherIdentityZone(subdomain, getMockMvc(), getWebApplicationContext()); String otherSubdomain = generator.generate(); mockMvcUtils.createOtherIdentityZone(otherSubdomain, getMockMvc(), getWebApplicationContext()); String zoneAdminToken = testClient.getClientCredentialsOAuthAccessToken( "admin", "admin-secret", "scim.write", subdomain); ScimUser user = getScimUser(); byte[] requestBody = JsonUtils.writeValueAsBytes(user); MockHttpServletRequestBuilder post = post("/Users") .with(new SetServerNameRequestPostProcessor(otherSubdomain + ".localhost")) .header("Authorization", "Bearer " + zoneAdminToken) .contentType(APPLICATION_JSON) .content(requestBody); getMockMvc().perform(post).andExpect(status().isUnauthorized()); }
@Test public void test_Create_User_Too_Long_Password() throws Exception { String email = "joe@" + generator.generate().toLowerCase() + ".com"; ScimUser user = getScimUser(); user.setUserName(email); user.setPrimaryEmail(email); user.setPassword(new RandomValueStringGenerator(300).generate()); ResultActions result = createUserAndReturnResult(user, scimReadWriteToken, null, null); result .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.error").value("invalid_password")) .andExpect( jsonPath("$.message").value("Password must be no more than 255 characters in length.")) .andExpect( jsonPath("$.error_description") .value("Password must be no more than 255 characters in length.")); }
@Test public void verification_link_in_non_default_zone_using_switch() throws Exception { String subdomain = generator.generate().toLowerCase(); MockMvcUtils.IdentityZoneCreationResult zoneResult = utils() .createOtherIdentityZoneAndReturnResult( subdomain, getMockMvc(), getWebApplicationContext(), null); String zonedClientId = "admin"; String zonedClientSecret = "adminsecret"; String zonedScimCreateToken = utils() .getClientCredentialsOAuthAccessToken( getMockMvc(), zonedClientId, zonedClientSecret, "uaa.admin", null); ScimUser joel = setUpScimUser(zoneResult.getIdentityZone()); MockHttpServletRequestBuilder get = MockMvcRequestBuilders.get("/Users/" + joel.getId() + "/verify-link") .header("Host", "localhost") .header("Authorization", "Bearer " + zonedScimCreateToken) .header(IdentityZoneSwitchingFilter.SUBDOMAIN_HEADER, subdomain) .param("redirect_uri", HTTP_REDIRECT_EXAMPLE_COM) .accept(APPLICATION_JSON); MvcResult result = getMockMvc().perform(get).andExpect(status().isOk()).andReturn(); VerificationResponse verificationResponse = JsonUtils.readValue(result.getResponse().getContentAsString(), VerificationResponse.class); assertThat( verificationResponse.getVerifyLink().toString(), startsWith("http://" + subdomain + ".localhost/verify_user")); String query = verificationResponse.getVerifyLink().getQuery(); String code = getQueryStringParam(query, "code"); assertThat(code, is(notNullValue())); ExpiringCode expiringCode = codeStore.retrieveCode(code); assertThat(expiringCode.getExpiresAt().getTime(), is(greaterThan(System.currentTimeMillis()))); assertThat(expiringCode.getIntent(), is(REGISTRATION.name())); Map<String, String> data = JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {}); assertThat(data.get(InvitationConstants.USER_ID), is(notNullValue())); assertThat(data.get(CLIENT_ID), is("admin")); assertThat(data.get(REDIRECT_URI), is(HTTP_REDIRECT_EXAMPLE_COM)); }
@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()); }
private void verifyUser(String token) throws Exception { ScimUserProvisioning usersRepository = getWebApplicationContext().getBean(ScimUserProvisioning.class); String email = "joe@" + generator.generate().toLowerCase() + ".com"; ScimUser joel = new ScimUser(null, email, "Joel", "D'sa"); joel.addEmail(email); joel = usersRepository.createUser(joel, "pas5Word"); MockHttpServletRequestBuilder get = MockMvcRequestBuilders.get("/Users/" + joel.getId() + "/verify") .header("Authorization", "Bearer " + token) .accept(APPLICATION_JSON); getMockMvc() .perform(get) .andExpect(status().isOk()) .andExpect(header().string("ETag", "\"0\"")) .andExpect(jsonPath("$.userName").value(email)) .andExpect(jsonPath("$.emails[0].value").value(email)) .andExpect(jsonPath("$.name.familyName").value("D'sa")) .andExpect(jsonPath("$.name.givenName").value("Joel")) .andExpect(jsonPath("$.verified").value(true)); }
@Test public void test_zone_deleted() { String zoneAdminId = generator.generate(); addGroup(zoneAdminId, "zones." + zone.getId() + ".admin", IdentityZone.getUaa().getId()); addMember(zoneAdminId, "m1", "USER", "MEMBER", OriginKeys.UAA); IdentityZoneHolder.set(zone); addMembers(); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); assertThat( jdbcTemplate.queryForObject( "select count(*) from external_group_mapping where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=? and displayName like ?)", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(1)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=? and displayName like ?", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(1)); gdao.onApplicationEvent(new EntityDeletedEvent<>(zone, null)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from external_group_mapping where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=? and displayName like ?)", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=? and displayName like ?", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(0)); }
public class JdbcScimGroupMembershipManagerTests extends JdbcTestBase { private JdbcScimGroupProvisioning gdao; private JdbcScimUserProvisioning udao; private JdbcScimGroupMembershipManager dao; private static final String addUserSqlFormat = "insert into users (id, username, password, email, givenName, familyName, phoneNumber, authorities ,identity_zone_id) values ('%s','%s','%s','%s','%s','%s','%s','%s','%s')"; private static final String addGroupSqlFormat = "insert into groups (id, displayName, identity_zone_id) values ('%s','%s','%s')"; private static final String addMemberSqlFormat = "insert into group_membership (group_id, member_id, member_type, authorities, origin) values ('%s', '%s', '%s', '%s', '%s')"; private static final String addExternalMapSql = "insert into external_group_mapping (group_id, external_group, added, origin) values (?, ?, ?, ?)"; private RandomValueStringGenerator generator = new RandomValueStringGenerator(); private IdentityZone zone = MultitenancyFixture.identityZone(generator.generate(), generator.generate()); @Before public void initJdbcScimGroupMembershipManagerTests() { JdbcTemplate template = new JdbcTemplate(dataSource); JdbcPagingListFactory pagingListFactory = new JdbcPagingListFactory(template, limitSqlAdapter); udao = new JdbcScimUserProvisioning(template, pagingListFactory); gdao = new JdbcScimGroupProvisioning(template, pagingListFactory); dao = new JdbcScimGroupMembershipManager(template, pagingListFactory); dao.setScimGroupProvisioning(gdao); dao.setScimUserProvisioning(udao); dao.setDefaultUserGroups(Collections.singleton("uaa.user")); for (String id : Arrays.asList(zone.getId(), IdentityZone.getUaa().getId())) { String g1 = id.equals(zone.getId()) ? zone.getId() + "-" + "g1" : "g1"; String g2 = id.equals(zone.getId()) ? zone.getId() + "-" + "g2" : "g2"; String g3 = id.equals(zone.getId()) ? zone.getId() + "-" + "g3" : "g3"; String m1 = id.equals(zone.getId()) ? zone.getId() + "-" + "m1" : "m1"; String m2 = id.equals(zone.getId()) ? zone.getId() + "-" + "m2" : "m2"; String m3 = id.equals(zone.getId()) ? zone.getId() + "-" + "m3" : "m3"; addGroup(g1, "test1", id); addGroup(g2, "test2", id); addGroup(g3, "test3", id); addUser(m1, "test", id); addUser(m2, "test", id); addUser(m3, "test", id); mapExternalGroup(g1, g1 + "-external", UAA); mapExternalGroup(g2, g2 + "-external", LOGIN_SERVER); mapExternalGroup(g3, g3 + "-external", UAA); } validateCount(0); } private void mapExternalGroup(String gId, String external, String origin) { Timestamp now = new Timestamp(System.currentTimeMillis()); jdbcTemplate.update(addExternalMapSql, gId, external, now, origin); } private void addMember(String gId, String mId, String mType, String authorities) { addMember(gId, mId, mType, authorities, OriginKeys.UAA); } private void addMember(String gId, String mId, String mType, String authorities, String origin) { gId = IdentityZoneHolder.isUaa() ? gId : IdentityZoneHolder.get().getId() + "-" + gId; mId = IdentityZoneHolder.isUaa() ? mId : IdentityZoneHolder.get().getId() + "-" + mId; jdbcTemplate.execute(String.format(addMemberSqlFormat, gId, mId, mType, authorities, origin)); } private void addGroup(String id, String name, String zoneId) { TestUtils.assertNoSuchUser(jdbcTemplate, "id", id); jdbcTemplate.execute(String.format(addGroupSqlFormat, id, name, zoneId)); } private void addUser(String id, String password, String zoneId) { TestUtils.assertNoSuchUser(jdbcTemplate, "id", id); jdbcTemplate.execute( String.format(addUserSqlFormat, id, id, password, id, id, id, id, "", zoneId)); } private void validateCount(int expected) { int existingMemberCount = jdbcTemplate.queryForObject( "select count(*) from groups g, group_membership gm where g.identity_zone_id=? and gm.group_id=g.id", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class); assertEquals(expected, existingMemberCount); } private void validateUserGroups(String id, String... gNm) { Set<ScimGroup> directGroups = dao.getGroupsWithMember(id, false); assertNotNull(directGroups); Set<ScimGroup> indirectGroups = dao.getGroupsWithMember(id, true); indirectGroups.removeAll(directGroups); assertNotNull(indirectGroups); Set<String> expectedAuthorities = Collections.<String>emptySet(); if (gNm != null) { expectedAuthorities = new HashSet<>(Arrays.asList(gNm)); } expectedAuthorities.add("uaa.user"); assertEquals(expectedAuthorities.size(), directGroups.size() + indirectGroups.size()); for (ScimGroup group : directGroups) { assertTrue(expectedAuthorities.contains(group.getDisplayName())); } for (ScimGroup group : indirectGroups) { assertTrue(expectedAuthorities.contains(group.getDisplayName() + ".i")); } } @After public void cleanupDataSource() throws Exception { IdentityZoneHolder.clear(); TestUtils.deleteFrom(dataSource, "group_membership"); TestUtils.deleteFrom(dataSource, "groups"); TestUtils.deleteFrom(dataSource, "users"); validateCount(0); } @Test public void canQuery_Filter_Has_ZoneIn_Effect() throws Exception { addMembers(); validateCount(4); String id = generator.generate(); IdentityZone zone = MultitenancyFixture.identityZone(id, id); IdentityZoneHolder.set(zone); assertEquals(0, dao.query("origin eq \"" + OriginKeys.UAA + "\"").size()); IdentityZoneHolder.clear(); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"").size()); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"", "member_id", true).size()); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"", "1,2", true).size()); assertEquals(4, dao.query("origin eq \"" + OriginKeys.UAA + "\"", "origin", true).size()); } @Test(expected = IllegalArgumentException.class) public void cannotQuery_Filter_Has_Unknown_Sort() throws Exception { dao.query("origin eq \"" + OriginKeys.UAA + "\"", "unknown,origin", true); } @Test public void canDeleteWithFilter1() throws Exception { addMembers(); validateCount(4); dao.delete("origin eq \"" + OriginKeys.UAA + "\""); validateCount(0); } @Test public void canDeleteWithFilter2() throws Exception { addMembers(); validateCount(4); dao.delete("origin eq \"" + OriginKeys.ORIGIN + "\""); validateCount(4); } @Test public void canDeleteWithFilter3() throws Exception { addMembers(); validateCount(4); dao.delete("member_id eq \"m3\" and origin eq \"" + OriginKeys.UAA + "\""); validateCount(2); } @Test public void canDeleteWithFilter4() throws Exception { addMembers(); validateCount(4); dao.delete("member_id sw \"m\" and origin eq \"" + OriginKeys.UAA + "\""); validateCount(1); } @Test public void canDeleteWithFilter5() throws Exception { addMembers(); validateCount(4); dao.delete("member_id sw \"m\" and origin eq \"" + OriginKeys.LDAP + "\""); validateCount(4); } @Test public void cannot_Delete_With_Filter_Outside_Zone() throws Exception { String id = generator.generate(); addMembers(); validateCount(4); IdentityZone zone = MultitenancyFixture.identityZone(id, id); IdentityZoneHolder.set(zone); dao.delete("member_id eq \"m3\" and origin eq \"" + OriginKeys.UAA + "\""); IdentityZoneHolder.clear(); validateCount(4); } @Test public void canGetGroupsForMember() { addMembers(); Set<ScimGroup> groups = dao.getGroupsWithMember("g2", false); assertNotNull(groups); assertEquals(1, groups.size()); groups = dao.getGroupsWithMember("m3", true); assertNotNull(groups); assertEquals(3, groups.size()); } private void addMembers(String origin) { addMember("g1", "m3", "USER", "READER", origin); addMember("g1", "g2", "GROUP", "READER", origin); addMember("g3", "m2", "USER", "READER,WRITER", origin); addMember("g2", "m3", "USER", "READER", origin); } private void addMembers() { addMembers(OriginKeys.UAA); } @Test public void test_zone_deleted() { String zoneAdminId = generator.generate(); addGroup(zoneAdminId, "zones." + zone.getId() + ".admin", IdentityZone.getUaa().getId()); addMember(zoneAdminId, "m1", "USER", "MEMBER", OriginKeys.UAA); IdentityZoneHolder.set(zone); addMembers(); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); assertThat( jdbcTemplate.queryForObject( "select count(*) from external_group_mapping where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=? and displayName like ?)", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(1)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=? and displayName like ?", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(1)); gdao.onApplicationEvent(new EntityDeletedEvent<>(zone, null)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from external_group_mapping where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=? and displayName like ?)", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=? and displayName like ?", new Object[] { IdentityZone.getUaa().getId(), "zones." + IdentityZoneHolder.get().getId() + ".%" }, Integer.class), is(0)); } @Test public void test_provider_deleted() { IdentityZoneHolder.set(zone); addMembers(LOGIN_SERVER); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); assertThat( jdbcTemplate.queryForObject( "select count(*) from external_group_mapping where origin = ? and group_id in (select id from groups where identity_zone_id=?)", new Object[] {LOGIN_SERVER, IdentityZoneHolder.get().getId()}, Integer.class), is(1)); IdentityProvider loginServer = new IdentityProvider().setOriginKey(LOGIN_SERVER).setIdentityZoneId(zone.getId()); gdao.onApplicationEvent(new EntityDeletedEvent<>(loginServer, null)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(0)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); assertThat( jdbcTemplate.queryForObject( "select count(*) from external_group_mapping where origin = ? and group_id in (select id from groups where identity_zone_id=?)", new Object[] {LOGIN_SERVER, IdentityZoneHolder.get().getId()}, Integer.class), is(0)); } @Test public void test_cannot_delete_uaa_zone() { addMembers(); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); gdao.onApplicationEvent(new EntityDeletedEvent<>(IdentityZone.getUaa(), null)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); } @Test public void test_cannot_delete_uaa_provider() { IdentityZoneHolder.set(zone); addMembers(LOGIN_SERVER); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); IdentityProvider loginServer = new IdentityProvider().setOriginKey(UAA).setIdentityZoneId(zone.getId()); gdao.onApplicationEvent(new EntityDeletedEvent<>(loginServer, null)); assertThat( jdbcTemplate.queryForObject( "select count(*) from group_membership where group_id in (select id from groups where identity_zone_id=?)", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(4)); assertThat( jdbcTemplate.queryForObject( "select count(*) from groups where identity_zone_id=?", new Object[] {IdentityZoneHolder.get().getId()}, Integer.class), is(3)); } @Test public void canGetGroupsForMemberEvenWhenCycleExistsInGroupHierarchy() { addMember("g1", "m3", "USER", "READER"); addMember("g1", "g2", "GROUP", "READER"); addMember("g2", "g3", "GROUP", "READER"); addMember("g3", "g1", "GROUP", "READER"); Set<ScimGroup> groups = dao.getGroupsWithMember("m3", true); assertNotNull(groups); assertEquals(4, groups.size()); } @Test public void canAddMember() throws Exception { validateCount(0); ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null); ScimGroupMember m2 = dao.addMember("g2", m1); validateCount(1); assertEquals(ScimGroupMember.Type.USER, m2.getType()); assertEquals(ScimGroupMember.GROUP_MEMBER, m2.getRoles()); assertEquals("m1", m2.getMemberId()); validateUserGroups("m1", "test2"); } @Test(expected = ScimResourceNotFoundException.class) public void addMember_In_Different_Zone_Causes_Issues() throws Exception { String subdomain = generator.generate(); IdentityZone otherZone = MultitenancyFixture.identityZone(subdomain, subdomain); IdentityZoneHolder.set(otherZone); ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null); m1.setOrigin(OriginKeys.UAA); dao.addMember("g2", m1); } @Test(expected = ScimResourceNotFoundException.class) public void canAddMember_Validate_Origin_and_ZoneId() throws Exception { String subdomain = generator.generate(); IdentityZone otherZone = MultitenancyFixture.identityZone(subdomain, subdomain); IdentityZoneHolder.set(otherZone); validateCount(0); ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, null); m1.setOrigin(OriginKeys.UAA); dao.addMember("g2", m1); } @Test public void canAddNestedGroupMember() { addMember("g2", "m1", "USER", "READER"); ScimGroupMember g2 = new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_ADMIN); g2 = dao.addMember("g1", g2); assertEquals(ScimGroupMember.Type.GROUP, g2.getType()); assertEquals(ScimGroupMember.GROUP_ADMIN, g2.getRoles()); assertEquals("g2", g2.getMemberId()); validateUserGroups("m1", "test1.i", "test2"); } @Test(expected = InvalidScimResourceException.class) public void cannotNestGroupWithinItself() { ScimGroupMember g2 = new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_ADMIN); dao.addMember("g2", g2); } @Test public void canGetMembers() throws Exception { addMember("g1", "m1", "USER", "READER"); addMember("g1", "g2", "GROUP", "READER"); addMember("g3", "m2", "USER", "READER,WRITER"); List<ScimGroupMember> members = dao.getMembers("g1", null, false); assertNotNull(members); assertEquals(2, members.size()); members = dao.getMembers("g2", null, false); assertNotNull(members); assertEquals(0, members.size()); } @Test public void canGetMembers_Fails_In_Other_Zone() throws Exception { addMember("g1", "m1", "USER", "READER"); addMember("g1", "g2", "GROUP", "READER"); addMember("g3", "m2", "USER", "READER,WRITER"); IdentityZoneHolder.set( MultitenancyFixture.identityZone(generator.generate(), generator.generate())); assertEquals(0, dao.getMembers("g1", null, false).size()); } @Test public void testBackwardsCompatibilityToMemberAuthorities() { addMember("g1", "m1", "USER", "READ"); addMember("g1", "g2", "GROUP", "member"); addMember("g1", "m2", "USER", "READER,write"); List<ScimGroupMember> members = dao.getMembers("g1", null, false); assertNotNull(members); assertEquals(3, members.size()); List<ScimGroupMember> readers = new ArrayList<ScimGroupMember>(), writers = new ArrayList<ScimGroupMember>(); for (ScimGroupMember member : members) { if (member.getRoles().contains(ScimGroupMember.Role.READER)) { readers.add(member); } if (member.getRoles().contains(ScimGroupMember.Role.WRITER)) { writers.add(member); } } assertEquals(2, readers.size()); assertEquals(1, writers.size()); } @Test public void canGetDefaultGroupsUsingGetGroupsForMember() { Set<ScimGroup> groups = dao.getGroupsWithMember("m1", false); assertNotNull(groups); assertEquals(1, groups.size()); } @Test public void canGetAdminMembers() { addMember("g1", "m3", "USER", "READER,WRITER"); addMember("g1", "g2", "GROUP", "READER"); assertEquals(1, dao.getMembers("g1", ScimGroupMember.Role.WRITER).size()); assertTrue( dao.getMembers("g1", ScimGroupMember.Role.WRITER).contains(new ScimGroupMember("m3"))); assertEquals(0, dao.getMembers("g2", ScimGroupMember.Role.WRITER).size()); } @Test public void canGetMembersByAuthority() { addMember("g1", "m3", "USER", "READER,WRITER"); addMember("g1", "g2", "GROUP", "READER,MEMBER"); addMember("g2", "g3", "GROUP", "MEMBER"); assertEquals(1, dao.getMembers("g1", ScimGroupMember.Role.MEMBER).size()); assertEquals(2, dao.getMembers("g1", ScimGroupMember.Role.READER).size()); assertEquals(1, dao.getMembers("g1", ScimGroupMember.Role.WRITER).size()); assertEquals(1, dao.getMembers("g2", ScimGroupMember.Role.MEMBER).size()); assertEquals(0, dao.getMembers("g2", ScimGroupMember.Role.WRITER).size()); } @Test public void canGetMemberById() throws Exception { addMember("g3", "m2", "USER", "READER,WRITER"); ScimGroupMember m = dao.getMemberById("g3", "m2"); assertEquals(ScimGroupMember.Type.USER, m.getType()); assertEquals(ScimGroupMember.GROUP_ADMIN, m.getRoles()); } @Test public void canUpdateMember() throws Exception { addMember("g1", "m1", "USER", "READER"); validateCount(1); ScimGroupMember m1 = new ScimGroupMember("m1", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_ADMIN); ScimGroupMember m2 = dao.updateMember("g1", m1); assertEquals(ScimGroupMember.GROUP_ADMIN, m2.getRoles()); assertNotSame(m1, m2); validateCount(1); validateUserGroups("m1", "test1"); } @Test public void canUpdateOrAddMembers() { dao.addMember( "g1", new ScimGroupMember("m1", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_MEMBER)); dao.addMember( "g1", new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER)); dao.addMember( "g2", new ScimGroupMember("m2", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_ADMIN)); validateCount(3); validateUserGroups("m1", "test1"); validateUserGroups("m2", "test2", "test1.i"); ScimGroupMember g2 = new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_ADMIN); ScimGroupMember m3 = new ScimGroupMember("m3", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_MEMBER); List<ScimGroupMember> members = dao.updateOrAddMembers("g1", Arrays.asList(g2, m3)); validateCount(3); assertEquals(2, members.size()); assertTrue(members.contains(new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, null))); assertTrue(members.contains(new ScimGroupMember("m3", ScimGroupMember.Type.USER, null))); assertFalse(members.contains(new ScimGroupMember("m1", ScimGroupMember.Type.USER, null))); validateUserGroups("m3", "test1"); validateUserGroups("m2", "test2", "test1.i"); validateUserGroups("m1"); } @Test public void canRemoveMemberById() throws Exception { addMember("g1", "m1", "USER", "READER"); validateCount(1); dao.removeMemberById("g1", "m1"); validateCount(0); try { dao.getMemberById("g1", "m1"); fail("member should not exist"); } catch (MemberNotFoundException ex) { } } @Test public void canRemoveNestedGroupMember() { dao.addMember( "g1", new ScimGroupMember("m1", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_MEMBER)); dao.addMember( "g1", new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER)); dao.addMember( "g2", new ScimGroupMember("m2", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_ADMIN)); validateCount(3); validateUserGroups("m1", "test1"); validateUserGroups("m2", "test2", "test1.i"); dao.removeMemberById("g1", "g2"); try { dao.getMemberById("g1", "g2"); fail("member should not exist"); } catch (MemberNotFoundException ex) { } validateCount(2); validateUserGroups("m1", "test1"); validateUserGroups("m2", "test2"); } @Test public void canRemoveAllMembers() { dao.addMember( "g1", new ScimGroupMember("m1", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_MEMBER)); dao.addMember( "g1", new ScimGroupMember("g2", ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER)); dao.addMember( "g2", new ScimGroupMember("m2", ScimGroupMember.Type.USER, ScimGroupMember.GROUP_ADMIN)); validateCount(3); validateUserGroups("m1", "test1"); validateUserGroups("m2", "test2", "test1.i"); dao.removeMembersByGroupId("g1"); validateCount(1); try { dao.getMemberById("g1", "m1"); fail("member should not exist"); } catch (MemberNotFoundException ex) { } validateUserGroups("m1"); validateUserGroups("m2", "test2"); } }
private IdentityZone getIdentityZone() throws Exception { String subdomain = generator.generate(); return mockMvcUtils.createOtherIdentityZone( subdomain, getMockMvc(), getWebApplicationContext()); }