KEYCLOAK-15102 Complement methods for accessing groups with Stream variants
This commit is contained in:
parent
6d45d715d3
commit
d59a74c364
51 changed files with 606 additions and 678 deletions
|
@ -24,6 +24,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
@ -162,7 +163,7 @@ public class GroupPolicyProviderFactory implements PolicyProviderFactory<GroupPo
|
||||||
config.put("groupsClaim", groupsClaim);
|
config.put("groupsClaim", groupsClaim);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GroupModel> topLevelGroups = authorization.getRealm().getTopLevelGroups();
|
List<GroupModel> topLevelGroups = authorization.getRealm().getTopLevelGroupsStream().collect(Collectors.toList());
|
||||||
|
|
||||||
for (GroupPolicyRepresentation.GroupDefinition definition : groups) {
|
for (GroupPolicyRepresentation.GroupDefinition definition : groups) {
|
||||||
GroupModel group = null;
|
GroupModel group = null;
|
||||||
|
@ -184,7 +185,7 @@ public class GroupPolicyProviderFactory implements PolicyProviderFactory<GroupPo
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
parent = topLevelGroups.stream().filter(groupModel -> groupModel.getName().equals(part)).findFirst().orElseThrow(() -> new RuntimeException("Top level group with name [" + part + "] not found"));
|
parent = topLevelGroups.stream().filter(groupModel -> groupModel.getName().equals(part)).findFirst().orElseThrow(() -> new RuntimeException("Top level group with name [" + part + "] not found"));
|
||||||
} else {
|
} else {
|
||||||
group = parent.getSubGroups().stream().filter(groupModel -> groupModel.getName().equals(part)).findFirst().orElseThrow(() -> new RuntimeException("Group with name [" + part + "] not found"));
|
group = parent.getSubGroupsStream().filter(groupModel -> groupModel.getName().equals(part)).findFirst().orElseThrow(() -> new RuntimeException("Group with name [" + part + "] not found"));
|
||||||
parent = group;
|
parent = group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,9 +284,8 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
UserModel proxy = proxy(realm, user, ldapUser, true);
|
UserModel proxy = proxy(realm, user, ldapUser, true);
|
||||||
DefaultRoles.addDefaultRoles(realm, proxy);
|
DefaultRoles.addDefaultRoles(realm, proxy);
|
||||||
|
|
||||||
for (GroupModel g : realm.getDefaultGroups()) {
|
realm.getDefaultGroupsStream().forEach(proxy::joinGroup);
|
||||||
proxy.joinGroup(g);
|
|
||||||
}
|
|
||||||
for (RequiredActionProviderModel r : realm.getRequiredActionProviders()) {
|
for (RequiredActionProviderModel r : realm.getRequiredActionProviders()) {
|
||||||
if (r.isEnabled() && r.isDefaultAction()) {
|
if (r.isEnabled() && r.isDefaultAction()) {
|
||||||
proxy.addRequiredAction(r.getAlias());
|
proxy.addRequiredAction(r.getAlias());
|
||||||
|
|
|
@ -26,8 +26,7 @@ import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||||
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||||
import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
|
import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.stream.Stream;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:jean-loup.maillet@yesitis.fr">Jean-Loup Maillet</a>
|
* @author <a href="mailto:jean-loup.maillet@yesitis.fr">Jean-Loup Maillet</a>
|
||||||
|
@ -51,12 +50,12 @@ public class HardcodedLDAPGroupStorageMapper extends AbstractLDAPStorageMapper {
|
||||||
return new UserModelDelegate(delegate) {
|
return new UserModelDelegate(delegate) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
Set<GroupModel> groups = new HashSet<GroupModel>(super.getGroups());
|
Stream<GroupModel> groups = super.getGroupsStream();
|
||||||
|
|
||||||
GroupModel group = getGroup(realm);
|
GroupModel group = getGroup(realm);
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
groups.add(group);
|
return Stream.concat(groups, Stream.of(group));
|
||||||
}
|
}
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package org.keycloak.storage.ldap.mappers.membership.group;
|
package org.keycloak.storage.ldap.mappers.membership.group;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.GroupModel;
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
|
@ -44,7 +43,6 @@ import org.keycloak.storage.ldap.mappers.membership.MembershipType;
|
||||||
import org.keycloak.storage.ldap.mappers.membership.UserRolesRetrieveStrategy;
|
import org.keycloak.storage.ldap.mappers.membership.UserRolesRetrieveStrategy;
|
||||||
import org.keycloak.storage.user.SynchronizationResult;
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -53,9 +51,12 @@ import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -269,7 +270,6 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
|
|
||||||
// List of group path groups known to the whole transaction
|
// List of group path groups known to the whole transaction
|
||||||
Map<String, GroupModel> transactionGroupPathGroups = getKcSubGroups(currentRealm, null)
|
Map<String, GroupModel> transactionGroupPathGroups = getKcSubGroups(currentRealm, null)
|
||||||
.stream()
|
|
||||||
.collect(Collectors.toMap(GroupModel::getName, Function.identity()));
|
.collect(Collectors.toMap(GroupModel::getName, Function.identity()));
|
||||||
|
|
||||||
for (int i = 0; i < groupsPerTransaction && it.hasNext(); i++) {
|
for (int i = 0; i < groupsPerTransaction && it.hasNext(); i++) {
|
||||||
|
@ -310,14 +310,8 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
String groupName = groupTreeEntry.getGroupName();
|
String groupName = groupTreeEntry.getGroupName();
|
||||||
|
|
||||||
// Check if group already exists
|
// Check if group already exists
|
||||||
GroupModel kcGroup = null;
|
GroupModel kcGroup = getKcSubGroups(realm, kcParent)
|
||||||
Collection<GroupModel> subgroups = getKcSubGroups(realm, kcParent);
|
.filter(g -> Objects.equals(g.getName(), groupName)).findFirst().orElse(null);
|
||||||
for (GroupModel group : subgroups) {
|
|
||||||
if (group.getName().equals(groupName)) {
|
|
||||||
kcGroup = group;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kcGroup != null) {
|
if (kcGroup != null) {
|
||||||
logger.debugf("Updated Keycloak group '%s' from LDAP", kcGroup.getName());
|
logger.debugf("Updated Keycloak group '%s' from LDAP", kcGroup.getName());
|
||||||
|
@ -344,14 +338,13 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
|
|
||||||
private void dropNonExistingKcGroups(RealmModel realm, SynchronizationResult syncResult, Set<String> visitedGroupIds) {
|
private void dropNonExistingKcGroups(RealmModel realm, SynchronizationResult syncResult, Set<String> visitedGroupIds) {
|
||||||
// Remove keycloak groups, which doesn't exists in LDAP
|
// Remove keycloak groups, which doesn't exists in LDAP
|
||||||
List<GroupModel> allGroups = getAllKcGroups(realm);
|
getAllKcGroups(realm)
|
||||||
for (GroupModel kcGroup : allGroups) {
|
.filter(kcGroup -> !visitedGroupIds.contains(kcGroup.getId()))
|
||||||
if (!visitedGroupIds.contains(kcGroup.getId())) {
|
.forEach(kcGroup -> {
|
||||||
logger.debugf("Removing Keycloak group '%s', which doesn't exist in LDAP", kcGroup.getName());
|
logger.debugf("Removing Keycloak group '%s', which doesn't exist in LDAP", kcGroup.getName());
|
||||||
realm.removeGroup(kcGroup);
|
realm.removeGroup(kcGroup);
|
||||||
syncResult.increaseRemoved();
|
syncResult.increaseRemoved();
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAttributesOfKCGroup(GroupModel kcGroup, LDAPObject ldapGroup) {
|
private void updateAttributesOfKCGroup(GroupModel kcGroup, LDAPObject ldapGroup) {
|
||||||
|
@ -374,14 +367,8 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
|
|
||||||
if (config.isPreserveGroupsInheritance()) {
|
if (config.isPreserveGroupsInheritance()) {
|
||||||
// Override if better effectivity or different algorithm is needed
|
// Override if better effectivity or different algorithm is needed
|
||||||
List<GroupModel> groups = getAllKcGroups(realm);
|
return getAllKcGroups(realm)
|
||||||
for (GroupModel group : groups) {
|
.filter(group -> Objects.equals(group.getName(), groupName)).findFirst().orElse(null);
|
||||||
if (group.getName().equals(groupName)) {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
} else {
|
} else {
|
||||||
// Without preserved inheritance, it's always at groups path
|
// Without preserved inheritance, it's always at groups path
|
||||||
return KeycloakModelUtils.findGroupByPath(realm, getKcGroupPathFromLDAPGroupName(groupName));
|
return KeycloakModelUtils.findGroupByPath(realm, getKcGroupPathFromLDAPGroupName(groupName));
|
||||||
|
@ -462,9 +449,8 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
Set<String> ldapGroupNames = new HashSet<>();
|
Set<String> ldapGroupNames = new HashSet<>();
|
||||||
|
|
||||||
// Create or update KC groups to LDAP including their attributes
|
// Create or update KC groups to LDAP including their attributes
|
||||||
for (GroupModel kcGroup : getKcSubGroups(realm, null)) {
|
getKcSubGroups(realm, null)
|
||||||
processKeycloakGroupSyncToLDAP(kcGroup, ldapGroupsMap, ldapGroupNames, syncResult);
|
.forEach(kcGroup -> processKeycloakGroupSyncToLDAP(kcGroup, ldapGroupsMap, ldapGroupNames, syncResult));
|
||||||
}
|
|
||||||
|
|
||||||
// If dropNonExisting, then drop all groups, which doesn't exist in KC from LDAP as well
|
// If dropNonExisting, then drop all groups, which doesn't exist in KC from LDAP as well
|
||||||
if (config.isDropNonExistingGroupsDuringSync()) {
|
if (config.isDropNonExistingGroupsDuringSync()) {
|
||||||
|
@ -480,9 +466,8 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
|
|
||||||
// Finally process memberships,
|
// Finally process memberships,
|
||||||
if (config.isPreserveGroupsInheritance()) {
|
if (config.isPreserveGroupsInheritance()) {
|
||||||
for (GroupModel kcGroup : getKcSubGroups(realm, null)) {
|
getKcSubGroups(realm, null)
|
||||||
processKeycloakGroupMembershipsSyncToLDAP(kcGroup, ldapGroupsMap);
|
.forEach(kcGroup -> processKeycloakGroupMembershipsSyncToLDAP(kcGroup, ldapGroupsMap));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return syncResult;
|
return syncResult;
|
||||||
|
@ -497,9 +482,8 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
// extract group attributes to be updated to LDAP
|
// extract group attributes to be updated to LDAP
|
||||||
Map<String, Set<String>> supportedLdapAttributes = new HashMap<>();
|
Map<String, Set<String>> supportedLdapAttributes = new HashMap<>();
|
||||||
for (String attrName : config.getGroupAttributes()) {
|
for (String attrName : config.getGroupAttributes()) {
|
||||||
List<String> kcAttrValues = kcGroup.getAttribute(attrName);
|
Set<String> valueSet = kcGroup.getAttributeStream(attrName).collect(Collectors.toSet());
|
||||||
Set<String> attrValues2 = (kcAttrValues == null || kcAttrValues.isEmpty()) ? null : new HashSet<>(kcAttrValues);
|
supportedLdapAttributes.put(attrName, valueSet.isEmpty() ? null : valueSet);
|
||||||
supportedLdapAttributes.put(attrName, attrValues2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LDAPObject ldapGroup = ldapGroupsMap.get(groupName);
|
LDAPObject ldapGroup = ldapGroupsMap.get(groupName);
|
||||||
|
@ -520,9 +504,8 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
ldapGroupNames.add(groupName);
|
ldapGroupNames.add(groupName);
|
||||||
|
|
||||||
// process KC subgroups
|
// process KC subgroups
|
||||||
for (GroupModel kcSubgroup : kcGroup.getSubGroups()) {
|
kcGroup.getSubGroupsStream()
|
||||||
processKeycloakGroupSyncToLDAP(kcSubgroup, ldapGroupsMap, ldapGroupNames, syncResult);
|
.forEach(kcSubgroup -> processKeycloakGroupSyncToLDAP(kcSubgroup, ldapGroupsMap, ldapGroupNames, syncResult));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update memberships of group in LDAP based on subgroups from KC. Do it recursively
|
// Update memberships of group in LDAP based on subgroups from KC. Do it recursively
|
||||||
|
@ -533,7 +516,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
String membershipUserLdapAttrName = getMembershipUserLdapAttribute(); // Not applicable for groups, but needs to be here
|
String membershipUserLdapAttrName = getMembershipUserLdapAttribute(); // Not applicable for groups, but needs to be here
|
||||||
|
|
||||||
// Add LDAP subgroups, which are KC subgroups
|
// Add LDAP subgroups, which are KC subgroups
|
||||||
Set<GroupModel> kcSubgroups = kcGroup.getSubGroups();
|
Set<GroupModel> kcSubgroups = kcGroup.getSubGroupsStream().collect(Collectors.toSet());
|
||||||
for (GroupModel kcSubgroup : kcSubgroups) {
|
for (GroupModel kcSubgroup : kcSubgroups) {
|
||||||
LDAPObject ldapSubgroup = ldapGroupsMap.get(kcSubgroup.getName());
|
LDAPObject ldapSubgroup = ldapGroupsMap.get(kcSubgroup.getName());
|
||||||
if (!toRemoveSubgroupsDNs.remove(ldapSubgroup.getDn())) {
|
if (!toRemoveSubgroupsDNs.remove(ldapSubgroup.getDn())) {
|
||||||
|
@ -549,7 +532,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
LDAPUtils.deleteMember(ldapProvider, MembershipType.DN, config.getMembershipLdapAttribute(), membershipUserLdapAttrName, ldapGroup, fakeGroup);
|
LDAPUtils.deleteMember(ldapProvider, MembershipType.DN, config.getMembershipLdapAttribute(), membershipUserLdapAttrName, ldapGroup, fakeGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GroupModel kcSubgroup : kcGroup.getSubGroups()) {
|
for (GroupModel kcSubgroup : kcSubgroups) {
|
||||||
processKeycloakGroupMembershipsSyncToLDAP(kcSubgroup, ldapGroupsMap);
|
processKeycloakGroupMembershipsSyncToLDAP(kcSubgroup, ldapGroupsMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -709,20 +692,18 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasRole(RoleModel role) {
|
public boolean hasRole(RoleModel role) {
|
||||||
return super.hasRole(role) || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
return super.hasRole(role) || RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
Set<GroupModel> ldapGroupMappings = getLDAPGroupMappingsConverted();
|
Stream<GroupModel> ldapGroupMappings = getLDAPGroupMappingsConverted();
|
||||||
if (config.getMode() == LDAPGroupMapperMode.LDAP_ONLY) {
|
if (config.getMode() == LDAPGroupMapperMode.LDAP_ONLY) {
|
||||||
// Use just group mappings from LDAP
|
// Use just group mappings from LDAP
|
||||||
return ldapGroupMappings;
|
return ldapGroupMappings;
|
||||||
} else {
|
} else {
|
||||||
// Merge mappings from both DB and LDAP
|
// Merge mappings from both DB and LDAP
|
||||||
Set<GroupModel> modelGroupMappings = super.getGroups();
|
return Stream.concat(ldapGroupMappings, super.getGroupsStream());
|
||||||
ldapGroupMappings.addAll(modelGroupMappings);
|
|
||||||
return ldapGroupMappings;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,28 +751,22 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMemberOf(GroupModel group) {
|
public boolean isMemberOf(GroupModel group) {
|
||||||
Set<GroupModel> ldapGroupMappings = getGroups();
|
return getGroupsStream().anyMatch(Predicate.isEqual(group));
|
||||||
return ldapGroupMappings.contains(group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<GroupModel> getLDAPGroupMappingsConverted() {
|
protected Stream<GroupModel> getLDAPGroupMappingsConverted() {
|
||||||
if (cachedLDAPGroupMappings != null) {
|
if (cachedLDAPGroupMappings != null) {
|
||||||
return new HashSet<>(cachedLDAPGroupMappings);
|
return cachedLDAPGroupMappings.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<LDAPObject> ldapGroups = getLDAPGroupMappings(ldapUser);
|
List<LDAPObject> ldapGroups = getLDAPGroupMappings(ldapUser);
|
||||||
|
|
||||||
Set<GroupModel> result = new HashSet<>();
|
cachedLDAPGroupMappings = ldapGroups.stream()
|
||||||
for (LDAPObject ldapGroup : ldapGroups) {
|
.map(ldapGroup -> findKcGroupOrSyncFromLDAP(realm, ldapGroup, this))
|
||||||
GroupModel kcGroup = findKcGroupOrSyncFromLDAP(realm, ldapGroup, this);
|
.filter(Objects::nonNull)
|
||||||
if (kcGroup != null) {
|
.collect(Collectors.toSet());
|
||||||
result.add(kcGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedLDAPGroupMappings = new HashSet<>(result);
|
return cachedLDAPGroupMappings.stream();
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,56 +801,34 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
/**
|
/**
|
||||||
* Provides a list of all KC sub groups from given parent group or from groups path.
|
* Provides a list of all KC sub groups from given parent group or from groups path.
|
||||||
*/
|
*/
|
||||||
protected Collection<GroupModel> getKcSubGroups(RealmModel realm, GroupModel parentGroup) {
|
protected Stream<GroupModel> getKcSubGroups(RealmModel realm, GroupModel parentGroup) {
|
||||||
|
|
||||||
// If no parent group given then use groups path
|
// If no parent group given then use groups path
|
||||||
if (parentGroup == null) {
|
if (parentGroup == null) {
|
||||||
parentGroup = getKcGroupsPathGroup(realm);
|
parentGroup = getKcGroupsPathGroup(realm);
|
||||||
}
|
}
|
||||||
return parentGroup == null ? realm.getTopLevelGroups() : parentGroup.getSubGroups();
|
return parentGroup == null ? realm.getTopLevelGroupsStream() : parentGroup.getSubGroupsStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a list of all KC groups (with their sub groups) from groups path configured by the "Groups Path" configuration property.
|
* Provides a stream of all KC groups (with their sub groups) from groups path configured by the "Groups Path" configuration property.
|
||||||
*/
|
*/
|
||||||
protected List<GroupModel> getAllKcGroups(RealmModel realm) {
|
protected Stream<GroupModel> getAllKcGroups(RealmModel realm) {
|
||||||
Long start = null;
|
|
||||||
if (logger.isTraceEnabled()) {
|
|
||||||
logger.trace("Calling getAllKcGroups started");
|
|
||||||
start = Time.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupModel topParentGroup = getKcGroupsPathGroup(realm);
|
GroupModel topParentGroup = getKcGroupsPathGroup(realm);
|
||||||
|
|
||||||
List<GroupModel> allGroups = realm.getGroups();
|
Stream<GroupModel> allGroups = realm.getGroupsStream();
|
||||||
List<GroupModel> filtered = new ArrayList<>();
|
if (topParentGroup == null) return allGroups;
|
||||||
for (GroupModel group : allGroups) {
|
|
||||||
if (topParentGroup == null) {
|
return allGroups.filter(group -> {
|
||||||
filtered.add(group);
|
|
||||||
} else {
|
|
||||||
// Check if group is descendant of the topParentGroup (which is group configured by "Groups Path")
|
// Check if group is descendant of the topParentGroup (which is group configured by "Groups Path")
|
||||||
boolean finished = false;
|
|
||||||
GroupModel parent = group.getParent();
|
GroupModel parent = group.getParent();
|
||||||
while (!finished) {
|
while (parent != null) {
|
||||||
if (parent == null) {
|
|
||||||
finished = true;
|
|
||||||
} else {
|
|
||||||
if (parent.getId().equals(topParentGroup.getId())) {
|
if (parent.getId().equals(topParentGroup.getId())) {
|
||||||
filtered.add(group);
|
return true;
|
||||||
finished = true;
|
}
|
||||||
} else {
|
|
||||||
parent = parent.getParent();
|
parent = parent.getParent();
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
|
||||||
long took = Time.currentTimeMillis() - start;
|
|
||||||
logger.tracef("Calling getAllKcGroups took %d ms. Count of groups %d", took, filtered.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
return filtered;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,7 +369,7 @@ public class RoleLDAPStorageMapper extends AbstractLDAPStorageMapper implements
|
||||||
public boolean hasRole(RoleModel role) {
|
public boolean hasRole(RoleModel role) {
|
||||||
Set<RoleModel> roles = getRoleMappings();
|
Set<RoleModel> roles = getRoleMappings();
|
||||||
return RoleUtils.hasRole(roles, role)
|
return RoleUtils.hasRole(roles, role)
|
||||||
|| RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
|| RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -136,10 +137,10 @@ public class GroupAdapter implements GroupModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getAttribute(String name) {
|
public Stream<String> getAttributeStream(String name) {
|
||||||
List<String> values = cached.getAttributes(modelSupplier).get(name);
|
List<String> values = cached.getAttributes(modelSupplier).get(name);
|
||||||
if (values == null) return null;
|
if (values == null) return Stream.empty();
|
||||||
return values;
|
return values.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -234,20 +235,20 @@ public class GroupAdapter implements GroupModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getSubGroups() {
|
public Stream<GroupModel> getSubGroupsStream() {
|
||||||
if (isUpdated()) return updated.getSubGroups();
|
if (isUpdated()) return updated.getSubGroupsStream();
|
||||||
Set<GroupModel> subGroups = new HashSet<>();
|
Set<GroupModel> subGroups = new HashSet<>();
|
||||||
for (String id : cached.getSubGroups(modelSupplier)) {
|
for (String id : cached.getSubGroups(modelSupplier)) {
|
||||||
GroupModel subGroup = keycloakSession.groups().getGroupById(realm, id);
|
GroupModel subGroup = keycloakSession.groups().getGroupById(realm, id);
|
||||||
if (subGroup == null) {
|
if (subGroup == null) {
|
||||||
// chance that role was removed, so just delegate to persistence and get user invalidated
|
// chance that role was removed, so just delegate to persistence and get user invalidated
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
return updated.getSubGroups();
|
return updated.getSubGroupsStream();
|
||||||
|
|
||||||
}
|
}
|
||||||
subGroups.add(subGroup);
|
subGroups.add(subGroup);
|
||||||
}
|
}
|
||||||
return subGroups;
|
return subGroups.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -705,15 +705,9 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getDefaultGroups() {
|
public Stream<GroupModel> getDefaultGroupsStream() {
|
||||||
if (isUpdated()) return updated.getDefaultGroups();
|
if (isUpdated()) return updated.getDefaultGroupsStream();
|
||||||
|
return cached.getDefaultGroups().stream().map(this::getGroupById);
|
||||||
List<GroupModel> defaultGroups = new LinkedList<>();
|
|
||||||
for (String id : cached.getDefaultGroups()) {
|
|
||||||
defaultGroups.add(cacheSession.getGroupById(this, id));
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(defaultGroups);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1420,8 +1414,8 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
return cacheSession.getGroups(this);
|
return cacheSession.getGroupsStream(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1435,18 +1429,18 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups() {
|
public Stream<GroupModel> getTopLevelGroupsStream() {
|
||||||
return cacheSession.getTopLevelGroups(this);
|
return cacheSession.getTopLevelGroupsStream(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups(Integer first, Integer max) {
|
public Stream<GroupModel> getTopLevelGroupsStream(Integer first, Integer max) {
|
||||||
return cacheSession.getTopLevelGroups(this, first, max);
|
return cacheSession.getTopLevelGroupsStream(this, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> searchForGroupByName(String search, Integer first, Integer max) {
|
public Stream<GroupModel> searchForGroupByNameStream(String search, Integer first, Integer max) {
|
||||||
return cacheSession.searchForGroupByName(this, search, first, max);
|
return cacheSession.searchForGroupByNameStream(this, search, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -866,11 +866,11 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroups(RealmModel realm) {
|
public Stream<GroupModel> getGroupsStream(RealmModel realm) {
|
||||||
String cacheKey = getGroupsQueryCacheKey(realm.getId());
|
String cacheKey = getGroupsQueryCacheKey(realm.getId());
|
||||||
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
|
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
|
||||||
if (queryDB) {
|
if (queryDB) {
|
||||||
return getGroupDelegate().getGroups(realm);
|
return getGroupDelegate().getGroupsStream(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
||||||
|
@ -880,28 +880,26 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
|
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
List<GroupModel> model = getGroupDelegate().getGroups(realm);
|
List<GroupModel> model = getGroupDelegate().getGroupsStream(realm).collect(Collectors.toList());
|
||||||
if (model == null) return null;
|
if (model.isEmpty()) return Stream.empty();
|
||||||
Set<String> ids = new HashSet<>();
|
Set<String> ids = new HashSet<>();
|
||||||
for (GroupModel client : model) ids.add(client.getId());
|
for (GroupModel client : model) ids.add(client.getId());
|
||||||
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
||||||
logger.tracev("adding realm getGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
logger.tracev("adding realm getGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
||||||
cache.addRevisioned(query, startupRevision);
|
cache.addRevisioned(query, startupRevision);
|
||||||
return model;
|
return model.stream();
|
||||||
}
|
}
|
||||||
List<GroupModel> list = new LinkedList<>();
|
List<GroupModel> list = new LinkedList<>();
|
||||||
for (String id : query.getGroups()) {
|
for (String id : query.getGroups()) {
|
||||||
GroupModel group = session.groups().getGroupById(realm, id);
|
GroupModel group = session.groups().getGroupById(realm, id);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
invalidations.add(cacheKey);
|
invalidations.add(cacheKey);
|
||||||
return getGroupDelegate().getGroups(realm);
|
return getGroupDelegate().getGroupsStream(realm);
|
||||||
}
|
}
|
||||||
list.add(group);
|
list.add(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
list.sort(Comparator.comparing(GroupModel::getName));
|
return list.stream().sorted(Comparator.comparing(GroupModel::getName));
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -920,16 +918,16 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
public Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
||||||
return getGroupDelegate().getGroupsByRole(realm, role, firstResult, maxResults);
|
return getGroupDelegate().getGroupsByRoleStream(realm, role, firstResult, maxResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm) {
|
||||||
String cacheKey = getTopGroupsQueryCacheKey(realm.getId());
|
String cacheKey = getTopGroupsQueryCacheKey(realm.getId());
|
||||||
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
|
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId());
|
||||||
if (queryDB) {
|
if (queryDB) {
|
||||||
return getGroupDelegate().getTopLevelGroups(realm);
|
return getGroupDelegate().getTopLevelGroupsStream(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
||||||
|
@ -939,36 +937,34 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
|
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
List<GroupModel> model = getGroupDelegate().getTopLevelGroups(realm);
|
List<GroupModel> model = getGroupDelegate().getTopLevelGroupsStream(realm).collect(Collectors.toList());
|
||||||
if (model == null) return null;
|
if (model.isEmpty()) return Stream.empty();
|
||||||
Set<String> ids = new HashSet<>();
|
Set<String> ids = new HashSet<>();
|
||||||
for (GroupModel client : model) ids.add(client.getId());
|
for (GroupModel client : model) ids.add(client.getId());
|
||||||
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
||||||
logger.tracev("adding realm getTopLevelGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
logger.tracev("adding realm getTopLevelGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
||||||
cache.addRevisioned(query, startupRevision);
|
cache.addRevisioned(query, startupRevision);
|
||||||
return model;
|
return model.stream();
|
||||||
}
|
}
|
||||||
List<GroupModel> list = new LinkedList<>();
|
List<GroupModel> list = new LinkedList<>();
|
||||||
for (String id : query.getGroups()) {
|
for (String id : query.getGroups()) {
|
||||||
GroupModel group = session.groups().getGroupById(realm, id);
|
GroupModel group = session.groups().getGroupById(realm, id);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
invalidations.add(cacheKey);
|
invalidations.add(cacheKey);
|
||||||
return getGroupDelegate().getTopLevelGroups(realm);
|
return getGroupDelegate().getTopLevelGroupsStream(realm);
|
||||||
}
|
}
|
||||||
list.add(group);
|
list.add(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
list.sort(Comparator.comparing(GroupModel::getName));
|
return list.stream().sorted(Comparator.comparing(GroupModel::getName));
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups(RealmModel realm, Integer first, Integer max) {
|
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer first, Integer max) {
|
||||||
String cacheKey = getTopGroupsQueryCacheKey(realm.getId() + first + max);
|
String cacheKey = getTopGroupsQueryCacheKey(realm.getId() + first + max);
|
||||||
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId() + first + max);
|
boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId() + first + max);
|
||||||
if (queryDB) {
|
if (queryDB) {
|
||||||
return getGroupDelegate().getTopLevelGroups(realm, first, max);
|
return getGroupDelegate().getTopLevelGroupsStream(realm, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
GroupListQuery query = cache.get(cacheKey, GroupListQuery.class);
|
||||||
|
@ -978,33 +974,31 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
|
|
||||||
if (Objects.isNull(query)) {
|
if (Objects.isNull(query)) {
|
||||||
Long loaded = cache.getCurrentRevision(cacheKey);
|
Long loaded = cache.getCurrentRevision(cacheKey);
|
||||||
List<GroupModel> model = getGroupDelegate().getTopLevelGroups(realm, first, max);
|
List<GroupModel> model = getGroupDelegate().getTopLevelGroupsStream(realm, first, max).collect(Collectors.toList());
|
||||||
if (model == null) return null;
|
if (model.isEmpty()) return Stream.empty();
|
||||||
Set<String> ids = new HashSet<>();
|
Set<String> ids = new HashSet<>();
|
||||||
for (GroupModel client : model) ids.add(client.getId());
|
for (GroupModel client : model) ids.add(client.getId());
|
||||||
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
query = new GroupListQuery(loaded, cacheKey, realm, ids);
|
||||||
logger.tracev("adding realm getTopLevelGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
logger.tracev("adding realm getTopLevelGroups cache miss: realm {0} key {1}", realm.getName(), cacheKey);
|
||||||
cache.addRevisioned(query, startupRevision);
|
cache.addRevisioned(query, startupRevision);
|
||||||
return model;
|
return model.stream();
|
||||||
}
|
}
|
||||||
List<GroupModel> list = new LinkedList<>();
|
List<GroupModel> list = new LinkedList<>();
|
||||||
for (String id : query.getGroups()) {
|
for (String id : query.getGroups()) {
|
||||||
GroupModel group = session.groups().getGroupById(realm, id);
|
GroupModel group = session.groups().getGroupById(realm, id);
|
||||||
if (Objects.isNull(group)) {
|
if (Objects.isNull(group)) {
|
||||||
invalidations.add(cacheKey);
|
invalidations.add(cacheKey);
|
||||||
return getGroupDelegate().getTopLevelGroups(realm);
|
return getGroupDelegate().getTopLevelGroupsStream(realm);
|
||||||
}
|
}
|
||||||
list.add(group);
|
list.add(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
list.sort(Comparator.comparing(GroupModel::getName));
|
return list.stream().sorted(Comparator.comparing(GroupModel::getName));
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer first, Integer max) {
|
public Stream<GroupModel> searchForGroupByNameStream(RealmModel realm, String search, Integer first, Integer max) {
|
||||||
return getGroupDelegate().searchForGroupByName(realm, search, first, max);
|
return getGroupDelegate().searchForGroupByNameStream(realm, search, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -315,7 +316,7 @@ public class UserAdapter implements CachedUserModel {
|
||||||
for (RoleModel mapping: mappings) {
|
for (RoleModel mapping: mappings) {
|
||||||
if (mapping.hasRole(role)) return true;
|
if (mapping.hasRole(role)) return true;
|
||||||
}
|
}
|
||||||
return RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
return RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -348,20 +349,20 @@ public class UserAdapter implements CachedUserModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
if (updated != null) return updated.getGroups();
|
if (updated != null) return updated.getGroupsStream();
|
||||||
Set<GroupModel> groups = new LinkedHashSet<>();
|
Set<GroupModel> groups = new LinkedHashSet<>();
|
||||||
for (String id : cached.getGroups(modelSupplier)) {
|
for (String id : cached.getGroups(modelSupplier)) {
|
||||||
GroupModel groupModel = keycloakSession.groups().getGroupById(realm, id);
|
GroupModel groupModel = keycloakSession.groups().getGroupById(realm, id);
|
||||||
if (groupModel == null) {
|
if (groupModel == null) {
|
||||||
// chance that role was removed, so just delete to persistence and get user invalidated
|
// chance that role was removed, so just delete to persistence and get user invalidated
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
return updated.getGroups();
|
return updated.getGroupsStream();
|
||||||
}
|
}
|
||||||
groups.add(groupModel);
|
groups.add(groupModel);
|
||||||
|
|
||||||
}
|
}
|
||||||
return groups;
|
return groups.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -381,8 +382,7 @@ public class UserAdapter implements CachedUserModel {
|
||||||
public boolean isMemberOf(GroupModel group) {
|
public boolean isMemberOf(GroupModel group) {
|
||||||
if (updated != null) return updated.isMemberOf(group);
|
if (updated != null) return updated.isMemberOf(group);
|
||||||
if (cached.getGroups(modelSupplier).contains(group.getId())) return true;
|
if (cached.getGroups(modelSupplier).contains(group.getId())) return true;
|
||||||
Set<GroupModel> roles = getGroups();
|
return RoleUtils.isMember(getGroupsStream(), group);
|
||||||
return RoleUtils.isMember(roles, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class CachedGroup extends AbstractRevisioned implements InRealm {
|
||||||
this.parentId = group.getParentId();
|
this.parentId = group.getParentId();
|
||||||
this.attributes = new DefaultLazyLoader<>(source -> new MultivaluedHashMap<>(source.getAttributes()), MultivaluedHashMap::new);
|
this.attributes = new DefaultLazyLoader<>(source -> new MultivaluedHashMap<>(source.getAttributes()), MultivaluedHashMap::new);
|
||||||
this.roleMappings = new DefaultLazyLoader<>(source -> source.getRoleMappings().stream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet);
|
this.roleMappings = new DefaultLazyLoader<>(source -> source.getRoleMappings().stream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet);
|
||||||
this.subGroups = new DefaultLazyLoader<>(source -> source.getSubGroups().stream().map(GroupModel::getId).collect(Collectors.toSet()), Collections::emptySet);
|
this.subGroups = new DefaultLazyLoader<>(source -> source.getSubGroupsStream().map(GroupModel::getId).collect(Collectors.toSet()), Collections::emptySet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealm() {
|
public String getRealm() {
|
||||||
|
|
|
@ -43,6 +43,7 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -148,7 +149,7 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
return identityProviderMapperSet;
|
return identityProviderMapperSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> defaultGroups = new LinkedList<>();
|
protected List<String> defaultGroups;
|
||||||
protected List<String> clientScopes = new LinkedList<>();
|
protected List<String> clientScopes = new LinkedList<>();
|
||||||
protected List<String> defaultDefaultClientScopes = new LinkedList<>();
|
protected List<String> defaultDefaultClientScopes = new LinkedList<>();
|
||||||
protected List<String> optionalDefaultClientScopes = new LinkedList<>();
|
protected List<String> optionalDefaultClientScopes = new LinkedList<>();
|
||||||
|
@ -282,9 +283,7 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
requiredActionProvidersByAlias.put(action.getAlias(), action);
|
requiredActionProvidersByAlias.put(action.getAlias(), action);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GroupModel group : model.getDefaultGroups()) {
|
defaultGroups = model.getDefaultGroupsStream().map(GroupModel::getId).collect(Collectors.toList());
|
||||||
defaultGroups.add(group.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
browserFlow = model.getBrowserFlow();
|
browserFlow = model.getBrowserFlow();
|
||||||
registrationFlow = model.getRegistrationFlow();
|
registrationFlow = model.getRegistrationFlow();
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class CachedUser extends AbstractExtendableRevisioned implements InRealm
|
||||||
this.requiredActions = new DefaultLazyLoader<>(UserModel::getRequiredActions, Collections::emptySet);
|
this.requiredActions = new DefaultLazyLoader<>(UserModel::getRequiredActions, Collections::emptySet);
|
||||||
this.attributes = new DefaultLazyLoader<>(userModel -> new MultivaluedHashMap<>(userModel.getAttributes()), MultivaluedHashMap::new);
|
this.attributes = new DefaultLazyLoader<>(userModel -> new MultivaluedHashMap<>(userModel.getAttributes()), MultivaluedHashMap::new);
|
||||||
this.roleMappings = new DefaultLazyLoader<>(userModel -> userModel.getRoleMappings().stream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet);
|
this.roleMappings = new DefaultLazyLoader<>(userModel -> userModel.getRoleMappings().stream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet);
|
||||||
this.groups = new DefaultLazyLoader<>(userModel -> userModel.getGroups().stream().map(GroupModel::getId).collect(Collectors.toCollection(LinkedHashSet::new)), LinkedHashSet::new);
|
this.groups = new DefaultLazyLoader<>(userModel -> userModel.getGroupsStream().map(GroupModel::getId).collect(Collectors.toCollection(LinkedHashSet::new)), LinkedHashSet::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealm() {
|
public String getRealm() {
|
||||||
|
|
|
@ -36,9 +36,13 @@ import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
|
||||||
|
import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -119,17 +123,10 @@ public class GroupAdapter implements GroupModel , JpaModel<GroupEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getSubGroups() {
|
public Stream<GroupModel> getSubGroupsStream() {
|
||||||
TypedQuery<String> query = em.createNamedQuery("getGroupIdsByParent", String.class);
|
TypedQuery<String> query = em.createNamedQuery("getGroupIdsByParent", String.class);
|
||||||
query.setParameter("parent", group.getId());
|
query.setParameter("parent", group.getId());
|
||||||
List<String> ids = query.getResultList();
|
return closing(query.getResultStream().map(realm::getGroupById).filter(Objects::nonNull));
|
||||||
Set<GroupModel> set = new HashSet<>();
|
|
||||||
for (String id : ids) {
|
|
||||||
GroupModel subGroup = realm.getGroupById(id);
|
|
||||||
if (subGroup == null) continue;
|
|
||||||
set.add(subGroup);
|
|
||||||
}
|
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -203,14 +200,10 @@ public class GroupAdapter implements GroupModel , JpaModel<GroupEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getAttribute(String name) {
|
public Stream<String> getAttributeStream(String name) {
|
||||||
List<String> result = new ArrayList<>();
|
return group.getAttributes().stream()
|
||||||
for (GroupAttributeEntity attr : group.getAttributes()) {
|
.filter(attr -> Objects.equals(attr.getName(), name))
|
||||||
if (attr.getName().equals(name)) {
|
.map(GroupAttributeEntity::getValue);
|
||||||
result.add(attr.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -171,9 +171,7 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
|
||||||
|
|
||||||
removeRoles(adapter);
|
removeRoles(adapter);
|
||||||
|
|
||||||
for (GroupModel group : adapter.getGroups()) {
|
adapter.getGroupsStream().forEach(adapter::removeGroup);
|
||||||
session.groups().removeGroup(adapter, group);
|
|
||||||
}
|
|
||||||
|
|
||||||
num = em.createNamedQuery("removeClientInitialAccessByRealm")
|
num = em.createNamedQuery("removeClientInitialAccessByRealm")
|
||||||
.setParameter("realm", realm).executeUpdate();
|
.setParameter("realm", realm).executeUpdate();
|
||||||
|
@ -420,14 +418,12 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroups(RealmModel realm) {
|
public Stream<GroupModel> getGroupsStream(RealmModel realm) {
|
||||||
RealmEntity ref = em.getReference(RealmEntity.class, realm.getId());
|
RealmEntity ref = em.getReference(RealmEntity.class, realm.getId());
|
||||||
|
|
||||||
return ref.getGroups().stream()
|
return ref.getGroups().stream()
|
||||||
.map(g -> session.groups().getGroupById(realm, g.getId()))
|
.map(g -> session.groups().getGroupById(realm, g.getId()))
|
||||||
.sorted(Comparator.comparing(GroupModel::getName))
|
.sorted(Comparator.comparing(GroupModel::getName));
|
||||||
.collect(Collectors.collectingAndThen(
|
|
||||||
Collectors.toList(), Collections::unmodifiableList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -454,11 +450,11 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getGroupsCountByNameContaining(RealmModel realm, String search) {
|
public Long getGroupsCountByNameContaining(RealmModel realm, String search) {
|
||||||
return (long) searchForGroupByName(realm, search, null, null).size();
|
return searchForGroupByNameStream(realm, search, null, null).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
public Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
||||||
TypedQuery<GroupEntity> query = em.createNamedQuery("groupsInRole", GroupEntity.class);
|
TypedQuery<GroupEntity> query = em.createNamedQuery("groupsInRole", GroupEntity.class);
|
||||||
query.setParameter("roleId", role.getId());
|
query.setParameter("roleId", role.getId());
|
||||||
if (firstResult != -1) {
|
if (firstResult != -1) {
|
||||||
|
@ -467,44 +463,33 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
|
||||||
if (maxResults != -1) {
|
if (maxResults != -1) {
|
||||||
query.setMaxResults(maxResults);
|
query.setMaxResults(maxResults);
|
||||||
}
|
}
|
||||||
List<GroupEntity> results = query.getResultList();
|
Stream<GroupEntity> results = query.getResultStream();
|
||||||
|
|
||||||
return results.stream()
|
return closing(results
|
||||||
.map(g -> new GroupAdapter(realm, em, g))
|
.map(g -> (GroupModel) new GroupAdapter(realm, em, g))
|
||||||
.sorted(Comparator.comparing(GroupModel::getName))
|
.sorted(Comparator.comparing(GroupModel::getName)));
|
||||||
.collect(Collectors.collectingAndThen(
|
|
||||||
Collectors.toList(), Collections::unmodifiableList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm) {
|
||||||
RealmEntity ref = em.getReference(RealmEntity.class, realm.getId());
|
RealmEntity ref = em.getReference(RealmEntity.class, realm.getId());
|
||||||
|
|
||||||
return ref.getGroups().stream()
|
return ref.getGroups().stream()
|
||||||
.filter(g -> GroupEntity.TOP_PARENT_ID.equals(g.getParentId()))
|
.filter(g -> GroupEntity.TOP_PARENT_ID.equals(g.getParentId()))
|
||||||
.map(g -> session.groups().getGroupById(realm, g.getId()))
|
.map(g -> session.groups().getGroupById(realm, g.getId()))
|
||||||
.sorted(Comparator.comparing(GroupModel::getName))
|
.sorted(Comparator.comparing(GroupModel::getName));
|
||||||
.collect(Collectors.collectingAndThen(
|
|
||||||
Collectors.toList(), Collections::unmodifiableList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups(RealmModel realm, Integer first, Integer max) {
|
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer first, Integer max) {
|
||||||
List<String> groupIds = em.createNamedQuery("getTopLevelGroupIds", String.class)
|
Stream<String> groupIds = em.createNamedQuery("getTopLevelGroupIds", String.class)
|
||||||
.setParameter("realm", realm.getId())
|
.setParameter("realm", realm.getId())
|
||||||
.setParameter("parent", GroupEntity.TOP_PARENT_ID)
|
.setParameter("parent", GroupEntity.TOP_PARENT_ID)
|
||||||
.setFirstResult(first)
|
.setFirstResult(first)
|
||||||
.setMaxResults(max)
|
.setMaxResults(max)
|
||||||
.getResultList();
|
.getResultStream();
|
||||||
List<GroupModel> list = new ArrayList<>();
|
|
||||||
if(Objects.nonNull(groupIds) && !groupIds.isEmpty()) {
|
return closing(groupIds.map(realm::getGroupById));
|
||||||
for (String id : groupIds) {
|
|
||||||
GroupModel group = getGroupById(realm, id);
|
|
||||||
list.add(group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no need to sort, it's sorted at database level
|
|
||||||
return Collections.unmodifiableList(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -534,9 +519,8 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
|
||||||
session.users().preRemove(realm, group);
|
session.users().preRemove(realm, group);
|
||||||
|
|
||||||
realm.removeDefaultGroup(group);
|
realm.removeDefaultGroup(group);
|
||||||
for (GroupModel subGroup : group.getSubGroups()) {
|
group.getSubGroupsStream().forEach(realm::removeGroup);
|
||||||
session.groups().removeGroup(realm, subGroup);
|
|
||||||
}
|
|
||||||
GroupEntity groupEntity = em.find(GroupEntity.class, group.getId(), LockModeType.PESSIMISTIC_WRITE);
|
GroupEntity groupEntity = em.find(GroupEntity.class, group.getId(), LockModeType.PESSIMISTIC_WRITE);
|
||||||
if ((groupEntity == null) || (!groupEntity.getRealm().equals(realm.getId()))) {
|
if ((groupEntity == null) || (!groupEntity.getRealm().equals(realm.getId()))) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -745,28 +729,22 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer first, Integer max) {
|
public Stream<GroupModel> searchForGroupByNameStream(RealmModel realm, String search, Integer first, Integer max) {
|
||||||
TypedQuery<String> query = em.createNamedQuery("getGroupIdsByNameContaining", String.class)
|
TypedQuery<String> query = em.createNamedQuery("getGroupIdsByNameContaining", String.class)
|
||||||
.setParameter("realm", realm.getId())
|
.setParameter("realm", realm.getId())
|
||||||
.setParameter("search", search);
|
.setParameter("search", search);
|
||||||
if(Objects.nonNull(first) && Objects.nonNull(max)) {
|
if(Objects.nonNull(first) && Objects.nonNull(max)) {
|
||||||
query= query.setFirstResult(first).setMaxResults(max);
|
query= query.setFirstResult(first).setMaxResults(max);
|
||||||
}
|
}
|
||||||
List<String> groups = query.getResultList();
|
Stream<String> groups = query.getResultStream();
|
||||||
if (Objects.isNull(groups)) return Collections.EMPTY_LIST;
|
|
||||||
List<GroupModel> list = new ArrayList<>();
|
return closing(groups.map(id -> {
|
||||||
for (String id : groups) {
|
|
||||||
GroupModel groupById = session.groups().getGroupById(realm, id);
|
GroupModel groupById = session.groups().getGroupById(realm, id);
|
||||||
while(Objects.nonNull(groupById.getParentId())) {
|
while (Objects.nonNull(groupById.getParentId())) {
|
||||||
groupById = session.groups().getGroupById(realm, groupById.getParentId());
|
groupById = session.groups().getGroupById(realm, groupById.getParentId());
|
||||||
}
|
}
|
||||||
if(!list.contains(groupById)) {
|
return groupById;
|
||||||
list.add(groupById);
|
}).sorted(Comparator.comparing(GroupModel::getName)).distinct());
|
||||||
}
|
|
||||||
}
|
|
||||||
list.sort(Comparator.comparing(GroupModel::getName));
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -50,7 +50,6 @@ import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.client.ClientStorageProvider;
|
import org.keycloak.storage.client.ClientStorageProvider;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.Query;
|
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
@ -110,9 +109,8 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
|
||||||
if (addDefaultRoles) {
|
if (addDefaultRoles) {
|
||||||
DefaultRoles.addDefaultRoles(realm, userModel);
|
DefaultRoles.addDefaultRoles(realm, userModel);
|
||||||
|
|
||||||
for (GroupModel g : realm.getDefaultGroups()) {
|
// No need to check if user has group as it's new user
|
||||||
userModel.joinGroupImpl(g); // No need to check if user has group as it's new user
|
realm.getDefaultGroupsStream().forEach(userModel::joinGroupImpl);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addDefaultRequiredActions){
|
if (addDefaultRequiredActions){
|
||||||
|
|
|
@ -792,14 +792,10 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getDefaultGroups() {
|
public Stream<GroupModel> getDefaultGroupsStream() {
|
||||||
Collection<GroupEntity> entities = realm.getDefaultGroups();
|
Collection<GroupEntity> entities = realm.getDefaultGroups();
|
||||||
if (entities == null || entities.isEmpty()) return Collections.EMPTY_LIST;
|
if (entities == null || entities.isEmpty()) return Stream.empty();
|
||||||
List<GroupModel> defaultGroups = new LinkedList<>();
|
return entities.stream().map(GroupEntity::getId).map(this::getGroupById);
|
||||||
for (GroupEntity entity : entities) {
|
|
||||||
defaultGroups.add(session.groups().getGroupById(this, entity.getId()));
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(defaultGroups);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2036,8 +2032,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
return session.groups().getGroups(this);
|
return session.groups().getGroupsStream(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2051,18 +2047,18 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups() {
|
public Stream<GroupModel> getTopLevelGroupsStream() {
|
||||||
return session.groups().getTopLevelGroups(this);
|
return session.groups().getTopLevelGroupsStream(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> getTopLevelGroups(Integer first, Integer max) {
|
public Stream<GroupModel> getTopLevelGroupsStream(Integer first, Integer max) {
|
||||||
return session.groups().getTopLevelGroups(this, first, max);
|
return session.groups().getTopLevelGroupsStream(this, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupModel> searchForGroupByName(String search, Integer first, Integer max) {
|
public Stream<GroupModel> searchForGroupByNameStream(String search, Integer first, Integer max) {
|
||||||
return session.groups().searchForGroupByName(this, search, first, max);
|
return session.groups().searchForGroupByNameStream(this, search, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -43,11 +43,9 @@ import javax.persistence.criteria.Join;
|
||||||
import javax.persistence.criteria.Predicate;
|
import javax.persistence.criteria.Predicate;
|
||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -55,6 +53,8 @@ import java.util.Objects;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
|
||||||
|
import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -401,22 +401,18 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
|
||||||
return em.createQuery(queryBuilder);
|
return em.createQuery(queryBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<GroupModel> getGroupModels(Collection<String> groupIds) {
|
private Stream<GroupModel> getGroupModels(Stream<String> groupIds) {
|
||||||
Set<GroupModel> groups = new LinkedHashSet<>();
|
return groupIds.map(realm::getGroupById);
|
||||||
for (String id : groupIds) {
|
|
||||||
groups.add(realm.getGroupById(id));
|
|
||||||
}
|
|
||||||
return groups;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
return getGroupModels(createGetGroupsQuery(null, null, null).getResultList());
|
return closing(getGroupModels(createGetGroupsQuery(null, null, null).getResultStream()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups(String search, int first, int max) {
|
public Stream<GroupModel> getGroupsStream(String search, int first, int max) {
|
||||||
return getGroupModels(createGetGroupsQuery(search, first, max).getResultList());
|
return closing(getGroupModels(createGetGroupsQuery(search, first, max).getResultStream()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -463,8 +459,7 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMemberOf(GroupModel group) {
|
public boolean isMemberOf(GroupModel group) {
|
||||||
Set<GroupModel> roles = getGroups();
|
return RoleUtils.isMember(getGroupsStream(), group);
|
||||||
return RoleUtils.isMember(roles, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TypedQuery<UserGroupMembershipEntity> getUserGroupMappingQuery(GroupModel group) {
|
protected TypedQuery<UserGroupMembershipEntity> getUserGroupMappingQuery(GroupModel group) {
|
||||||
|
@ -479,7 +474,7 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
|
||||||
public boolean hasRole(RoleModel role) {
|
public boolean hasRole(RoleModel role) {
|
||||||
Set<RoleModel> roles = getRoleMappings();
|
Set<RoleModel> roles = getRoleMappings();
|
||||||
return RoleUtils.hasRole(roles, role)
|
return RoleUtils.hasRole(roles, role)
|
||||||
|| RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
|| RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TypedQuery<UserRoleMappingEntity> getUserRoleMappingEntityTypedQuery(RoleModel role) {
|
protected TypedQuery<UserRoleMappingEntity> getUserRoleMappingEntityTypedQuery(RoleModel role) {
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserConsentModel;
|
import org.keycloak.models.UserConsentModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.jpa.JpaUserCredentialStore;
|
import org.keycloak.models.jpa.JpaUserCredentialStore;
|
||||||
import org.keycloak.models.jpa.entities.CredentialEntity;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.storage.StorageId;
|
import org.keycloak.storage.StorageId;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
@ -61,10 +60,12 @@ import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
|
||||||
|
import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -439,17 +440,10 @@ public class JpaUserFederatedStorageProvider implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups(RealmModel realm, String userId) {
|
public Stream<GroupModel> getGroupsStream(RealmModel realm, String userId) {
|
||||||
Set<GroupModel> set = new HashSet<>();
|
|
||||||
TypedQuery<FederatedUserGroupMembershipEntity> query = em.createNamedQuery("feduserGroupMembership", FederatedUserGroupMembershipEntity.class);
|
TypedQuery<FederatedUserGroupMembershipEntity> query = em.createNamedQuery("feduserGroupMembership", FederatedUserGroupMembershipEntity.class);
|
||||||
query.setParameter("userId", userId);
|
query.setParameter("userId", userId);
|
||||||
List<FederatedUserGroupMembershipEntity> results = query.getResultList();
|
return closing(query.getResultStream().map(FederatedUserGroupMembershipEntity::getGroupId).map(realm::getGroupById));
|
||||||
if (results.size() == 0) return set;
|
|
||||||
for (FederatedUserGroupMembershipEntity entity : results) {
|
|
||||||
GroupModel group = realm.getGroupById(entity.getGroupId());
|
|
||||||
set.add(group);
|
|
||||||
}
|
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -160,7 +160,7 @@ public class DefaultEvaluation implements Evaluation {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkParent) {
|
if (checkParent) {
|
||||||
return RoleUtils.isMember(user.getGroups(), group);
|
return RoleUtils.isMember(user.getGroupsStream(), group);
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.isMemberOf(group);
|
return user.isMemberOf(group);
|
||||||
|
@ -253,7 +253,7 @@ public class DefaultEvaluation implements Evaluation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getUserGroups(String id) {
|
public List<String> getUserGroups(String id) {
|
||||||
return getUser(id, authorizationProvider.getKeycloakSession()).getGroups().stream()
|
return getUser(id, authorizationProvider.getKeycloakSession()).getGroupsStream()
|
||||||
.map(ModelToRepresentation::buildGroupPath)
|
.map(ModelToRepresentation::buildGroupPath)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,12 @@ import java.security.cert.X509Certificate;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of helper methods, which are useful in various model implementations.
|
* Set of helper methods, which are useful in various model implementations.
|
||||||
|
@ -382,30 +386,11 @@ public final class KeycloakModelUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param name
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String resolveFirstAttribute(UserModel user, String name) {
|
|
||||||
String value = user.getFirstAttribute(name);
|
|
||||||
if (value != null) return value;
|
|
||||||
for (GroupModel group : user.getGroups()) {
|
|
||||||
value = resolveFirstAttribute(group, name);
|
|
||||||
if (value != null) return value;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> resolveAttribute(GroupModel group, String name) {
|
public static List<String> resolveAttribute(GroupModel group, String name) {
|
||||||
List<String> values = group.getAttribute(name);
|
List<String> values = group.getAttributeStream(name).collect(Collectors.toList());
|
||||||
if (values != null && !values.isEmpty()) return values;
|
if (!values.isEmpty()) return values;
|
||||||
if (group.getParentId() == null) return null;
|
if (group.getParentId() == null) return null;
|
||||||
return resolveAttribute(group.getParent(), name);
|
return resolveAttribute(group.getParent(), name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -418,21 +403,24 @@ public final class KeycloakModelUtils {
|
||||||
}
|
}
|
||||||
aggrValues.addAll(values);
|
aggrValues.addAll(values);
|
||||||
}
|
}
|
||||||
for (GroupModel group : user.getGroups()) {
|
Stream<List<String>> attributes = user.getGroupsStream()
|
||||||
values = resolveAttribute(group, name);
|
.map(group -> resolveAttribute(group, name))
|
||||||
if (values != null && !values.isEmpty()) {
|
.filter(Objects::nonNull)
|
||||||
|
.filter(attr -> !attr.isEmpty());
|
||||||
|
|
||||||
if (!aggregateAttrs) {
|
if (!aggregateAttrs) {
|
||||||
return values;
|
Optional<List<String>> first = attributes.findFirst();
|
||||||
}
|
if (first.isPresent()) return first.get();
|
||||||
aggrValues.addAll(values);
|
} else {
|
||||||
}
|
aggrValues.addAll(attributes.flatMap(Collection::stream).collect(Collectors.toSet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return aggrValues;
|
return aggrValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static GroupModel findSubGroup(String[] segments, int index, GroupModel parent) {
|
private static GroupModel findSubGroup(String[] segments, int index, GroupModel parent) {
|
||||||
for (GroupModel group : parent.getSubGroups()) {
|
return parent.getSubGroupsStream().map(group -> {
|
||||||
String groupName = group.getName();
|
String groupName = group.getName();
|
||||||
String[] pathSegments = formatPathSegments(segments, index, groupName);
|
String[] pathSegments = formatPathSegments(segments, index, groupName);
|
||||||
|
|
||||||
|
@ -444,14 +432,11 @@ public final class KeycloakModelUtils {
|
||||||
if (index + 1 < pathSegments.length) {
|
if (index + 1 < pathSegments.length) {
|
||||||
GroupModel found = findSubGroup(pathSegments, index + 1, group);
|
GroupModel found = findSubGroup(pathSegments, index + 1, group);
|
||||||
if (found != null) return found;
|
if (found != null) return found;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
}).filter(Objects::nonNull).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -504,26 +489,25 @@ public final class KeycloakModelUtils {
|
||||||
}
|
}
|
||||||
String[] split = path.split("/");
|
String[] split = path.split("/");
|
||||||
if (split.length == 0) return null;
|
if (split.length == 0) return null;
|
||||||
GroupModel found = null;
|
|
||||||
for (GroupModel group : realm.getTopLevelGroups()) {
|
return realm.getTopLevelGroupsStream().map(group -> {
|
||||||
String groupName = group.getName();
|
String groupName = group.getName();
|
||||||
String[] pathSegments = formatPathSegments(split, 0, groupName);
|
String[] pathSegments = formatPathSegments(split, 0, groupName);
|
||||||
|
|
||||||
if (groupName.equals(pathSegments[0])) {
|
if (groupName.equals(pathSegments[0])) {
|
||||||
if (pathSegments.length == 1) {
|
if (pathSegments.length == 1) {
|
||||||
found = group;
|
return group;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (pathSegments.length > 1) {
|
if (pathSegments.length > 1) {
|
||||||
found = findSubGroup(pathSegments, 1, group);
|
GroupModel subGroup = findSubGroup(pathSegments, 1, group);
|
||||||
if (found != null) break;
|
if (subGroup != null) return subGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
return found;
|
}).filter(Objects::nonNull).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<RoleModel> getClientScopeMappings(ClientModel client, ScopeContainerModel container) {
|
public static Set<RoleModel> getClientScopeMappings(ClientModel client, ScopeContainerModel container) {
|
||||||
|
|
|
@ -46,9 +46,9 @@ import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -139,63 +139,40 @@ public class ModelToRepresentation {
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GroupRepresentation> searchForGroupByName(RealmModel realm, boolean full, String search, Integer first, Integer max) {
|
public static Stream<GroupRepresentation> searchForGroupByName(RealmModel realm, boolean full, String search, Integer first, Integer max) {
|
||||||
List<GroupRepresentation> result = new LinkedList<>();
|
return realm.searchForGroupByNameStream(search, first, max)
|
||||||
List<GroupModel> groups = realm.searchForGroupByName(search, first, max);
|
.map(g -> toGroupHierarchy(g, full));
|
||||||
if (Objects.isNull(groups)) return result;
|
|
||||||
for (GroupModel group : groups) {
|
|
||||||
GroupRepresentation rep = toGroupHierarchy(group, full);
|
|
||||||
result.add(rep);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GroupRepresentation> searchForGroupByName(UserModel user, boolean full, String search, Integer first, Integer max) {
|
public static Stream<GroupRepresentation> searchForGroupByName(UserModel user, boolean full, String search, Integer first, Integer max) {
|
||||||
return user.getGroups(search, first, max).stream()
|
return user.getGroupsStream(search, first, max)
|
||||||
.map(group -> toRepresentation(group, full))
|
.map(group -> toRepresentation(group, full));
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GroupRepresentation> toGroupHierarchy(RealmModel realm, boolean full, Integer first, Integer max) {
|
public static Stream<GroupRepresentation> toGroupHierarchy(RealmModel realm, boolean full, Integer first, Integer max) {
|
||||||
List<GroupRepresentation> hierarchy = new LinkedList<>();
|
return realm.getTopLevelGroupsStream(first, max)
|
||||||
List<GroupModel> groups = realm.getTopLevelGroups(first, max);
|
.map(g -> toGroupHierarchy(g, full));
|
||||||
if (Objects.isNull(groups)) return hierarchy;
|
|
||||||
for (GroupModel group : groups) {
|
|
||||||
GroupRepresentation rep = toGroupHierarchy(group, full);
|
|
||||||
hierarchy.add(rep);
|
|
||||||
}
|
|
||||||
return hierarchy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GroupRepresentation> toGroupHierarchy(UserModel user, boolean full, Integer first, Integer max) {
|
public static Stream<GroupRepresentation> toGroupHierarchy(UserModel user, boolean full, Integer first, Integer max) {
|
||||||
return user.getGroups(first, max).stream()
|
return user.getGroupsStream(null, first, max)
|
||||||
.map(group -> toRepresentation(group, full))
|
.map(group -> toRepresentation(group, full));
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GroupRepresentation> toGroupHierarchy(RealmModel realm, boolean full) {
|
public static Stream<GroupRepresentation> toGroupHierarchy(RealmModel realm, boolean full) {
|
||||||
List<GroupRepresentation> hierarchy = new LinkedList<>();
|
return realm.getTopLevelGroupsStream()
|
||||||
List<GroupModel> groups = realm.getTopLevelGroups();
|
.map(g -> toGroupHierarchy(g, full));
|
||||||
if (Objects.isNull(groups)) return hierarchy;
|
|
||||||
for (GroupModel group : groups) {
|
|
||||||
GroupRepresentation rep = toGroupHierarchy(group, full);
|
|
||||||
hierarchy.add(rep);
|
|
||||||
}
|
|
||||||
return hierarchy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GroupRepresentation> toGroupHierarchy(UserModel user, boolean full) {
|
public static Stream<GroupRepresentation> toGroupHierarchy(UserModel user, boolean full) {
|
||||||
return user.getGroups().stream()
|
return user.getGroupsStream()
|
||||||
.map(group -> toRepresentation(group, full))
|
.map(group -> toRepresentation(group, full));
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GroupRepresentation toGroupHierarchy(GroupModel group, boolean full) {
|
public static GroupRepresentation toGroupHierarchy(GroupModel group, boolean full) {
|
||||||
GroupRepresentation rep = toRepresentation(group, full);
|
GroupRepresentation rep = toRepresentation(group, full);
|
||||||
List<GroupRepresentation> subGroups = new LinkedList<>();
|
List<GroupRepresentation> subGroups = group.getSubGroupsStream()
|
||||||
for (GroupModel subGroup : group.getSubGroups()) {
|
.map(subGroup -> toGroupHierarchy(subGroup, full)).collect(Collectors.toList());
|
||||||
subGroups.add(toGroupHierarchy(subGroup, full));
|
|
||||||
}
|
|
||||||
rep.setSubGroups(subGroups);
|
rep.setSubGroups(subGroups);
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
@ -437,13 +414,10 @@ public class ModelToRepresentation {
|
||||||
List<String> roleStrings = new ArrayList<>(defaultRoles);
|
List<String> roleStrings = new ArrayList<>(defaultRoles);
|
||||||
rep.setDefaultRoles(roleStrings);
|
rep.setDefaultRoles(roleStrings);
|
||||||
}
|
}
|
||||||
List<GroupModel> defaultGroups = realm.getDefaultGroups();
|
List<String> defaultGroups = realm.getDefaultGroupsStream()
|
||||||
|
.map(ModelToRepresentation::buildGroupPath).collect(Collectors.toList());
|
||||||
if (!defaultGroups.isEmpty()) {
|
if (!defaultGroups.isEmpty()) {
|
||||||
List<String> groupPaths = new LinkedList<>();
|
rep.setDefaultGroups(defaultGroups);
|
||||||
for (GroupModel group : defaultGroups) {
|
|
||||||
groupPaths.add(ModelToRepresentation.buildGroupPath(group));
|
|
||||||
}
|
|
||||||
rep.setDefaultGroups(groupPaths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
|
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
|
||||||
|
@ -502,8 +476,7 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void exportGroups(RealmModel realm, RealmRepresentation rep) {
|
public static void exportGroups(RealmModel realm, RealmRepresentation rep) {
|
||||||
List<GroupRepresentation> groups = toGroupHierarchy(realm, true);
|
rep.setGroups(toGroupHierarchy(realm, true).collect(Collectors.toList()));
|
||||||
rep.setGroups(groups);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void exportAuthenticationFlows(RealmModel realm, RealmRepresentation rep) {
|
public static void exportAuthenticationFlows(RealmModel realm, RealmRepresentation rep) {
|
||||||
|
|
|
@ -30,12 +30,12 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.RoleUtils;
|
import org.keycloak.models.utils.RoleUtils;
|
||||||
import org.keycloak.storage.ReadOnlyException;
|
import org.keycloak.storage.ReadOnlyException;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -79,10 +79,7 @@ public class InMemoryUserAdapter extends UserModelDefaultMethods {
|
||||||
public void addDefaults() {
|
public void addDefaults() {
|
||||||
DefaultRoles.addDefaultRoles(realm, this);
|
DefaultRoles.addDefaultRoles(realm, this);
|
||||||
|
|
||||||
for (GroupModel g : realm.getDefaultGroups()) {
|
realm.getDefaultGroupsStream().forEach(this::joinGroup);
|
||||||
joinGroup(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReadonly(boolean flag) {
|
public void setReadonly(boolean flag) {
|
||||||
|
@ -213,13 +210,8 @@ public class InMemoryUserAdapter extends UserModelDefaultMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
if (groupIds.isEmpty()) return new HashSet<>();
|
return groupIds.stream().map(realm::getGroupById);
|
||||||
Set<GroupModel> groups = new HashSet<>();
|
|
||||||
for (String id : groupIds) {
|
|
||||||
groups.add(realm.getGroupById(id));
|
|
||||||
}
|
|
||||||
return groups;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -240,8 +232,7 @@ public class InMemoryUserAdapter extends UserModelDefaultMethods {
|
||||||
public boolean isMemberOf(GroupModel group) {
|
public boolean isMemberOf(GroupModel group) {
|
||||||
if (groupIds == null) return false;
|
if (groupIds == null) return false;
|
||||||
if (groupIds.contains(group.getId())) return true;
|
if (groupIds.contains(group.getId())) return true;
|
||||||
Set<GroupModel> groups = getGroups();
|
return RoleUtils.isMember(getGroupsStream(), group);
|
||||||
return RoleUtils.isMember(groups, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -299,7 +290,7 @@ public class InMemoryUserAdapter extends UserModelDefaultMethods {
|
||||||
public boolean hasRole(RoleModel role) {
|
public boolean hasRole(RoleModel role) {
|
||||||
Set<RoleModel> roles = getRoleMappings();
|
Set<RoleModel> roles = getRoleMappings();
|
||||||
return RoleUtils.hasRole(roles, role)
|
return RoleUtils.hasRole(roles, role)
|
||||||
|| RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
|| RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,6 +22,8 @@ import org.keycloak.provider.ProviderEvent;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -61,13 +63,24 @@ public interface GroupModel extends RoleMapperModel {
|
||||||
* @param name
|
* @param name
|
||||||
* @return list of all attribute values or empty list if there are not any values. Never return null
|
* @return list of all attribute values or empty list if there are not any values. Never return null
|
||||||
*/
|
*/
|
||||||
List<String> getAttribute(String name);
|
@Deprecated
|
||||||
|
default List<String> getAttribute(String name) {
|
||||||
|
return getAttributeStream(name).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<String> getAttributeStream(String name);
|
||||||
|
|
||||||
Map<String, List<String>> getAttributes();
|
Map<String, List<String>> getAttributes();
|
||||||
|
|
||||||
GroupModel getParent();
|
GroupModel getParent();
|
||||||
String getParentId();
|
String getParentId();
|
||||||
Set<GroupModel> getSubGroups();
|
|
||||||
|
@Deprecated
|
||||||
|
default Set<GroupModel> getSubGroups() {
|
||||||
|
return getSubGroupsStream().collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getSubGroupsStream();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You must also call addChild on the parent group, addChild on RealmModel if there is no parent group
|
* You must also call addChild on the parent group, addChild on RealmModel if there is no parent group
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.keycloak.models;
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -55,8 +57,20 @@ public interface GroupProvider extends Provider {
|
||||||
*
|
*
|
||||||
* @param realm Realm.
|
* @param realm Realm.
|
||||||
* @return List of groups in the Realm.
|
* @return List of groups in the Realm.
|
||||||
|
* @deprecated Use {@link #getGroupsStream(RealmModel)} getGroupsStream} instead.
|
||||||
*/
|
*/
|
||||||
List<GroupModel> getGroups(RealmModel realm);
|
@Deprecated
|
||||||
|
default List<GroupModel> getGroups(RealmModel realm) {
|
||||||
|
return getGroupsStream(realm).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns groups for the given realm.
|
||||||
|
*
|
||||||
|
* @param realm Realm.
|
||||||
|
* @return Stream of groups in the Realm.
|
||||||
|
*/
|
||||||
|
Stream<GroupModel> getGroupsStream(RealmModel realm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a number of groups/top level groups (i.e. groups without parent group) for the given realm.
|
* Returns a number of groups/top level groups (i.e. groups without parent group) for the given realm.
|
||||||
|
@ -84,16 +98,43 @@ public interface GroupProvider extends Provider {
|
||||||
* @param firstResult First result to return. Ignored if negative.
|
* @param firstResult First result to return. Ignored if negative.
|
||||||
* @param maxResults Maximum number of results to return. Ignored if negative.
|
* @param maxResults Maximum number of results to return. Ignored if negative.
|
||||||
* @return List of groups with the given role.
|
* @return List of groups with the given role.
|
||||||
|
* @deprecated Use {@link #getGroupsByRoleStream(RealmModel, RoleModel, int, int)} getGroupsByRoleStream} instead.
|
||||||
*/
|
*/
|
||||||
List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults);
|
@Deprecated
|
||||||
|
default List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
||||||
|
return getGroupsByRoleStream(realm, role, firstResult, maxResults).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns groups with the given role in the given realm.
|
||||||
|
*
|
||||||
|
* @param realm Realm.
|
||||||
|
* @param role Role.
|
||||||
|
* @param firstResult First result to return. Ignored if negative.
|
||||||
|
* @param maxResults Maximum number of results to return. Ignored if negative.
|
||||||
|
* @return Stream of groups with the given role.
|
||||||
|
*/
|
||||||
|
Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, int firstResult, int maxResults);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all top level groups (i.e. groups without parent group) for the given realm.
|
* Returns all top level groups (i.e. groups without parent group) for the given realm.
|
||||||
*
|
*
|
||||||
* @param realm Realm.
|
* @param realm Realm.
|
||||||
* @return List of all top level groups in the realm.
|
* @return List of all top level groups in the realm.
|
||||||
|
* @deprecated Use {@link #getTopLevelGroupsStream(RealmModel)} getTopLevelGroupsStream} instead.
|
||||||
*/
|
*/
|
||||||
List<GroupModel> getTopLevelGroups(RealmModel realm);
|
@Deprecated
|
||||||
|
default List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
||||||
|
return getTopLevelGroupsStream(realm).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all top level groups (i.e. groups without parent group) for the given realm.
|
||||||
|
*
|
||||||
|
* @param realm Realm.
|
||||||
|
* @return Stream of all top level groups in the realm.
|
||||||
|
*/
|
||||||
|
Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns top level groups (i.e. groups without parent group) for the given realm.
|
* Returns top level groups (i.e. groups without parent group) for the given realm.
|
||||||
|
@ -102,8 +143,22 @@ public interface GroupProvider extends Provider {
|
||||||
* @param firstResult First result to return.
|
* @param firstResult First result to return.
|
||||||
* @param maxResults Maximum number of results to return.
|
* @param maxResults Maximum number of results to return.
|
||||||
* @return List of top level groups in the realm.
|
* @return List of top level groups in the realm.
|
||||||
|
* @deprecated Use {@link #getTopLevelGroupsStream(RealmModel, Integer, Integer)} getTopLevelGroupsStream} instead.
|
||||||
*/
|
*/
|
||||||
List<GroupModel> getTopLevelGroups(RealmModel realm, Integer firstResult, Integer maxResults);
|
@Deprecated
|
||||||
|
default List<GroupModel> getTopLevelGroups(RealmModel realm, Integer firstResult, Integer maxResults) {
|
||||||
|
return getTopLevelGroupsStream(realm, firstResult, maxResults).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns top level groups (i.e. groups without parent group) for the given realm.
|
||||||
|
*
|
||||||
|
* @param realm Realm.
|
||||||
|
* @param firstResult First result to return.
|
||||||
|
* @param maxResults Maximum number of results to return.
|
||||||
|
* @return Stream of top level groups in the realm.
|
||||||
|
*/
|
||||||
|
Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer firstResult, Integer maxResults);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns groups with the given string in name for the given realm.
|
* Returns groups with the given string in name for the given realm.
|
||||||
|
@ -113,8 +168,23 @@ public interface GroupProvider extends Provider {
|
||||||
* @param firstResult First result to return. Ignored if {@code null}.
|
* @param firstResult First result to return. Ignored if {@code null}.
|
||||||
* @param maxResults Maximum number of results to return. Ignored if {@code null}.
|
* @param maxResults Maximum number of results to return. Ignored if {@code null}.
|
||||||
* @return List of groups with the given string in name.
|
* @return List of groups with the given string in name.
|
||||||
|
* @deprecated Use {@link #searchForGroupByNameStream(RealmModel, String, Integer, Integer)} searchForGroupByNameStream} instead.
|
||||||
*/
|
*/
|
||||||
List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer firstResult, Integer maxResults);
|
@Deprecated
|
||||||
|
default List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
|
||||||
|
return searchForGroupByNameStream(realm, search, firstResult, maxResults).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns groups with the given string in name for the given realm.
|
||||||
|
*
|
||||||
|
* @param realm Realm.
|
||||||
|
* @param search Searched string.
|
||||||
|
* @param firstResult First result to return. Ignored if {@code null}.
|
||||||
|
* @param maxResults Maximum number of results to return. Ignored if {@code null}.
|
||||||
|
* @return Stream of groups with the given string in name.
|
||||||
|
*/
|
||||||
|
Stream<GroupModel> searchForGroupByNameStream(RealmModel realm, String search, Integer firstResult, Integer maxResults);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new group with the given name in the given realm.
|
* Creates a new group with the given name in the given realm.
|
||||||
|
|
|
@ -282,7 +282,12 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
|
|
||||||
RoleModel getRoleById(String id);
|
RoleModel getRoleById(String id);
|
||||||
|
|
||||||
List<GroupModel> getDefaultGroups();
|
@Deprecated
|
||||||
|
default List<GroupModel> getDefaultGroups() {
|
||||||
|
return getDefaultGroupsStream().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getDefaultGroupsStream();
|
||||||
|
|
||||||
void addDefaultGroup(GroupModel group);
|
void addDefaultGroup(GroupModel group);
|
||||||
|
|
||||||
|
@ -535,12 +540,38 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
GroupModel createGroup(String id, String name, GroupModel toParent);
|
GroupModel createGroup(String id, String name, GroupModel toParent);
|
||||||
|
|
||||||
GroupModel getGroupById(String id);
|
GroupModel getGroupById(String id);
|
||||||
List<GroupModel> getGroups();
|
|
||||||
|
@Deprecated
|
||||||
|
default List<GroupModel> getGroups() {
|
||||||
|
return getGroupsStream().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getGroupsStream();
|
||||||
|
|
||||||
Long getGroupsCount(Boolean onlyTopGroups);
|
Long getGroupsCount(Boolean onlyTopGroups);
|
||||||
Long getGroupsCountByNameContaining(String search);
|
Long getGroupsCountByNameContaining(String search);
|
||||||
List<GroupModel> getTopLevelGroups();
|
|
||||||
List<GroupModel> getTopLevelGroups(Integer first, Integer max);
|
@Deprecated
|
||||||
List<GroupModel> searchForGroupByName(String search, Integer first, Integer max);
|
default List<GroupModel> getTopLevelGroups() {
|
||||||
|
return getTopLevelGroupsStream().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getTopLevelGroupsStream();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
default List<GroupModel> getTopLevelGroups(Integer first, Integer max) {
|
||||||
|
return getTopLevelGroupsStream(first, max).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getTopLevelGroupsStream(Integer first, Integer max);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
default List<GroupModel> searchForGroupByName(String search, Integer first, Integer max) {
|
||||||
|
return searchForGroupByNameStream(search, first, max).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> searchForGroupByNameStream(String search, Integer first, Integer max);
|
||||||
|
|
||||||
boolean removeGroup(GroupModel group);
|
boolean removeGroup(GroupModel group);
|
||||||
void moveGroup(GroupModel group, GroupModel toParent);
|
void moveGroup(GroupModel group, GroupModel toParent);
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,9 @@ public interface RealmProvider extends Provider /* TODO: Remove in future versio
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
@Override
|
@Override
|
||||||
List<GroupModel> getGroups(RealmModel realm);
|
default List<GroupModel> getGroups(RealmModel realm) {
|
||||||
|
return getGroupsStream(realm).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
|
@ -234,22 +236,30 @@ public interface RealmProvider extends Provider /* TODO: Remove in future versio
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
@Override
|
@Override
|
||||||
List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults);
|
default List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
|
||||||
|
return getGroupsByRoleStream(realm, role, firstResult, maxResults).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
@Override
|
@Override
|
||||||
List<GroupModel> getTopLevelGroups(RealmModel realm);
|
default List<GroupModel> getTopLevelGroups(RealmModel realm) {
|
||||||
|
return getTopLevelGroupsStream(realm).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
@Override
|
@Override
|
||||||
List<GroupModel> getTopLevelGroups(RealmModel realm, Integer first, Integer max);
|
default List<GroupModel> getTopLevelGroups(RealmModel realm, Integer first, Integer max) {
|
||||||
|
return getTopLevelGroupsStream(realm, first, max).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
@Override
|
@Override
|
||||||
List searchForGroupByName(RealmModel realm, String search, Integer first, Integer max);
|
default List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer first, Integer max) {
|
||||||
|
return searchForGroupByNameStream(realm, search, first, max).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
* @deprecated Use the corresponding method from {@link GroupProvider}. */
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -118,18 +119,29 @@ public interface UserModel extends RoleMapperModel {
|
||||||
|
|
||||||
void setEmailVerified(boolean verified);
|
void setEmailVerified(boolean verified);
|
||||||
|
|
||||||
Set<GroupModel> getGroups();
|
@Deprecated
|
||||||
|
default Set<GroupModel> getGroups() {
|
||||||
default Set<GroupModel> getGroups(int first, int max) {
|
return getGroupsStream().collect(Collectors.toSet());
|
||||||
return getGroups(null, first, max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getGroupsStream();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
default Set<GroupModel> getGroups(int first, int max) {
|
||||||
|
return getGroupsStream(null, first, max).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
default Set<GroupModel> getGroups(String search, int first, int max) {
|
default Set<GroupModel> getGroups(String search, int first, int max) {
|
||||||
return getGroups().stream()
|
return getGroupsStream(search, first, max)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
default Stream<GroupModel> getGroupsStream(String search, int first, int max) {
|
||||||
|
return getGroupsStream()
|
||||||
.filter(group -> search == null || group.getName().toLowerCase().contains(search.toLowerCase()))
|
.filter(group -> search == null || group.getName().toLowerCase().contains(search.toLowerCase()))
|
||||||
.skip(first)
|
.skip(first)
|
||||||
.limit(max)
|
.limit(max);
|
||||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default long getGroupsCount() {
|
default long getGroupsCount() {
|
||||||
|
@ -138,11 +150,11 @@ public interface UserModel extends RoleMapperModel {
|
||||||
|
|
||||||
default long getGroupsCountByNameContaining(String search) {
|
default long getGroupsCountByNameContaining(String search) {
|
||||||
if (search == null) {
|
if (search == null) {
|
||||||
return getGroups().size();
|
return getGroupsStream().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
String s = search.toLowerCase();
|
String s = search.toLowerCase();
|
||||||
return getGroups().stream().filter(group -> group.getName().toLowerCase().contains(s)).count();
|
return getGroupsStream().filter(group -> group.getName().toLowerCase().contains(s)).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
void joinGroup(GroupModel group);
|
void joinGroup(GroupModel group);
|
||||||
|
|
|
@ -39,13 +39,15 @@ public class RoleUtils {
|
||||||
* @param groups
|
* @param groups
|
||||||
* @param targetGroup
|
* @param targetGroup
|
||||||
* @return true if targetGroup is in groups (directly or indirectly via parent child relationship)
|
* @return true if targetGroup is in groups (directly or indirectly via parent child relationship)
|
||||||
|
* @deprecated Use {@link #isMember(Stream, GroupModel)} isMember(Stream, GroupModel)} instead.
|
||||||
*/
|
*/
|
||||||
public static boolean isMember(Set<GroupModel> groups, GroupModel targetGroup) {
|
public static boolean isMember(Set<GroupModel> groups, GroupModel targetGroup) {
|
||||||
|
// collecting to set to keep "Breadth First Search" like functionality
|
||||||
if (groups.contains(targetGroup)) return true;
|
if (groups.contains(targetGroup)) return true;
|
||||||
|
|
||||||
for (GroupModel mapping : groups) {
|
for (GroupModel mapping : groups) {
|
||||||
GroupModel child = mapping;
|
GroupModel child = mapping;
|
||||||
while(child.getParent() != null) {
|
while (child.getParent() != null) {
|
||||||
if (child.getParent().equals(targetGroup)) return true;
|
if (child.getParent().equals(targetGroup)) return true;
|
||||||
child = child.getParent();
|
child = child.getParent();
|
||||||
}
|
}
|
||||||
|
@ -53,6 +55,27 @@ public class RoleUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param groups
|
||||||
|
* @param targetGroup
|
||||||
|
* @return true if targetGroup is in groups (directly or indirectly via parent child relationship)
|
||||||
|
*/
|
||||||
|
public static boolean isMember(Stream<GroupModel> groups, GroupModel targetGroup) {
|
||||||
|
// collecting to set to keep "Breadth First Search" like functionality
|
||||||
|
Set<GroupModel> groupsSet = groups.collect(Collectors.toSet());
|
||||||
|
if (groupsSet.contains(targetGroup)) return true;
|
||||||
|
|
||||||
|
return groupsSet.stream().anyMatch(mapping -> {
|
||||||
|
GroupModel child = mapping;
|
||||||
|
while (child.getParent() != null) {
|
||||||
|
if (child.getParent().equals(targetGroup)) return true;
|
||||||
|
child = child.getParent();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param roles
|
* @param roles
|
||||||
* @param targetRole
|
* @param targetRole
|
||||||
|
@ -94,6 +117,7 @@ public class RoleUtils {
|
||||||
* @param targetRole
|
* @param targetRole
|
||||||
* @param checkParentGroup When {@code true}, also parent group is recursively checked for role
|
* @param checkParentGroup When {@code true}, also parent group is recursively checked for role
|
||||||
* @return true if targetRole is in roles (directly or indirectly via composite role)
|
* @return true if targetRole is in roles (directly or indirectly via composite role)
|
||||||
|
* @deprecated Use {@link #hasRoleFromGroup(Stream, RoleModel, boolean)} hasRoleFromGroup(Stream, RoleModel, boolean)} instead.
|
||||||
*/
|
*/
|
||||||
public static boolean hasRoleFromGroup(Iterable<GroupModel> groups, RoleModel targetRole, boolean checkParentGroup) {
|
public static boolean hasRoleFromGroup(Iterable<GroupModel> groups, RoleModel targetRole, boolean checkParentGroup) {
|
||||||
if (groups == null) {
|
if (groups == null) {
|
||||||
|
@ -104,6 +128,22 @@ public class RoleUtils {
|
||||||
.anyMatch(group -> hasRoleFromGroup(group, targetRole, checkParentGroup));
|
.anyMatch(group -> hasRoleFromGroup(group, targetRole, checkParentGroup));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the {@code targetRole} is contained in any of the {@code groups} or their parents
|
||||||
|
* (if requested)
|
||||||
|
* @param groups
|
||||||
|
* @param targetRole
|
||||||
|
* @param checkParentGroup When {@code true}, also parent group is recursively checked for role
|
||||||
|
* @return true if targetRole is in roles (directly or indirectly via composite role)
|
||||||
|
*/
|
||||||
|
public static boolean hasRoleFromGroup(Stream<GroupModel> groups, RoleModel targetRole, boolean checkParentGroup) {
|
||||||
|
if (groups == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups.anyMatch(group -> hasRoleFromGroup(group, targetRole, checkParentGroup));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively expands composite roles into their composite.
|
* Recursively expands composite roles into their composite.
|
||||||
* @param role
|
* @param role
|
||||||
|
@ -156,10 +196,7 @@ public class RoleUtils {
|
||||||
*/
|
*/
|
||||||
public static Set<RoleModel> getDeepUserRoleMappings(UserModel user) {
|
public static Set<RoleModel> getDeepUserRoleMappings(UserModel user) {
|
||||||
Set<RoleModel> roleMappings = new HashSet<>(user.getRoleMappings());
|
Set<RoleModel> roleMappings = new HashSet<>(user.getRoleMappings());
|
||||||
for (GroupModel group : user.getGroups()) {
|
user.getGroupsStream().forEach(group -> addGroupRoles(group, roleMappings));
|
||||||
addGroupRoles(group, roleMappings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return expandCompositeRoles(roleMappings);
|
return expandCompositeRoles(roleMappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.models.UserModel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegation pattern. Used to proxy UserModel implementations.
|
* Delegation pattern. Used to proxy UserModel implementations.
|
||||||
|
@ -224,8 +225,8 @@ public class UserModelDelegate implements UserModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
return delegate.getGroups();
|
return delegate.getGroupsStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,6 +36,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This abstract class provides implementations for everything but getUsername(). getId() returns a default value
|
* This abstract class provides implementations for everything but getUsername(). getId() returns a default value
|
||||||
|
@ -94,8 +95,8 @@ public abstract class AbstractUserAdapter extends UserModelDefaultMethods {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected Set<GroupModel> getGroupsInternal() {
|
protected Stream<GroupModel> getGroupsInternal() {
|
||||||
return Collections.emptySet();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,11 +111,10 @@ public abstract class AbstractUserAdapter extends UserModelDefaultMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
Set<GroupModel> set = new HashSet<>();
|
Stream<GroupModel> groups = getGroupsInternal();
|
||||||
if (appendDefaultGroups()) set.addAll(realm.getDefaultGroups());
|
if (appendDefaultGroups()) groups = Stream.concat(groups, realm.getDefaultGroupsStream());
|
||||||
set.addAll(getGroupsInternal());
|
return groups;
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,8 +131,7 @@ public abstract class AbstractUserAdapter extends UserModelDefaultMethods {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMemberOf(GroupModel group) {
|
public boolean isMemberOf(GroupModel group) {
|
||||||
Set<GroupModel> roles = getGroups();
|
return RoleUtils.isMember(getGroupsStream(), group);
|
||||||
return RoleUtils.isMember(roles, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -170,7 +169,7 @@ public abstract class AbstractUserAdapter extends UserModelDefaultMethods {
|
||||||
public boolean hasRole(RoleModel role) {
|
public boolean hasRole(RoleModel role) {
|
||||||
Set<RoleModel> roles = getRoleMappings();
|
Set<RoleModel> roles = getRoleMappings();
|
||||||
return RoleUtils.hasRole(roles, role)
|
return RoleUtils.hasRole(roles, role)
|
||||||
|| RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
|| RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,6 +36,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assumes everything is managed by federated storage except for username. getId() returns a default value
|
* Assumes everything is managed by federated storage except for username. getId() returns a default value
|
||||||
|
@ -103,8 +104,8 @@ public abstract class AbstractUserAdapterFederatedStorage extends UserModelDefau
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected Set<GroupModel> getGroupsInternal() {
|
protected Stream<GroupModel> getGroupsInternal() {
|
||||||
return Collections.emptySet();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,11 +128,10 @@ public abstract class AbstractUserAdapterFederatedStorage extends UserModelDefau
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups() {
|
public Stream<GroupModel> getGroupsStream() {
|
||||||
Set<GroupModel> set = new HashSet<>(getFederatedStorage().getGroups(realm, this.getId()));
|
Stream<GroupModel> groups = getFederatedStorage().getGroupsStream(realm, this.getId());
|
||||||
if (appendDefaultGroups()) set.addAll(realm.getDefaultGroups());
|
if (appendDefaultGroups()) groups = Stream.concat(groups, realm.getDefaultGroupsStream());
|
||||||
set.addAll(getGroupsInternal());
|
return Stream.concat(groups, getGroupsInternal());
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -148,8 +148,7 @@ public abstract class AbstractUserAdapterFederatedStorage extends UserModelDefau
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMemberOf(GroupModel group) {
|
public boolean isMemberOf(GroupModel group) {
|
||||||
Set<GroupModel> roles = getGroups();
|
return RoleUtils.isMember(getGroupsStream(), group);
|
||||||
return RoleUtils.isMember(roles, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -203,7 +202,7 @@ public abstract class AbstractUserAdapterFederatedStorage extends UserModelDefau
|
||||||
public boolean hasRole(RoleModel role) {
|
public boolean hasRole(RoleModel role) {
|
||||||
Set<RoleModel> roles = getRoleMappings();
|
Set<RoleModel> roles = getRoleMappings();
|
||||||
return RoleUtils.hasRole(roles, role)
|
return RoleUtils.hasRole(roles, role)
|
||||||
|| RoleUtils.hasRoleFromGroup(getGroups(), role, true);
|
|| RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,13 +21,21 @@ import org.keycloak.models.RealmModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface UserGroupMembershipFederatedStorage {
|
public interface UserGroupMembershipFederatedStorage {
|
||||||
Set<GroupModel> getGroups(RealmModel realm, String userId);
|
@Deprecated
|
||||||
|
default Set<GroupModel> getGroups(RealmModel realm, String userId) {
|
||||||
|
return getGroupsStream(realm, userId).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<GroupModel> getGroupsStream(RealmModel realm, String userId);
|
||||||
|
|
||||||
void joinGroup(RealmModel realm, String userId, GroupModel group);
|
void joinGroup(RealmModel realm, String userId, GroupModel group);
|
||||||
void leaveGroup(RealmModel realm, String userId, GroupModel group);
|
void leaveGroup(RealmModel realm, String userId, GroupModel group);
|
||||||
List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max);
|
List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional capability interface implemented by UserStorageProviders.
|
* Optional capability interface implemented by UserStorageProviders.
|
||||||
|
@ -128,14 +127,9 @@ public interface UserQueryProvider {
|
||||||
* @return number of users that are in at least one of the groups
|
* @return number of users that are in at least one of the groups
|
||||||
*/
|
*/
|
||||||
static int countUsersInGroups(List<UserModel> users, Set<String> groupIds) {
|
static int countUsersInGroups(List<UserModel> users, Set<String> groupIds) {
|
||||||
return (int) users.stream().filter(u -> {
|
return (int) users.stream()
|
||||||
for (GroupModel group : u.getGroups()) {
|
.filter(u -> u.getGroupsStream().anyMatch(group -> groupIds.contains(group.getId())))
|
||||||
if (groupIds.contains(group.getId())) {
|
.count();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -567,10 +567,7 @@ public class ExportUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.isGroupsAndRolesIncluded()) {
|
if (options.isGroupsAndRolesIncluded()) {
|
||||||
List<String> groups = new LinkedList<>();
|
List<String> groups = user.getGroupsStream().map(ModelToRepresentation::buildGroupPath).collect(Collectors.toList());
|
||||||
for (GroupModel group : user.getGroups()) {
|
|
||||||
groups.add(ModelToRepresentation.buildGroupPath(group));
|
|
||||||
}
|
|
||||||
userRep.setGroups(groups);
|
userRep.setGroups(groups);
|
||||||
}
|
}
|
||||||
return userRep;
|
return userRep;
|
||||||
|
@ -737,10 +734,8 @@ public class ExportUtils {
|
||||||
userRep.setNotBefore(notBefore);
|
userRep.setNotBefore(notBefore);
|
||||||
|
|
||||||
if (options.isGroupsAndRolesIncluded()) {
|
if (options.isGroupsAndRolesIncluded()) {
|
||||||
List<String> groups = new LinkedList<>();
|
List<String> groups = session.userFederatedStorage().getGroupsStream(realm, id)
|
||||||
for (GroupModel group : session.userFederatedStorage().getGroups(realm, id)) {
|
.map(ModelToRepresentation::buildGroupPath).collect(Collectors.toList());
|
||||||
groups.add(ModelToRepresentation.buildGroupPath(group));
|
|
||||||
}
|
|
||||||
userRep.setGroups(groups);
|
userRep.setGroups(groups);
|
||||||
}
|
}
|
||||||
return userRep;
|
return userRep;
|
||||||
|
|
|
@ -27,9 +27,10 @@ import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps user group membership
|
* Maps user group membership
|
||||||
|
@ -93,16 +94,10 @@ public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements
|
||||||
* @param userSession
|
* @param userSession
|
||||||
*/
|
*/
|
||||||
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
|
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
|
||||||
|
Function<GroupModel, String> toGroupRepresentation = useFullPath(mappingModel) ?
|
||||||
|
ModelToRepresentation::buildGroupPath : GroupModel::getName;
|
||||||
|
List<String> membership = userSession.getUser().getGroupsStream().map(toGroupRepresentation).collect(Collectors.toList());
|
||||||
|
|
||||||
List<String> membership = new LinkedList<>();
|
|
||||||
boolean fullPath = useFullPath(mappingModel);
|
|
||||||
for (GroupModel group : userSession.getUser().getGroups()) {
|
|
||||||
if (fullPath) {
|
|
||||||
membership.add(ModelToRepresentation.buildGroupPath(group));
|
|
||||||
} else {
|
|
||||||
membership.add(group.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String protocolClaim = mappingModel.getConfig().get(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
String protocolClaim = mappingModel.getConfig().get(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||||
|
|
||||||
token.getOtherClaims().put(protocolClaim, membership);
|
token.getOtherClaims().put(protocolClaim, membership);
|
||||||
|
|
|
@ -20,7 +20,6 @@ package org.keycloak.protocol.saml.mappers;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
@ -32,6 +31,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -122,27 +122,27 @@ public class GroupMembershipMapper extends AbstractSAMLProtocolMapper implements
|
||||||
boolean singleAttribute = Boolean.parseBoolean(single);
|
boolean singleAttribute = Boolean.parseBoolean(single);
|
||||||
|
|
||||||
boolean fullPath = useFullPath(mappingModel);
|
boolean fullPath = useFullPath(mappingModel);
|
||||||
AttributeType singleAttributeType = null;
|
final AtomicReference<AttributeType> singleAttributeType = new AtomicReference<>(null);
|
||||||
for (GroupModel group : userSession.getUser().getGroups()) {
|
userSession.getUser().getGroupsStream().forEach(group -> {
|
||||||
String groupName;
|
String groupName;
|
||||||
if (fullPath) {
|
if (fullPath) {
|
||||||
groupName = ModelToRepresentation.buildGroupPath(group);
|
groupName = ModelToRepresentation.buildGroupPath(group);
|
||||||
} else {
|
} else {
|
||||||
groupName = group.getName();
|
groupName = group.getName();
|
||||||
}
|
}
|
||||||
AttributeType attributeType = null;
|
AttributeType attributeType;
|
||||||
if (singleAttribute) {
|
if (singleAttribute) {
|
||||||
if (singleAttributeType == null) {
|
if (singleAttributeType.get() == null) {
|
||||||
singleAttributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
singleAttributeType.set(AttributeStatementHelper.createAttributeType(mappingModel));
|
||||||
attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType));
|
attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType.get()));
|
||||||
}
|
}
|
||||||
attributeType = singleAttributeType;
|
attributeType = singleAttributeType.get();
|
||||||
} else {
|
} else {
|
||||||
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
||||||
attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
||||||
}
|
}
|
||||||
attributeType.addAttributeValue(groupName);
|
attributeType.addAttributeValue(groupName);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProtocolMapperModel create(String name, String samlAttributeName, String nameFormat, String friendlyName, boolean singleAttribute) {
|
public static ProtocolMapperModel create(String name, String samlAttributeName, String nameFormat, String friendlyName, boolean singleAttribute) {
|
||||||
|
|
|
@ -52,6 +52,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @resource Groups
|
* @resource Groups
|
||||||
|
@ -101,12 +103,11 @@ public class GroupResource {
|
||||||
public Response updateGroup(GroupRepresentation rep) {
|
public Response updateGroup(GroupRepresentation rep) {
|
||||||
this.auth.groups().requireManage(group);
|
this.auth.groups().requireManage(group);
|
||||||
|
|
||||||
for (GroupModel sibling: siblings()) {
|
boolean exists = siblings().filter(s -> !Objects.equals(s.getId(), group.getId()))
|
||||||
if (Objects.equals(sibling.getId(), group.getId())) continue;
|
.anyMatch(s -> Objects.equals(s.getName(), rep.getName()));
|
||||||
if (sibling.getName().equals(rep.getName())) {
|
if (exists) {
|
||||||
return ErrorResponse.exists("Sibling group named '" + rep.getName() + "' already exists.");
|
return ErrorResponse.exists("Sibling group named '" + rep.getName() + "' already exists.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
updateGroup(rep, group);
|
updateGroup(rep, group);
|
||||||
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success();
|
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(rep).success();
|
||||||
|
@ -114,11 +115,11 @@ public class GroupResource {
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<GroupModel> siblings() {
|
private Stream<GroupModel> siblings() {
|
||||||
if (group.getParentId() == null) {
|
if (group.getParentId() == null) {
|
||||||
return realm.getTopLevelGroups();
|
return realm.getTopLevelGroupsStream();
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList(group.getParent().getSubGroups());
|
return group.getParent().getSubGroupsStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,11 +146,9 @@ public class GroupResource {
|
||||||
public Response addChild(GroupRepresentation rep) {
|
public Response addChild(GroupRepresentation rep) {
|
||||||
this.auth.groups().requireManage(group);
|
this.auth.groups().requireManage(group);
|
||||||
|
|
||||||
for (GroupModel group : group.getSubGroups()) {
|
if (group.getSubGroupsStream().map(GroupModel::getName).anyMatch(Predicate.isEqual(rep.getName()))) {
|
||||||
if (group.getName().equals(rep.getName())) {
|
|
||||||
return ErrorResponse.exists("Parent already contains subgroup named '" + rep.getName() + "'");
|
return ErrorResponse.exists("Parent already contains subgroup named '" + rep.getName() + "'");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Response.ResponseBuilder builder = Response.status(204);
|
Response.ResponseBuilder builder = Response.status(204);
|
||||||
GroupModel child = null;
|
GroupModel child = null;
|
||||||
|
|
|
@ -42,9 +42,9 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @resource Groups
|
* @resource Groups
|
||||||
|
@ -73,23 +73,19 @@ public class GroupsResource {
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public List<GroupRepresentation> getGroups(@QueryParam("search") String search,
|
public Stream<GroupRepresentation> getGroups(@QueryParam("search") String search,
|
||||||
@QueryParam("first") Integer firstResult,
|
@QueryParam("first") Integer firstResult,
|
||||||
@QueryParam("max") Integer maxResults,
|
@QueryParam("max") Integer maxResults,
|
||||||
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
|
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
|
||||||
auth.groups().requireList();
|
auth.groups().requireList();
|
||||||
|
|
||||||
List<GroupRepresentation> results;
|
|
||||||
|
|
||||||
if (Objects.nonNull(search)) {
|
if (Objects.nonNull(search)) {
|
||||||
results = ModelToRepresentation.searchForGroupByName(realm, !briefRepresentation, search.trim(), firstResult, maxResults);
|
return ModelToRepresentation.searchForGroupByName(realm, !briefRepresentation, search.trim(), firstResult, maxResults);
|
||||||
} else if(Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) {
|
} else if(Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) {
|
||||||
results = ModelToRepresentation.toGroupHierarchy(realm, !briefRepresentation, firstResult, maxResults);
|
return ModelToRepresentation.toGroupHierarchy(realm, !briefRepresentation, firstResult, maxResults);
|
||||||
} else {
|
} else {
|
||||||
results = ModelToRepresentation.toGroupHierarchy(realm, !briefRepresentation);
|
return ModelToRepresentation.toGroupHierarchy(realm, !briefRepresentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.ws.rs.BadRequestException;
|
import javax.ws.rs.BadRequestException;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -120,6 +121,7 @@ import org.keycloak.representations.idm.LDAPCapabilityRepresentation;
|
||||||
import org.keycloak.utils.ReservedCharValidator;
|
import org.keycloak.utils.ReservedCharValidator;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import org.keycloak.utils.ServicesUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base resource class for the admin REST api of one realm
|
* Base resource class for the admin REST api of one realm
|
||||||
|
@ -1045,14 +1047,10 @@ public class RealmAdminResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("default-groups")
|
@Path("default-groups")
|
||||||
public List<GroupRepresentation> getDefaultGroups() {
|
public Stream<GroupRepresentation> getDefaultGroups() {
|
||||||
auth.realm().requireViewRealm();
|
auth.realm().requireViewRealm();
|
||||||
|
|
||||||
List<GroupRepresentation> defaults = new LinkedList<>();
|
return realm.getDefaultGroupsStream().map(ServicesUtils::groupToBriefRepresentation);
|
||||||
for (GroupModel group : realm.getDefaultGroups()) {
|
|
||||||
defaults.add(ModelToRepresentation.toRepresentation(group, false));
|
|
||||||
}
|
|
||||||
return defaults;
|
|
||||||
}
|
}
|
||||||
@PUT
|
@PUT
|
||||||
@NoCache
|
@NoCache
|
||||||
|
|
|
@ -59,7 +59,6 @@ import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -440,7 +439,7 @@ public class RoleContainerResource extends RoleResource {
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@NoCache
|
@NoCache
|
||||||
public List<GroupRepresentation> getGroupsInRole(final @PathParam("role-name") String roleName,
|
public Stream<GroupRepresentation> getGroupsInRole(final @PathParam("role-name") String roleName,
|
||||||
@QueryParam("first") Integer firstResult,
|
@QueryParam("first") Integer firstResult,
|
||||||
@QueryParam("max") Integer maxResults,
|
@QueryParam("max") Integer maxResults,
|
||||||
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
|
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
|
||||||
|
@ -455,10 +454,8 @@ public class RoleContainerResource extends RoleResource {
|
||||||
throw new NotFoundException("Could not find role");
|
throw new NotFoundException("Could not find role");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GroupModel> groupsModel = session.groups().getGroupsByRole(realm, role, firstResult, maxResults);
|
Stream<GroupModel> groupsModel = session.groups().getGroupsByRoleStream(realm, role, firstResult, maxResults);
|
||||||
|
|
||||||
return groupsModel.stream()
|
return groupsModel.map(g -> ModelToRepresentation.toRepresentation(g, !briefRepresentation));
|
||||||
.map(g -> ModelToRepresentation.toRepresentation(g, !briefRepresentation))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID;
|
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID;
|
||||||
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME;
|
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME;
|
||||||
|
@ -868,22 +869,19 @@ public class UserResource {
|
||||||
@Path("groups")
|
@Path("groups")
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public List<GroupRepresentation> groupMembership(@QueryParam("search") String search,
|
public Stream<GroupRepresentation> groupMembership(@QueryParam("search") String search,
|
||||||
@QueryParam("first") Integer firstResult,
|
@QueryParam("first") Integer firstResult,
|
||||||
@QueryParam("max") Integer maxResults,
|
@QueryParam("max") Integer maxResults,
|
||||||
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
|
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
|
||||||
auth.users().requireView(user);
|
auth.users().requireView(user);
|
||||||
List<GroupRepresentation> results;
|
|
||||||
|
|
||||||
if (Objects.nonNull(search) && Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) {
|
if (Objects.nonNull(search) && Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) {
|
||||||
results = ModelToRepresentation.searchForGroupByName(user, !briefRepresentation, search.trim(), firstResult, maxResults);
|
return ModelToRepresentation.searchForGroupByName(user, !briefRepresentation, search.trim(), firstResult, maxResults);
|
||||||
} else if(Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) {
|
} else if(Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) {
|
||||||
results = ModelToRepresentation.toGroupHierarchy(user, !briefRepresentation, firstResult, maxResults);
|
return ModelToRepresentation.toGroupHierarchy(user, !briefRepresentation, firstResult, maxResults);
|
||||||
} else {
|
} else {
|
||||||
results = ModelToRepresentation.toGroupHierarchy(user, !briefRepresentation);
|
return ModelToRepresentation.toGroupHierarchy(user, !briefRepresentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
|
|
@ -546,10 +546,7 @@ class UserPermissions implements UserPermissionEvaluator, UserPermissionManageme
|
||||||
|
|
||||||
private boolean evaluateHierarchy(UserModel user, Predicate<GroupModel> eval) {
|
private boolean evaluateHierarchy(UserModel user, Predicate<GroupModel> eval) {
|
||||||
Set<GroupModel> visited = new HashSet<>();
|
Set<GroupModel> visited = new HashSet<>();
|
||||||
for (GroupModel group : user.getGroups()) {
|
return user.getGroupsStream().anyMatch(group -> evaluateHierarchy(eval, group, visited));
|
||||||
if (evaluateHierarchy(eval, group, visited)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean evaluateHierarchy(Predicate<GroupModel> eval, GroupModel group, Set<GroupModel> visited) {
|
private boolean evaluateHierarchy(Predicate<GroupModel> eval, GroupModel group, Set<GroupModel> visited) {
|
||||||
|
|
|
@ -19,7 +19,10 @@ package org.keycloak.utils;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.executors.ExecutorsProvider;
|
import org.keycloak.executors.ExecutorsProvider;
|
||||||
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
import org.keycloak.representations.idm.GroupRepresentation;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
@ -53,4 +56,8 @@ public class ServicesUtils {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GroupRepresentation groupToBriefRepresentation(GroupModel g) {
|
||||||
|
return ModelToRepresentation.toRepresentation(g, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,14 +389,12 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<GroupModel> getGroups(RealmModel realm, String userId) {
|
public Stream<GroupModel> getGroupsStream(RealmModel realm, String userId) {
|
||||||
Set<String> set = userGroups.get(getUserIdInMap(realm, userId));
|
Set<String> set = userGroups.get(getUserIdInMap(realm, userId));
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
return set.stream()
|
return set.stream().map(realm::getGroupById);
|
||||||
.map(realm::getGroupById)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -150,7 +150,7 @@ public class LDAPGroupMapper2WaySyncTest extends AbstractLDAPTest {
|
||||||
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group12");
|
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group12");
|
||||||
GroupModel kcGroup2 = KeycloakModelUtils.findGroupByPath(realm, "/group2");
|
GroupModel kcGroup2 = KeycloakModelUtils.findGroupByPath(realm, "/group2");
|
||||||
|
|
||||||
Assert.assertEquals(0, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(0, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
Assert.assertEquals("group1 - description1", kcGroup1.getFirstAttribute(descriptionAttrName));
|
Assert.assertEquals("group1 - description1", kcGroup1.getFirstAttribute(descriptionAttrName));
|
||||||
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
||||||
|
@ -212,7 +212,7 @@ public class LDAPGroupMapper2WaySyncTest extends AbstractLDAPTest {
|
||||||
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group12");
|
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group12");
|
||||||
GroupModel kcGroup2 = KeycloakModelUtils.findGroupByPath(realm, "/group2");
|
GroupModel kcGroup2 = KeycloakModelUtils.findGroupByPath(realm, "/group2");
|
||||||
|
|
||||||
Assert.assertEquals(2, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(2, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
Assert.assertEquals("group1 - description1", kcGroup1.getFirstAttribute(descriptionAttrName));
|
Assert.assertEquals("group1 - description1", kcGroup1.getFirstAttribute(descriptionAttrName));
|
||||||
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
||||||
|
@ -226,9 +226,7 @@ public class LDAPGroupMapper2WaySyncTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
|
|
||||||
private static void removeAllModelGroups(RealmModel appRealm) {
|
private static void removeAllModelGroups(RealmModel appRealm) {
|
||||||
for (GroupModel group : appRealm.getTopLevelGroups()) {
|
appRealm.getTopLevelGroupsStream().forEach(appRealm::removeGroup);
|
||||||
appRealm.removeGroup(group);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testDropNonExisting(KeycloakSession session, LDAPTestContext ctx, ComponentModel mapperModel) {
|
private static void testDropNonExisting(KeycloakSession session, LDAPTestContext ctx, ComponentModel mapperModel) {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import javax.ws.rs.BadRequestException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.util.LDAPTestUtils.getGroupDescriptionLDAPAttrName;
|
import static org.keycloak.testsuite.util.LDAPTestUtils.getGroupDescriptionLDAPAttrName;
|
||||||
|
|
||||||
|
@ -105,10 +106,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
|
||||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||||
RealmModel realm = ctx.getRealm();
|
RealmModel realm = ctx.getRealm();
|
||||||
|
|
||||||
List<GroupModel> kcGroups = realm.getTopLevelGroups();
|
realm.getTopLevelGroupsStream().forEach(realm::removeGroup);
|
||||||
for (GroupModel kcGroup : kcGroups) {
|
|
||||||
realm.removeGroup(kcGroup);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +167,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
|
||||||
GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, "/group11");
|
GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, "/group11");
|
||||||
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group12");
|
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group12");
|
||||||
|
|
||||||
Assert.assertEquals(0, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(0, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
|
Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
|
||||||
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
||||||
|
@ -221,7 +219,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
|
||||||
GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group11");
|
GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group11");
|
||||||
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group12");
|
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group12");
|
||||||
|
|
||||||
Assert.assertEquals(2, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(2, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
|
Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
|
||||||
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
||||||
|
@ -272,7 +270,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
|
||||||
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, "/group1/group11"));
|
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, "/group1/group11"));
|
||||||
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, "/group1/group12"));
|
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, "/group1/group12"));
|
||||||
|
|
||||||
Assert.assertEquals(2, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(2, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
// Create some new groups in keycloak
|
// Create some new groups in keycloak
|
||||||
GroupModel model1 = realm.createGroup("model1");
|
GroupModel model1 = realm.createGroup("model1");
|
||||||
|
@ -341,7 +339,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
// Load user from LDAP to Keycloak DB
|
// Load user from LDAP to Keycloak DB
|
||||||
UserModel john = session.users().getUserByUsername("johnkeycloak", realm);
|
UserModel john = session.users().getUserByUsername("johnkeycloak", realm);
|
||||||
Set<GroupModel> johnGroups = john.getGroups();
|
Set<GroupModel> johnGroups = john.getGroupsStream().collect(Collectors.toSet());
|
||||||
|
|
||||||
// Assert just those groups, which john was memberOf exists because they were lazily created
|
// Assert just those groups, which john was memberOf exists because they were lazily created
|
||||||
GroupModel group1 = KeycloakModelUtils.findGroupByPath(realm, "/group1");
|
GroupModel group1 = KeycloakModelUtils.findGroupByPath(realm, "/group1");
|
||||||
|
|
|
@ -92,9 +92,7 @@ public class LDAPGroupMapperSyncWithGroupsPathTest extends AbstractLDAPTest {
|
||||||
RealmModel realm = ctx.getRealm();
|
RealmModel realm = ctx.getRealm();
|
||||||
|
|
||||||
GroupModel groupsPathGroup = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH);
|
GroupModel groupsPathGroup = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH);
|
||||||
for (GroupModel kcGroup : groupsPathGroup.getSubGroups()) {
|
groupsPathGroup.getSubGroupsStream().forEach(realm::removeGroup);
|
||||||
realm.removeGroup(kcGroup);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +124,7 @@ public class LDAPGroupMapperSyncWithGroupsPathTest extends AbstractLDAPTest {
|
||||||
GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11");
|
GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11");
|
||||||
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12");
|
GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12");
|
||||||
|
|
||||||
Assert.assertEquals(2, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(2, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
|
Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
|
||||||
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName));
|
||||||
|
@ -175,7 +173,7 @@ public class LDAPGroupMapperSyncWithGroupsPathTest extends AbstractLDAPTest {
|
||||||
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11"));
|
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11"));
|
||||||
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12"));
|
Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12"));
|
||||||
|
|
||||||
Assert.assertEquals(2, kcGroup1.getSubGroups().size());
|
Assert.assertEquals(2, kcGroup1.getSubGroupsStream().count());
|
||||||
|
|
||||||
// Create some new groups in keycloak
|
// Create some new groups in keycloak
|
||||||
GroupModel groupsPathGroup = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH);
|
GroupModel groupsPathGroup = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH);
|
||||||
|
|
|
@ -127,20 +127,11 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
RealmModel appRealm = ctx.getRealm();
|
RealmModel appRealm = ctx.getRealm();
|
||||||
|
|
||||||
UserModel johnDb = session.userLocalStorage().getUserByUsername("johnkeycloak", appRealm);
|
UserModel johnDb = session.userLocalStorage().getUserByUsername("johnkeycloak", appRealm);
|
||||||
Set<GroupModel> johnDbGroups = johnDb.getGroups();
|
Assert.assertEquals(2, johnDb.getGroupsStream().count());
|
||||||
Assert.assertEquals(2, johnDbGroups.size());
|
Assert.assertEquals(2, johnDb.getGroupsStream("Gr", 0, 10).count());
|
||||||
|
Assert.assertEquals(1, johnDb.getGroupsStream("Gr", 1, 10).count());
|
||||||
Set<GroupModel> johnDbGroupsWithGr = johnDb.getGroups("Gr", 0, 10);
|
Assert.assertEquals(1, johnDb.getGroupsStream("Gr", 0, 1).count());
|
||||||
Assert.assertEquals(2, johnDbGroupsWithGr.size());
|
Assert.assertEquals(1, johnDb.getGroupsStream("12", 0, 10).count());
|
||||||
|
|
||||||
Set<GroupModel> johnDbGroupsWithGr2 = johnDb.getGroups("Gr", 1, 10);
|
|
||||||
Assert.assertEquals(1, johnDbGroupsWithGr2.size());
|
|
||||||
|
|
||||||
Set<GroupModel> johnDbGroupsWithGr3 = johnDb.getGroups("Gr", 0, 1);
|
|
||||||
Assert.assertEquals(1, johnDbGroupsWithGr3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> johnDbGroupsWith12 = johnDb.getGroups("12", 0, 10);
|
|
||||||
Assert.assertEquals(1, johnDbGroupsWith12.size());
|
|
||||||
|
|
||||||
long dbGroupCount = johnDb.getGroupsCount();
|
long dbGroupCount = johnDb.getGroupsCount();
|
||||||
Assert.assertEquals(2, dbGroupCount);
|
Assert.assertEquals(2, dbGroupCount);
|
||||||
|
@ -161,7 +152,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
|
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
|
||||||
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm);
|
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm);
|
||||||
|
|
||||||
Set<GroupModel> johnGroups = john.getGroups();
|
Set<GroupModel> johnGroups = john.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertEquals(4, johnGroups.size());
|
Assert.assertEquals(4, johnGroups.size());
|
||||||
long groupCount = john.getGroupsCount();
|
long groupCount = john.getGroupsCount();
|
||||||
Assert.assertEquals(4, groupCount);
|
Assert.assertEquals(4, groupCount);
|
||||||
|
@ -171,23 +162,12 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
Assert.assertTrue(johnGroups.contains(groupTeam20162017));
|
Assert.assertTrue(johnGroups.contains(groupTeam20162017));
|
||||||
Assert.assertTrue(johnGroups.contains(groupTeamChild20182019));
|
Assert.assertTrue(johnGroups.contains(groupTeamChild20182019));
|
||||||
|
|
||||||
Set<GroupModel> johnGroupsWithGr = john.getGroups("gr", 0, 10);
|
Assert.assertEquals(2, john.getGroupsStream("gr", 0, 10).count());
|
||||||
Assert.assertEquals(2, johnGroupsWithGr.size());
|
Assert.assertEquals(1, john.getGroupsStream("gr", 1, 10).count());
|
||||||
|
Assert.assertEquals(1, john.getGroupsStream("gr", 0, 1).count());
|
||||||
Set<GroupModel> johnGroupsWithGr2 = john.getGroups("gr", 1, 10);
|
Assert.assertEquals(1, john.getGroupsStream("12", 0, 10).count());
|
||||||
Assert.assertEquals(1, johnGroupsWithGr2.size());
|
Assert.assertEquals(1, john.getGroupsStream("2017", 0, 10).count());
|
||||||
|
Assert.assertEquals(1, john.getGroupsStream("2018", 0, 10).count());
|
||||||
Set<GroupModel> johnGroupsWithGr3 = john.getGroups("gr", 0, 1);
|
|
||||||
Assert.assertEquals(1, johnGroupsWithGr3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> johnGroupsWith12 = john.getGroups("12", 0, 10);
|
|
||||||
Assert.assertEquals(1, johnGroupsWith12.size());
|
|
||||||
|
|
||||||
Set<GroupModel> johnGroupsWith2017 = john.getGroups("2017", 0, 10);
|
|
||||||
Assert.assertEquals(1, johnGroupsWith2017.size());
|
|
||||||
|
|
||||||
Set<GroupModel> johnGroupsWith2018 = john.getGroups("2018", 0, 10);
|
|
||||||
Assert.assertEquals(1, johnGroupsWith2017.size());
|
|
||||||
|
|
||||||
// 4 - Check through userProvider
|
// 4 - Check through userProvider
|
||||||
List<UserModel> group1Members = session.users().getGroupMembers(appRealm, group1, 0, 10);
|
List<UserModel> group1Members = session.users().getGroupMembers(appRealm, group1, 0, 10);
|
||||||
|
@ -217,8 +197,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
mary.leaveGroup(groupTeam20162017);
|
mary.leaveGroup(groupTeam20162017);
|
||||||
mary.leaveGroup(groupTeamChild20182019);
|
mary.leaveGroup(groupTeamChild20182019);
|
||||||
|
|
||||||
johnGroups = john.getGroups();
|
Assert.assertEquals(0, john.getGroupsStream().count());
|
||||||
Assert.assertEquals(0, johnGroups.size());
|
|
||||||
|
|
||||||
groupCount = john.getGroupsCount();
|
groupCount = john.getGroupsCount();
|
||||||
Assert.assertEquals(0, groupCount);
|
Assert.assertEquals(0, groupCount);
|
||||||
|
@ -266,7 +245,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
mary.joinGroup(group12);
|
mary.joinGroup(group12);
|
||||||
|
|
||||||
// Assert that mary has both LDAP and DB mapped groups
|
// Assert that mary has both LDAP and DB mapped groups
|
||||||
Set<GroupModel> maryGroups = mary.getGroups();
|
Set<GroupModel> maryGroups = mary.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertEquals(5, maryGroups.size());
|
Assert.assertEquals(5, maryGroups.size());
|
||||||
Assert.assertTrue(maryGroups.contains(group1));
|
Assert.assertTrue(maryGroups.contains(group1));
|
||||||
Assert.assertTrue(maryGroups.contains(group11));
|
Assert.assertTrue(maryGroups.contains(group11));
|
||||||
|
@ -275,17 +254,10 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
long groupCount = mary.getGroupsCount();
|
long groupCount = mary.getGroupsCount();
|
||||||
Assert.assertEquals(5, groupCount);
|
Assert.assertEquals(5, groupCount);
|
||||||
|
|
||||||
Set<GroupModel> maryGroupsWithGr = mary.getGroups("gr", 0, 10);
|
Assert.assertEquals(5, mary.getGroupsStream("gr", 0, 10).count());
|
||||||
Assert.assertEquals(5, maryGroupsWithGr.size());
|
Assert.assertEquals(4, mary.getGroupsStream("gr", 1, 10).count());
|
||||||
|
Assert.assertEquals(1, mary.getGroupsStream("gr", 0, 1).count());
|
||||||
Set<GroupModel> maryGroupsWithGr2 = mary.getGroups("gr", 1, 10);
|
Assert.assertEquals(2, mary.getGroupsStream("12", 0, 10).count());
|
||||||
Assert.assertEquals(4, maryGroupsWithGr2.size());
|
|
||||||
|
|
||||||
Set<GroupModel> maryGroupsWithGr3 = mary.getGroups("gr", 0, 1);
|
|
||||||
Assert.assertEquals(1, maryGroupsWithGr3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> maryGroupsWith12 = mary.getGroups("12", 0, 10);
|
|
||||||
Assert.assertEquals(2, maryGroupsWith12.size());
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
|
@ -315,7 +287,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
|
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
|
||||||
|
|
||||||
// Assert that mary has both LDAP and DB mapped groups
|
// Assert that mary has both LDAP and DB mapped groups
|
||||||
Set<GroupModel> maryGroups = mary.getGroups();
|
Set<GroupModel> maryGroups = mary.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertEquals(4, maryGroups.size());
|
Assert.assertEquals(4, maryGroups.size());
|
||||||
Assert.assertTrue(maryGroups.contains(group1));
|
Assert.assertTrue(maryGroups.contains(group1));
|
||||||
Assert.assertTrue(maryGroups.contains(group11));
|
Assert.assertTrue(maryGroups.contains(group11));
|
||||||
|
@ -324,17 +296,10 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
long groupCount = mary.getGroupsCount();
|
long groupCount = mary.getGroupsCount();
|
||||||
Assert.assertEquals(4, groupCount);
|
Assert.assertEquals(4, groupCount);
|
||||||
|
|
||||||
Set<GroupModel> maryGroupsWithGr = mary.getGroups("gr", 0, 10);
|
Assert.assertEquals(4, mary.getGroupsStream("gr", 0, 10).count());
|
||||||
Assert.assertEquals(4, maryGroupsWithGr.size());
|
Assert.assertEquals(3, mary.getGroupsStream("gr", 1, 10).count());
|
||||||
|
Assert.assertEquals(1, mary.getGroupsStream("gr", 0, 1).count());
|
||||||
Set<GroupModel> maryGroupsWithGr2 = mary.getGroups("gr", 1, 10);
|
Assert.assertEquals(1, mary.getGroupsStream("12", 0, 10).count());
|
||||||
Assert.assertEquals(3, maryGroupsWithGr2.size());
|
|
||||||
|
|
||||||
Set<GroupModel> maryGroupsWithGr3 = mary.getGroups("gr", 0, 1);
|
|
||||||
Assert.assertEquals(1, maryGroupsWithGr3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> maryGroupsWith12 = mary.getGroups("12", 0, 10);
|
|
||||||
Assert.assertEquals(1, maryGroupsWith12.size());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,22 +315,15 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
UserModel maryDB = session.userLocalStorage().getUserByUsername("marykeycloak", appRealm);
|
UserModel maryDB = session.userLocalStorage().getUserByUsername("marykeycloak", appRealm);
|
||||||
|
|
||||||
Set<GroupModel> maryDBGroups = maryDB.getGroups();
|
Set<GroupModel> maryDBGroups = maryDB.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertFalse(maryDBGroups.contains(group1));
|
Assert.assertFalse(maryDBGroups.contains(group1));
|
||||||
Assert.assertFalse(maryDBGroups.contains(group11));
|
Assert.assertFalse(maryDBGroups.contains(group11));
|
||||||
Assert.assertTrue(maryDBGroups.contains(group12));
|
Assert.assertTrue(maryDBGroups.contains(group12));
|
||||||
|
|
||||||
Set<GroupModel> maryDBGroupsWithGr = maryDB.getGroups("Gr", 0, 10);
|
Assert.assertEquals(3, maryDB.getGroupsStream("Gr", 0, 10).count());
|
||||||
Assert.assertEquals(3, maryDBGroupsWithGr.size());
|
Assert.assertEquals(2, maryDB.getGroupsStream("Gr", 1, 10).count());
|
||||||
|
Assert.assertEquals(1, maryDB.getGroupsStream("Gr", 0, 1).count());
|
||||||
Set<GroupModel> maryDBGroupsWithGr2 = maryDB.getGroups("Gr", 1, 10);
|
Assert.assertEquals(2, maryDB.getGroupsStream("12", 0, 10).count());
|
||||||
Assert.assertEquals(2, maryDBGroupsWithGr2.size());
|
|
||||||
|
|
||||||
Set<GroupModel> maryDBGroupsWithGr3 = maryDB.getGroups("Gr", 0, 1);
|
|
||||||
Assert.assertEquals(1, maryDBGroupsWithGr3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> maryDBGroupsWith12 = maryDB.getGroups("12", 0, 10);
|
|
||||||
Assert.assertEquals(2, maryDBGroupsWith12.size());
|
|
||||||
|
|
||||||
long dbGroupCount = maryDB.getGroupsCount();
|
long dbGroupCount = maryDB.getGroupsCount();
|
||||||
Assert.assertEquals(3, dbGroupCount);
|
Assert.assertEquals(3, dbGroupCount);
|
||||||
|
@ -455,23 +413,16 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
// Get user and check that he has requested groups from LDAP
|
// Get user and check that he has requested groups from LDAP
|
||||||
UserModel rob = session.users().getUserByUsername("robkeycloak", appRealm);
|
UserModel rob = session.users().getUserByUsername("robkeycloak", appRealm);
|
||||||
Set<GroupModel> robGroups = rob.getGroups();
|
Set<GroupModel> robGroups = rob.getGroupsStream().collect(Collectors.toSet());
|
||||||
|
|
||||||
Assert.assertFalse(robGroups.contains(group1));
|
Assert.assertFalse(robGroups.contains(group1));
|
||||||
Assert.assertTrue(robGroups.contains(group11));
|
Assert.assertTrue(robGroups.contains(group11));
|
||||||
Assert.assertTrue(robGroups.contains(group12));
|
Assert.assertTrue(robGroups.contains(group12));
|
||||||
|
|
||||||
Set<GroupModel> robGroupsWithGr = rob.getGroups("Gr", 0, 10);
|
Assert.assertEquals(4, rob.getGroupsStream("Gr", 0, 10).count());
|
||||||
Assert.assertEquals(4, robGroupsWithGr.size());
|
Assert.assertEquals(3, rob.getGroupsStream("Gr", 1, 10).count());
|
||||||
|
Assert.assertEquals(1, rob.getGroupsStream("Gr", 0, 1).count());
|
||||||
Set<GroupModel> robGroupsWithGr2 = rob.getGroups("Gr", 1, 10);
|
Assert.assertEquals(2, rob.getGroupsStream("12", 0, 10).count());
|
||||||
Assert.assertEquals(3, robGroupsWithGr2.size());
|
|
||||||
|
|
||||||
Set<GroupModel> robGroupsWithGr3 = rob.getGroups("Gr", 0, 1);
|
|
||||||
Assert.assertEquals(1, robGroupsWithGr3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> robGroupsWith12 = rob.getGroups("12", 0, 10);
|
|
||||||
Assert.assertEquals(2, robGroupsWith12.size());
|
|
||||||
|
|
||||||
long dbGroupCount = rob.getGroupsCount();
|
long dbGroupCount = rob.getGroupsCount();
|
||||||
Assert.assertEquals(4, dbGroupCount);
|
Assert.assertEquals(4, dbGroupCount);
|
||||||
|
@ -494,7 +445,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
ldapGroup = groupMapper.loadLDAPGroupByName("group12");
|
ldapGroup = groupMapper.loadLDAPGroupByName("group12");
|
||||||
groupMapper.deleteGroupMappingInLDAP(robLdap, ldapGroup);
|
groupMapper.deleteGroupMappingInLDAP(robLdap, ldapGroup);
|
||||||
|
|
||||||
robGroups = rob.getGroups();
|
robGroups = rob.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertTrue(robGroups.contains(group11));
|
Assert.assertTrue(robGroups.contains(group11));
|
||||||
Assert.assertTrue(robGroups.contains(group12));
|
Assert.assertTrue(robGroups.contains(group12));
|
||||||
|
|
||||||
|
@ -512,8 +463,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
// Delete group mappings through model and verifies that user doesn't have them anymore
|
// Delete group mappings through model and verifies that user doesn't have them anymore
|
||||||
rob.leaveGroup(group11);
|
rob.leaveGroup(group11);
|
||||||
rob.leaveGroup(group12);
|
rob.leaveGroup(group12);
|
||||||
robGroups = rob.getGroups();
|
Assert.assertEquals(2, rob.getGroupsStream().count());
|
||||||
Assert.assertEquals(2, robGroups.size());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +554,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
// Get user in Keycloak. Ensure that he is member of requested group
|
// Get user in Keycloak. Ensure that he is member of requested group
|
||||||
UserModel carlos = session.users().getUserByUsername("carloskeycloak", appRealm);
|
UserModel carlos = session.users().getUserByUsername("carloskeycloak", appRealm);
|
||||||
Set<GroupModel> carlosGroups = carlos.getGroups();
|
Set<GroupModel> carlosGroups = carlos.getGroupsStream().collect(Collectors.toSet());
|
||||||
|
|
||||||
GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
|
GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
|
||||||
GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
|
GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
|
||||||
|
@ -676,7 +626,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
GroupModel group32 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3/group32");
|
GroupModel group32 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3/group32");
|
||||||
GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
|
GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
|
||||||
|
|
||||||
Set<GroupModel> groups = john.getGroups();
|
Set<GroupModel> groups = john.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertTrue(groups.contains(group14));
|
Assert.assertTrue(groups.contains(group14));
|
||||||
Assert.assertFalse(groups.contains(group3));
|
Assert.assertFalse(groups.contains(group3));
|
||||||
Assert.assertTrue(groups.contains(group31));
|
Assert.assertTrue(groups.contains(group31));
|
||||||
|
@ -686,20 +636,11 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
long groupsCount = john.getGroupsCount();
|
long groupsCount = john.getGroupsCount();
|
||||||
Assert.assertEquals(4, groupsCount);
|
Assert.assertEquals(4, groupsCount);
|
||||||
|
|
||||||
Set<GroupModel> groupsWith3v1 = john.getGroups("3", 0, 10);
|
Assert.assertEquals(2, john.getGroupsStream("3", 0, 10).count());
|
||||||
Assert.assertEquals(2, groupsWith3v1.size());
|
Assert.assertEquals(1, john.getGroupsStream("3", 1, 10).count());
|
||||||
|
Assert.assertEquals(1, john.getGroupsStream("3", 1, 1).count());
|
||||||
Set<GroupModel> groupsWith3v2 = john.getGroups("3", 1, 10);
|
Assert.assertEquals(0, john.getGroupsStream("3", 1, 0).count());
|
||||||
Assert.assertEquals(1, groupsWith3v2.size());
|
Assert.assertEquals(0, john.getGroupsStream("Keycloak", 0, 10).count());
|
||||||
|
|
||||||
Set<GroupModel> groupsWith3v3 = john.getGroups("3", 1, 1);
|
|
||||||
Assert.assertEquals(1, groupsWith3v3.size());
|
|
||||||
|
|
||||||
Set<GroupModel> groupsWith3v4 = john.getGroups("3", 1, 0);
|
|
||||||
Assert.assertEquals(0, groupsWith3v4.size());
|
|
||||||
|
|
||||||
Set<GroupModel> groupsWithKeycloak = john.getGroups("Keycloak", 0, 10);
|
|
||||||
Assert.assertEquals(0, groupsWithKeycloak.size());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,7 +672,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
|
GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
|
||||||
Assert.assertNotNull(group4);
|
Assert.assertNotNull(group4);
|
||||||
|
|
||||||
Set<GroupModel> groups = david.getGroups();
|
Set<GroupModel> groups = david.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertTrue(groups.contains(defaultGroup11));
|
Assert.assertTrue(groups.contains(defaultGroup11));
|
||||||
Assert.assertTrue(groups.contains(defaultGroup12));
|
Assert.assertTrue(groups.contains(defaultGroup12));
|
||||||
Assert.assertFalse(groups.contains(group31));
|
Assert.assertFalse(groups.contains(group31));
|
||||||
|
@ -797,7 +738,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
// check all the users have the group assigned
|
// check all the users have the group assigned
|
||||||
for (int i = 0; i < membersToTest; i++) {
|
for (int i = 0; i < membersToTest; i++) {
|
||||||
UserModel kcUser = session.users().getUserByUsername(String.format("user%02d", i), appRealm);
|
UserModel kcUser = session.users().getUserByUsername(String.format("user%02d", i), appRealm);
|
||||||
Assert.assertTrue("User contains biggroup " + i, kcUser.getGroups().contains(kcBigGroup));
|
Assert.assertTrue("User contains biggroup " + i, kcUser.getGroupsStream().collect(Collectors.toSet()).contains(kcBigGroup));
|
||||||
}
|
}
|
||||||
// check the group contains all the users as member
|
// check the group contains all the users as member
|
||||||
List<UserModel> groupMembers = session.users().getGroupMembers(appRealm, kcBigGroup, 0, membersToTest);
|
List<UserModel> groupMembers = session.users().getGroupMembers(appRealm, kcBigGroup, 0, membersToTest);
|
||||||
|
@ -846,7 +787,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
|
||||||
List<UserModel> groupMembers = session.users().getGroupMembers(appRealm, kcDeleteGroup, 0, 5);
|
List<UserModel> groupMembers = session.users().getGroupMembers(appRealm, kcDeleteGroup, 0, 5);
|
||||||
Assert.assertEquals(1, groupMembers.size());
|
Assert.assertEquals(1, groupMembers.size());
|
||||||
Assert.assertEquals("marykeycloak", groupMembers.iterator().next().getUsername());
|
Assert.assertEquals("marykeycloak", groupMembers.iterator().next().getUsername());
|
||||||
Set<GroupModel> maryGroups = mary.getGroups();
|
Set<GroupModel> maryGroups = mary.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertEquals(1, maryGroups.size());
|
Assert.assertEquals(1, maryGroups.size());
|
||||||
Assert.assertEquals("deletegroup", maryGroups.iterator().next().getName());
|
Assert.assertEquals("deletegroup", maryGroups.iterator().next().getName());
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.keycloak.testsuite.util.LDAPTestUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.util.LDAPTestUtils.getGroupDescriptionLDAPAttrName;
|
import static org.keycloak.testsuite.util.LDAPTestUtils.getGroupDescriptionLDAPAttrName;
|
||||||
|
|
||||||
|
@ -162,7 +163,7 @@ public class LDAPSpecialCharsTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
// 2 - Check that group mappings are in LDAP and hence available through federation
|
// 2 - Check that group mappings are in LDAP and hence available through federation
|
||||||
|
|
||||||
Set<GroupModel> userGroups = specialUser.getGroups();
|
Set<GroupModel> userGroups = specialUser.getGroupsStream().collect(Collectors.toSet());
|
||||||
Assert.assertEquals(2, userGroups.size());
|
Assert.assertEquals(2, userGroups.size());
|
||||||
Assert.assertTrue(userGroups.contains(specialGroup));
|
Assert.assertTrue(userGroups.contains(specialGroup));
|
||||||
|
|
||||||
|
@ -182,8 +183,7 @@ public class LDAPSpecialCharsTest extends AbstractLDAPTest {
|
||||||
specialUser.leaveGroup(specialGroup);
|
specialUser.leaveGroup(specialGroup);
|
||||||
specialUser.leaveGroup(groupWithSlashes);
|
specialUser.leaveGroup(groupWithSlashes);
|
||||||
|
|
||||||
userGroups = specialUser.getGroups();
|
Assert.assertEquals(0, specialUser.getGroupsStream().count());
|
||||||
Assert.assertEquals(0, userGroups.size());
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import javax.ws.rs.NotFoundException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ public class FederatedStorageExportImportTest extends AbstractAuthTest {
|
||||||
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
||||||
Assert.assertTrue(session.userFederatedStorage().getGroups(realm, userId).contains(group));
|
Assert.assertTrue(session.userFederatedStorage().getGroupsStream(realm, userId).collect(Collectors.toSet()).contains(group));
|
||||||
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
||||||
Assert.assertEquals(1, creds.size());
|
Assert.assertEquals(1, creds.size());
|
||||||
Assert.assertTrue(FederatedStorageExportImportTest.getHashProvider(session, realm.getPasswordPolicy())
|
Assert.assertTrue(FederatedStorageExportImportTest.getHashProvider(session, realm.getPasswordPolicy())
|
||||||
|
@ -216,7 +217,7 @@ public class FederatedStorageExportImportTest extends AbstractAuthTest {
|
||||||
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
||||||
Assert.assertTrue(session.userFederatedStorage().getGroups(realm, userId).contains(group));
|
Assert.assertTrue(session.userFederatedStorage().getGroupsStream(realm, userId).collect(Collectors.toSet()).contains(group));
|
||||||
Assert.assertEquals(50, session.userFederatedStorage().getNotBeforeOfUser(realm, userId));
|
Assert.assertEquals(50, session.userFederatedStorage().getNotBeforeOfUser(realm, userId));
|
||||||
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
||||||
Assert.assertEquals(1, creds.size());
|
Assert.assertEquals(1, creds.size());
|
||||||
|
|
|
@ -44,9 +44,7 @@ public class TestCacheUtils {
|
||||||
|
|
||||||
cacheRoles(session, realm, realm);
|
cacheRoles(session, realm, realm);
|
||||||
|
|
||||||
for (GroupModel group : realm.getTopLevelGroups()) {
|
realm.getTopLevelGroupsStream().forEach(group -> cacheGroupRecursive(realm, group));
|
||||||
cacheGroupRecursive(realm, group);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ClientScopeModel clientScope : realm.getClientScopes()) {
|
for (ClientScopeModel clientScope : realm.getClientScopes()) {
|
||||||
realm.getClientScopeById(clientScope.getId());
|
realm.getClientScopeById(clientScope.getId());
|
||||||
|
@ -81,8 +79,6 @@ public class TestCacheUtils {
|
||||||
|
|
||||||
private static void cacheGroupRecursive(RealmModel realm, GroupModel group) {
|
private static void cacheGroupRecursive(RealmModel realm, GroupModel group) {
|
||||||
realm.getGroupById(group.getId());
|
realm.getGroupById(group.getId());
|
||||||
for (GroupModel sub : group.getSubGroups()) {
|
group.getSubGroupsStream().forEach(sub -> cacheGroupRecursive(realm, sub));
|
||||||
cacheGroupRecursive(realm, sub);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue