Skip to content

Commit 5838ea1

Browse files
committed
#503 Only prefetch groups and system users, but also prefetch membership
relationships
1 parent ccbacb4 commit 5838ea1

File tree

4 files changed

+153
-105
lines changed

4 files changed

+153
-105
lines changed

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableinstaller/impl/AuthorizableInstallerServiceImpl.java

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public void installAuthorizables(
106106
final Session session, InstallationLogger installLog)
107107
throws RepositoryException, AuthorizableCreatorException, LoginException, IOException, GeneralSecurityException {
108108

109-
UserManager userManager = new PrefetchedAuthorizablesUserManager(AccessControlUtils.getUserManagerAutoSaveDisabled(session), installLog);
109+
PrefetchingUserManager userManager = new PrefetchingUserManager(AccessControlUtils.getUserManagerAutoSaveDisabled(session), session.getValueFactory(), installLog);
110110

111111
Set<String> authorizablesFromConfigurations = authorizablesConfigBeans.getAuthorizableIds();
112112
for (AuthorizableConfigBean authorizableConfigBean : authorizablesConfigBeans) {
@@ -120,7 +120,7 @@ public void installAuthorizables(
120120
}
121121

122122
private void installAuthorizableConfigurationBean(final Session session,
123-
UserManager userManager,
123+
PrefetchingUserManager userManager,
124124
AcConfiguration acConfiguration,
125125
AuthorizableConfigBean authorizableConfigBean,
126126
InstallationLogger installLog, Set<String> authorizablesFromConfigurations)
@@ -250,16 +250,14 @@ private String getPassword(final AuthorizableConfigBean authorizableConfigBean)
250250
* regular relationships between groups contained in config are kept in isMemberOf */
251251
@SuppressWarnings("unchecked")
252252
void applyGroupMembershipConfigMembers(AcConfiguration acConfiguration, AuthorizableConfigBean authorizableConfigBean, InstallationLogger installLog,
253-
String authorizableId, UserManager userManager, Set<String> authorizablesFromConfigurations) throws RepositoryException {
253+
String authorizableId, PrefetchingUserManager userManager, Set<String> authorizablesFromConfigurations) throws RepositoryException {
254254
if (authorizableConfigBean.isGroup()) {
255255

256-
Group installedGroup = (Group) userManager.getAuthorizable(authorizableId);
257-
258256
String[] membersInConfigArr = authorizableConfigBean.getMembers();
259257
Set<String> membersInConfig = membersInConfigArr != null ? new HashSet<String>(Arrays.asList(membersInConfigArr)) : new HashSet<String>();
260258

261259
// initial set without regular users (those are never removed because that relationship is typically managed in AEM UI or LDAP/SAML/SSO/etc. )
262-
Set<String> relevantMembersInRepo = getDeclaredMembersWithoutRegularUsers(installedGroup);
260+
Set<String> relevantMembersInRepo = userManager.getDeclaredMembersWithoutRegularUsers(authorizableId);
263261

264262
// ensure authorizables from config itself that are added via isMemberOf are not deleted
265263
relevantMembersInRepo = new HashSet<String>(CollectionUtils.subtract(relevantMembersInRepo, authorizablesFromConfigurations));
@@ -271,6 +269,7 @@ void applyGroupMembershipConfigMembers(AcConfiguration acConfiguration, Authoriz
271269
Set<String> membersToAdd = new HashSet<String>(CollectionUtils.subtract(membersInConfig, relevantMembersInRepo));
272270
Set<String> membersToRemove = new HashSet<String>(CollectionUtils.subtract(relevantMembersInRepo, membersInConfig));
273271

272+
Group installedGroup = (Group) userManager.getAuthorizable(authorizableId);
274273
if (!membersToAdd.isEmpty()) {
275274
installLog.addVerboseMessage(LOG,
276275
"Adding " + membersToAdd.size() + " external members to group " + authorizableConfigBean.getAuthorizableId());
@@ -301,24 +300,6 @@ void applyGroupMembershipConfigMembers(AcConfiguration acConfiguration, Authoriz
301300
}
302301
}
303302

304-
private Set<String> getDeclaredMembersWithoutRegularUsers(Group installedGroup) throws RepositoryException {
305-
Set<String> membersInRepo = new HashSet<String>();
306-
Iterator<Authorizable> currentMemberInRepo = installedGroup.getDeclaredMembers();
307-
while (currentMemberInRepo.hasNext()) {
308-
Authorizable member = currentMemberInRepo.next();
309-
if (!isRegularUser(member)) {
310-
membersInRepo.add(member.getID());
311-
}
312-
}
313-
return membersInRepo;
314-
}
315-
316-
private boolean isRegularUser(Authorizable member) throws RepositoryException {
317-
return member != null && !member.isGroup() // if user
318-
&& !member.getPath().startsWith(Constants.USERS_ROOT + "/system/") // but not system user
319-
&& !member.getID().equals(Constants.USER_ANONYMOUS); // and not anonymous
320-
}
321-
322303
private Set<String> removeExternalMembersUnmanagedByConfiguration(AcConfiguration acConfiguration, AuthorizableConfigBean authorizableConfigBean,
323304
Set<String> relevantMembersInRepo, InstallationLogger installLog) {
324305
Set<String> relevantMembers = new HashSet<String>(relevantMembersInRepo);
@@ -504,13 +485,12 @@ private void deleteOldIntermediatePath(final Session session,
504485

505486
private void applyGroupMembershipConfigIsMemberOf(InstallationLogger installLog,
506487
AcConfiguration acConfiguration,
507-
AuthorizableConfigBean authorizableConfigBean, UserManager userManager, Session session,
488+
AuthorizableConfigBean authorizableConfigBean, PrefetchingUserManager userManager, Session session,
508489
Set<String> authorizablesFromConfigurations) throws RepositoryException, AuthorizableCreatorException {
509-
String[] memberOf = authorizableConfigBean.getIsMemberOf();
510490

511-
Authorizable currentGroupFromRepository = userManager.getAuthorizable(authorizableConfigBean.getAuthorizableId());
512-
Set<String> membershipGroupsFromConfig = getMembershipGroupsFromConfig(memberOf);
513-
Set<String> membershipGroupsFromRepository = getMembershipGroupsFromRepository(currentGroupFromRepository);
491+
String authId = authorizableConfigBean.getAuthorizableId();
492+
Set<String> membershipGroupsFromConfig = getMembershipGroupsFromConfig(authorizableConfigBean.getIsMemberOf());
493+
Set<String> membershipGroupsFromRepository = userManager.getDeclaredIsMemberOf(authId);
514494

515495
applyGroupMembershipConfigIsMemberOf(authorizableConfigBean, acConfiguration, installLog, userManager, session,
516496
membershipGroupsFromConfig,
@@ -547,19 +527,6 @@ private Authorizable createNewAuthorizable(
547527
return newAuthorizable;
548528
}
549529

550-
private Set<String> getMembershipGroupsFromRepository(Authorizable currentGroupFromRepository) throws RepositoryException {
551-
Set<String> membershipGroupsFromRepository = new HashSet<String>();
552-
Iterator<Group> memberOfGroupsIterator = currentGroupFromRepository.declaredMemberOf();
553-
554-
// build Set which contains the all Groups of which the existingGroup is
555-
// a member of
556-
while (memberOfGroupsIterator.hasNext()) {
557-
Authorizable memberOfGroup = memberOfGroupsIterator.next();
558-
membershipGroupsFromRepository.add(memberOfGroup.getID());
559-
}
560-
return membershipGroupsFromRepository;
561-
}
562-
563530
private Set<String> getMembershipGroupsFromConfig(String[] memberOf) {
564531
// Set which holds all other groups which the current Group from config
565532
// is a member of

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableinstaller/impl/PrefetchedAuthorizablesUserManager.java renamed to accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/authorizableinstaller/impl/PrefetchingUserManager.java

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,86 @@
33
import static biz.netcentric.cq.tools.actool.history.PersistableInstallationLogger.msHumanReadable;
44

55
import java.security.Principal;
6+
import java.util.Collections;
67
import java.util.HashMap;
8+
import java.util.HashSet;
79
import java.util.Iterator;
810
import java.util.Map;
11+
import java.util.Set;
912

1013
import javax.jcr.RepositoryException;
14+
import javax.jcr.ValueFactory;
1115

16+
import org.apache.jackrabbit.JcrConstants;
1217
import org.apache.jackrabbit.api.security.user.Authorizable;
1318
import org.apache.jackrabbit.api.security.user.Group;
1419
import org.apache.jackrabbit.api.security.user.Query;
1520
import org.apache.jackrabbit.api.security.user.QueryBuilder;
1621
import org.apache.jackrabbit.api.security.user.User;
1722
import org.apache.jackrabbit.api.security.user.UserManager;
23+
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
1824
import org.slf4j.Logger;
1925
import org.slf4j.LoggerFactory;
2026

21-
import biz.netcentric.cq.tools.actool.history.InstallationLogger;
27+
import com.google.common.annotations.VisibleForTesting;
2228

23-
/** Prefetches all authorizables in constructor to be able to answer getAuthorizable(userId) requests much quicker than the ootb oak
24-
* UserManager itself. */
25-
class PrefetchedAuthorizablesUserManager implements UserManager {
29+
import biz.netcentric.cq.tools.actool.helper.Constants;
30+
import biz.netcentric.cq.tools.actool.history.InstallationLogger;
2631

27-
private static final Logger LOG = LoggerFactory.getLogger(PrefetchedAuthorizablesUserManager.class);
32+
/** Prefetches a) all groups and system users (but not regular users) and b) all memberships between these authorizables in constructor. */
33+
class PrefetchingUserManager implements UserManager {
2834

29-
static final Query ALL_AUTHORIZABLES_QUERY = new Query() {
30-
public <T> void build(QueryBuilder<T> builder) {
31-
// fetch all authorizables
32-
}
33-
};
35+
private static final Logger LOG = LoggerFactory.getLogger(PrefetchingUserManager.class);
3436

3537
private final UserManager delegate;
36-
private final Map<String, Authorizable> authorizableCache;
38+
private final Map<String, Authorizable> authorizableCache = new HashMap<>();
39+
40+
private final Map<String, Set<String>> nonRegularUserMembersByAuthorizableId = new HashMap<>();
41+
private final Map<String, Set<String>> isMemberOfByAuthorizableId = new HashMap<>();
3742

38-
public PrefetchedAuthorizablesUserManager(UserManager delegate, InstallationLogger installLog) throws RepositoryException {
43+
public PrefetchingUserManager(UserManager delegate, final ValueFactory valueFactory, InstallationLogger installLog)
44+
throws RepositoryException {
3945
this.delegate = delegate;
40-
this.authorizableCache = new HashMap<>();
4146

4247
long startPrefetch = System.currentTimeMillis();
43-
Iterator<Authorizable> allAuthorizables = delegate.findAuthorizables(ALL_AUTHORIZABLES_QUERY);
48+
Iterator<Authorizable> allAuthorizables = delegate.findAuthorizables(new Query() {
49+
public <T> void build(QueryBuilder<T> builder) {
50+
builder.setCondition(
51+
builder.or( //
52+
builder.neq("@" + JcrConstants.JCR_PRIMARYTYPE, valueFactory.createValue(UserConstants.NT_REP_USER)),
53+
builder.eq("@" + UserConstants.REP_AUTHORIZABLE_ID, valueFactory.createValue(Constants.USER_ANONYMOUS))) //
54+
);
55+
}
56+
});
4457
while (allAuthorizables.hasNext()) {
4558
Authorizable auth = allAuthorizables.next();
46-
authorizableCache.put(auth.getID(), auth);
59+
String authId = auth.getID();
60+
authorizableCache.put(authId, auth);
61+
62+
// init lists
63+
nonRegularUserMembersByAuthorizableId.put(authId, new HashSet<String>());
64+
isMemberOfByAuthorizableId.put(authId, new HashSet<String>());
4765
}
4866

4967
installLog.addMessage(LOG, "Prefetched " + authorizableCache.size() + " authorizables in "
5068
+ msHumanReadable(System.currentTimeMillis() - startPrefetch));
69+
70+
long startPrefetchMemberships = System.currentTimeMillis();
71+
int membershipCount = 0;
72+
for (Authorizable authorizable : authorizableCache.values()) {
73+
String authId = authorizable.getID();
74+
Iterator<Group> declaredMemberOf = authorizable.declaredMemberOf();
75+
while (declaredMemberOf.hasNext()) {
76+
Group memberOfGroup = declaredMemberOf.next();
77+
String memberOfGroupId = memberOfGroup.getID();
78+
isMemberOfByAuthorizableId.get(authId).add(memberOfGroupId);
79+
nonRegularUserMembersByAuthorizableId.get(memberOfGroupId).add(authId);
80+
membershipCount++;
81+
}
82+
}
83+
84+
installLog.addMessage(LOG, "Prefetched " + membershipCount + " memberships in "
85+
+ msHumanReadable(System.currentTimeMillis() - startPrefetchMemberships));
5186
}
5287

5388
@Override
@@ -60,6 +95,26 @@ public Authorizable getAuthorizable(String id) throws RepositoryException {
6095
return authorizable;
6196
}
6297

98+
public Set<String> getDeclaredIsMemberOf(String id) throws RepositoryException {
99+
100+
if(isMemberOfByAuthorizableId.containsKey(id)) {
101+
return isMemberOfByAuthorizableId.get(id);
102+
} else {
103+
// for users fall back to retrieve on demand
104+
Set<String> memberOfSet = new HashSet<String>();
105+
Iterator<Group> memberOfIt = getAuthorizable(id).declaredMemberOf();
106+
while (memberOfIt.hasNext()) {
107+
Authorizable memberOfGroup = memberOfIt.next();
108+
memberOfSet.add(memberOfGroup.getID());
109+
}
110+
return memberOfSet;
111+
}
112+
}
113+
114+
public Set<String> getDeclaredMembersWithoutRegularUsers(String id) {
115+
return nonRegularUserMembersByAuthorizableId.containsKey(id) ? nonRegularUserMembersByAuthorizableId.get(id): Collections.<String>emptySet();
116+
}
117+
63118
public int getCacheSize() {
64119
return authorizableCache.size();
65120
}

0 commit comments

Comments
 (0)