@Override protected void syncMembership(@NotNull ExternalIdentity external, @NotNull Authorizable auth, long depth) throws RepositoryException { if (auth.isGroup()) { return; } if (auth.hasProperty(REP_LAST_SYNCED) && !auth.hasProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES)) { // user has been synchronized before dynamic membership has been turned on super.syncMembership(external, auth, depth); } else { // retrieve membership of the given external user (up to the configured // depth) and add (or replace) the rep:externalPrincipalNames property // with the accurate collection of principal names. try { Value[] vs; if (depth <= 0) { vs = new Value[0]; } else { Set<String> principalsNames = new HashSet<>(); collectPrincipalNames(principalsNames, external.getDeclaredGroups(), depth); vs = createValues(principalsNames); } auth.setProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, vs); } catch (ExternalIdentityException e) { log.error("Failed to synchronize membership information for external identity " + external.getId(), e); } } }
@Test public void testSyncMembershipDepthNoSync() throws Exception { ExternalUser externalUser = idp.listUsers().next(); Authorizable a = syncCtx.createUser(externalUser); root.commit(); assertTrue(externalUser.getDeclaredGroups().iterator().hasNext()); syncCtx.syncMembership(externalUser, a, 0); assertFalse(root.hasPendingChanges()); syncCtx.syncMembership(externalUser, a, -1); assertFalse(root.hasPendingChanges()); }
syncMembership(extGroup, grp, depth - 1); } else { log.debug("- group nesting level for '{}' reached", grp.getID());
@NotNull protected DefaultSyncResultImpl syncUser(@NotNull ExternalUser external, @NotNull User user) throws RepositoryException { // make also sure the local user to be synced belongs to the same IDP. Note: 'external' has been verified before. if (!isSameIDP(user)) { return new DefaultSyncResultImpl(new DefaultSyncedIdentity(external.getId(), external.getExternalId(), false, -1), SyncResult.Status.FOREIGN); } SyncResult.Status status; // check if user is expired if (!forceUserSync && !isExpired(user)) { status = SyncResult.Status.NOP; } else { syncExternalIdentity(external, user, config.user()); if (isExpired(user, config.user().getMembershipExpirationTime(), "Membership")) { // synchronize external memberships syncMembership(external, user, config.user().getMembershipNestingDepth()); } if (this.config.user().getDisableMissing() && user.isDisabled()) { status = SyncResult.Status.ENABLE; user.disable(null); } else { status = SyncResult.Status.UPDATE; } // finally "touch" the sync property user.setProperty(REP_LAST_SYNCED, nowValue); } return new DefaultSyncResultImpl(createSyncedIdentity(user), status); }
@Test public void testSyncMembershipGroupIsSyncedAsUser() throws Exception { ExternalUser fromIDP = idp.listUsers().next(); ExternalIdentityRef groupRef = fromIDP.getDeclaredGroups().iterator().next(); // sync the the ext-user from the idp (but make it just declare a single group) ExternalUser extuser = new ExternalUserWithDeclaredGroup(groupRef, fromIDP); Authorizable a = syncCtx.createUser(extuser); // create an external-user based on info that the IDP knows as group and sync it ExternalUser externalIdentity = new ExternalUserFromGroup(idp.getIdentity(groupRef)); Authorizable a2 = syncCtx.createUser(externalIdentity); assertFalse(a2.isGroup()); root.commit(); // now sync-ing the membership should not have any effect as the external // group referenced from 'extuser' has already been created in the system // as user. syncCtx.syncMembership(extuser, a, 1); assertFalse(root.hasPendingChanges()); }
@Test public void testSyncMembershipDepth1() throws Exception { ExternalUser externalUser = idp.listUsers().next(); Authorizable a = syncCtx.createUser(externalUser); syncCtx.syncMembership(externalUser, a, 1); assertTrue(root.hasPendingChanges()); for (ExternalIdentityRef ref : externalUser.getDeclaredGroups()) { Group g = userManager.getAuthorizable(ref.getId(), Group.class); assertNotNull(g); assertTrue(g.isDeclaredMember(a)); } }
@Test public void testSyncMembershipGroupIsExternalUser() throws Exception { // sync the 'wrong' external group into the repository ExternalIdentity externalIdentity = idp.listUsers().next(); sync(externalIdentity); // create external user with an synced-ext-user as declared group ExternalUser withWrongDeclaredGroup = new ExternalUserWithDeclaredGroup(externalIdentity.getExternalId()); try { Authorizable a = syncCtx.createUser(withWrongDeclaredGroup); root.commit(); syncCtx.syncMembership(withWrongDeclaredGroup, a, 1); assertFalse(root.hasPendingChanges()); } finally { Authorizable a = userManager.getAuthorizable(withWrongDeclaredGroup.getId()); if (a != null) { a.remove(); root.commit(); } } }
@Test public void testSyncMembershipDepthInfinite() throws Exception { ExternalUser externalUser = idp.listUsers().next(); Authorizable a = syncCtx.createUser(externalUser); syncCtx.syncMembership(externalUser, a, Long.MAX_VALUE); assertTrue(root.hasPendingChanges()); root.commit(); for (ExternalIdentityRef ref : externalUser.getDeclaredGroups()) { ExternalIdentity extGr = idp.getIdentity(ref); assertNotNull(extGr); for (ExternalIdentityRef inheritedGrRef : extGr.getDeclaredGroups()) { Group g = userManager.getAuthorizable(inheritedGrRef.getId(), Group.class); assertNotNull(g); if (Iterables.contains(externalUser.getDeclaredGroups(), inheritedGrRef)) { assertTrue(g.isDeclaredMember(a)); } else { assertFalse(g.isDeclaredMember(a)); } assertTrue(g.isMember(a)); } } }