Skip to content

Commit

Permalink
OAK-9871 : AutoMembershipPrincipals.getAutoMembership must resolved i…
Browse files Browse the repository at this point in the history
…nherited groups
  • Loading branch information
anchela committed Jul 29, 2022
1 parent c194a0d commit 088764c
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.UserManager;
Expand All @@ -31,7 +32,6 @@
import javax.jcr.RepositoryException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -148,64 +148,110 @@ boolean isInheritedMember(@NotNull String idpName, @NotNull Group group, @NotNul
*
* @param idpName The name of an IDP
* @param authorizable The target user/group
* @param includeInherited Flag indicating if inherited groups should be resolved for global automemberbship groups.
* @return A collection of principals the given authorizable is an automatic member of.
*/
@NotNull
Collection<Principal> getAutoMembership(@NotNull String idpName, @NotNull Authorizable authorizable) {
ImmutableSet.Builder<Principal> builder = ImmutableSet.builder();

Map<Principal,Group> getAutoMembership(@NotNull String idpName, @NotNull Authorizable authorizable, boolean includeInherited) {
// global auto-membership
builder.addAll(collectGlobalAutoMembershipPrincipals(idpName));

Map<Principal,Group> map = collectGlobalAutoMembershipPrincipals(idpName);
if (includeInherited) {
for (Group gr : map.values().toArray(new Group[0])) {
collectInheritedPrincipals(gr, map);
}
}
// conditional auto-membership
AutoMembershipConfig config = autoMembershipConfigMap.get(idpName);
if (config != null) {
config.getAutoMembership(authorizable).forEach(groupId -> addVerifiedPrincipal(groupId, builder));
config.getAutoMembership(authorizable).forEach(groupId -> addVerifiedPrincipal(groupId, map, includeInherited));
}
return builder.build();
return map;
}
@NotNull
private Set<Principal> collectGlobalAutoMembershipPrincipals(@NotNull String idpName) {

private Map<Principal, Group> collectGlobalAutoMembershipPrincipals(@NotNull String idpName) {
Map<Principal, Group> map = Maps.newHashMap();
if (!principalMap.containsKey(idpName)) {
ImmutableSet.Builder<Principal> builder = ImmutableSet.builder();
String[] vs = autoMembershipMapping.get(idpName);
if (vs != null) {
for (String groupId : vs) {
addVerifiedPrincipal(groupId, builder);
addVerifiedPrincipal(groupId, map, false);
}
}
Set<Principal> principals = builder.build();
principalMap.put(idpName, principals);
return principals;
// only cache the principal instance but not the group (tree might become disconnected)
principalMap.put(idpName, ImmutableSet.copyOf(map.keySet()));
} else {
return principalMap.get(idpName);
// resolve Group objects from cached principals
principalMap.get(idpName).forEach(groupPrincipal -> {
Group gr = retrieveGroup(groupPrincipal);
if (gr != null) {
map.put(groupPrincipal, gr);
}

});
}
return map;
}

private void addVerifiedPrincipal(@NotNull String groupId, @NotNull ImmutableSet.Builder<Principal> builder) {
Principal principal = getVerifiedPrincipal(groupId);
if (principal != null) {
builder.add(principal);

private static void collectInheritedPrincipals(@NotNull Group group,
@NotNull Map<Principal, Group> map) {
try {
Iterator<Group> groups = group.memberOf();
while (groups.hasNext()) {
Group gr = groups.next();
Principal p = getVerifiedPrincipal(gr);
if (p != null) {
map.put(p, gr);
}
}
} catch (RepositoryException e) {
log.warn("Error while resolving inherited auto-membership", e);
}
}


private void addVerifiedPrincipal(@NotNull String groupId, @NotNull Map<Principal,Group> builder,
boolean includeInherited) {
try {
Authorizable a = userManager.getAuthorizable(groupId);
if (a == null || !a.isGroup()) {
log.warn("Configured auto-membership group {} does not exist -> Ignoring", groupId);
return;
}

Group group = (Group) a;
Principal principal = getVerifiedPrincipal(group);
if (principal != null) {
builder.put(principal, group);
if (includeInherited) {
collectInheritedPrincipals(group, builder);
}
}
} catch (RepositoryException e) {
log.debug("Failed to retrieved 'auto-membership' group with id {}", groupId, e);
}
}

@Nullable
private Principal getVerifiedPrincipal(@NotNull String groupId) {
private static Principal getVerifiedPrincipal(@NotNull Group group) throws RepositoryException {
Principal grPrincipal = group.getPrincipal();
if (GroupPrincipals.isGroup(grPrincipal)) {
return grPrincipal;
} else {
log.warn("Principal of group {} is not of group type -> Ignoring", group.getID());
return null;
}
}

@Nullable
private Group retrieveGroup(@NotNull Principal principal) {
try {
Authorizable gr = userManager.getAuthorizable(groupId);
Authorizable gr = userManager.getAuthorizable(principal);
if (gr != null && gr.isGroup()) {
Principal grPrincipal = gr.getPrincipal();
if (GroupPrincipals.isGroup(grPrincipal)) {
return grPrincipal;
} else {
log.warn("Principal of group {} is not of group type -> Ignoring", groupId);
}
return (Group) gr;
} else {
log.warn("Configured auto-membership group {} does not exist -> Ignoring", groupId);
log.warn("Cannot retrieve group from principal {} -> Ignoring", principal);
}
} catch (RepositoryException e) {
log.debug("Failed to retrieved 'auto-membership' group with id {}", groupId, e);
log.debug("Failed to retrieved 'auto-membership' group for principal {}", principal.getName(), e);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants.REP_EXTERNAL_ID;
Expand Down Expand Up @@ -130,19 +129,7 @@ private static boolean isMember(@NotNull AutoMembershipPrincipals amPrincipals,
// not an external user (NOTE: with dynamic membership enabled external groups will not be synced into the repository)
return RangeIteratorAdapter.EMPTY;
}
Collection<Principal> groupPrincipals = autoMembershipPrincipals.getAutoMembership(idpName, authorizable);
Set<Group> groups = groupPrincipals.stream().map(principal -> {
try {
Authorizable a = userManager.getAuthorizable(principal);
if (a != null && a.isGroup()) {
return (Group) a;
} else {
return null;
}
} catch (RepositoryException e) {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toSet());
Collection<Group> groups = autoMembershipPrincipals.getAutoMembership(idpName, authorizable, false).values();
Iterator<Group> groupIt = new RangeIteratorAdapter(groups);

if (!includeInherited) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ private Set<Principal> getGroupPrincipals(@NotNull Authorizable authorizable, @N
// add existing group principals as defined with the _autoMembership_ option.
String idpName = getIdpName(userTree);
if (idpName != null) {
groupPrincipals.addAll(autoMembershipPrincipals.getAutoMembership(idpName, authorizable));
// resolve automembership including inherited group membership
groupPrincipals.addAll(autoMembershipPrincipals.getAutoMembership(idpName, authorizable, true).keySet());
}
return groupPrincipals;
}
Expand Down
Loading

0 comments on commit 088764c

Please sign in to comment.