[KEYCLOAK-15200] Complement methods for accessing users with Stream variants

This commit is contained in:
Stefan Guilhen 2020-10-20 14:55:47 -03:00 committed by Hynek Mlnařík
parent 8d6577d66c
commit aa46735173
36 changed files with 998 additions and 735 deletions

View file

@ -21,12 +21,12 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
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.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.naming.AuthenticationException; import javax.naming.AuthenticationException;
@ -247,7 +247,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
try (LDAPQuery ldapQuery = LDAPUtils.createQueryForUserSearch(this, realm)) { try (LDAPQuery ldapQuery = LDAPUtils.createQueryForUserSearch(this, realm)) {
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
@ -256,24 +256,15 @@ public class LDAPStorageProvider implements UserStorageProvider,
List<LDAPObject> ldapObjects = ldapQuery.getResultList(); List<LDAPObject> ldapObjects = ldapQuery.getResultList();
if (ldapObjects == null || ldapObjects.isEmpty()) { return ldapObjects.stream().map(ldapUser -> {
return Collections.emptyList();
}
List<UserModel> searchResults = new LinkedList<>();
for (LDAPObject ldapUser : ldapObjects) {
String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig()); String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig());
UserModel localUser = session.userLocalStorage().getUserByUsername(ldapUsername, realm); UserModel localUser = session.userLocalStorage().getUserByUsername(ldapUsername, realm);
if (localUser == null) { if (localUser == null) {
UserModel imported = importUserFromLDAP(session, realm, ldapUser); return importUserFromLDAP(session, realm, ldapUser);
searchResults.add(imported);
} else { } else {
searchResults.add(proxy(realm, localUser, ldapUser, false)); return proxy(realm, localUser, ldapUser, false);
} }
} });
return searchResults;
} }
} }
@ -348,34 +339,34 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(search, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
Map<String, String> attributes = new HashMap<String, String>(); Map<String, String> attributes = new HashMap<String, String>();
attributes.put(UserModel.SEARCH,search); attributes.put(UserModel.SEARCH,search);
return searchForUser(attributes, realm, firstResult, maxResults); return searchForUserStream(attributes, realm, firstResult, maxResults);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) {
return searchForUser(params, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(params, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
String search = params.get(UserModel.SEARCH); String search = params.get(UserModel.SEARCH);
if(search!=null) { if(search!=null) {
int spaceIndex = search.lastIndexOf(' '); int spaceIndex = search.lastIndexOf(' ');
@ -393,65 +384,47 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
} }
List<UserModel> searchResults =new LinkedList<UserModel>(); Stream<LDAPObject> stream = searchLDAP(realm, params).stream()
.filter(ldapObject -> {
List<LDAPObject> ldapUsers = searchLDAP(realm, params, maxResults + firstResult); String ldapUsername = LDAPUtils.getUsername(ldapObject, this.ldapIdentityStore.getConfig());
int counter = 0; return (session.userLocalStorage().getUserByUsername(ldapUsername, realm) == null);
for (LDAPObject ldapUser : ldapUsers) { });
if (counter++ < firstResult) continue; if (firstResult > 0)
String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig()); stream = stream.skip(firstResult);
if (session.userLocalStorage().getUserByUsername(ldapUsername, realm) == null) { if (maxResults >= 0)
UserModel imported = importUserFromLDAP(session, realm, ldapUser); stream = stream.limit(maxResults);
searchResults.add(imported); return stream.map(ldapObject -> importUserFromLDAP(session, realm, ldapObject));
}
}
return searchResults;
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return getGroupMembers(realm, group, 0, Integer.MAX_VALUE - 1); return getGroupMembersStream(realm, group, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
List<ComponentModel> sortedMappers = realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName()) return realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
.sorted(ldapMappersComparator.sortAsc()) .sorted(ldapMappersComparator.sortAsc())
.collect(Collectors.toList()); .map(mapperModel ->
mapperManager.getMapper(mapperModel).getGroupMembers(realm, group, firstResult, maxResults))
for (ComponentModel mapperModel : sortedMappers) { .filter(((Predicate<List>) List::isEmpty).negate())
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); .map(List::stream)
List<UserModel> users = ldapMapper.getGroupMembers(realm, group, firstResult, maxResults); .findFirst().orElse(Stream.empty());
// Sufficient for now
if (users.size() > 0) {
return users;
}
}
return Collections.emptyList();
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
return getRoleMembers(realm, role, 0, Integer.MAX_VALUE - 1); return getRoleMembersStream(realm, role, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
List<ComponentModel> sortedMappers = realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName()) return realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
.sorted(ldapMappersComparator.sortAsc()) .sorted(ldapMappersComparator.sortAsc())
.collect(Collectors.toList()); .map(mapperModel -> mapperManager.getMapper(mapperModel).getRoleMembers(realm, role, firstResult, maxResults))
for (ComponentModel mapperModel : sortedMappers) { .filter(((Predicate<List>) List::isEmpty).negate())
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); .map(List::stream)
List<UserModel> users = ldapMapper.getRoleMembers(realm, role, firstResult, maxResults); .findFirst().orElse(Stream.empty());
// Sufficient for now
if (users.size() > 0) {
return users;
}
}
return Collections.emptyList();
} }
public List<UserModel> loadUsersByUsernames(List<String> usernames, RealmModel realm) { public List<UserModel> loadUsersByUsernames(List<String> usernames, RealmModel realm) {
@ -469,7 +442,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
return result; return result;
} }
protected List<LDAPObject> searchLDAP(RealmModel realm, Map<String, String> attributes, int maxResults) { protected List<LDAPObject> searchLDAP(RealmModel realm, Map<String, String> attributes) {
List<LDAPObject> results = new ArrayList<LDAPObject>(); List<LDAPObject> results = new ArrayList<LDAPObject>();
if (attributes.containsKey(UserModel.USERNAME)) { if (attributes.containsKey(UserModel.USERNAME)) {

View file

@ -34,6 +34,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;
/** /**
* Mapper useful for the LDAP deployments when some attribute (usually CN) is mapped to full name of user * Mapper useful for the LDAP deployments when some attribute (usually CN) is mapped to full name of user
@ -108,13 +109,13 @@ public class FullNameLDAPStorageMapper extends AbstractLDAPStorageMapper {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (UserModel.FIRST_NAME.equals(name)) { if (UserModel.FIRST_NAME.equals(name)) {
return firstName != null ? Collections.singletonList(firstName) : super.getAttribute(name); return firstName != null ? Stream.of(firstName) : super.getAttributeStream(name);
} else if (UserModel.LAST_NAME.equals(name)) { } else if (UserModel.LAST_NAME.equals(name)) {
return lastName != null ? Collections.singletonList(lastName) : super.getAttribute(name); return lastName != null ? Stream.of(lastName) : super.getAttributeStream(name);
} }
return super.getAttribute(name); return super.getAttributeStream(name);
} }
@Override @Override

View file

@ -18,8 +18,8 @@
package org.keycloak.storage.ldap.mappers; package org.keycloak.storage.ldap.mappers;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
@ -73,11 +73,11 @@ public class HardcodedAttributeMapper extends AbstractLDAPStorageMapper {
delegate = new UserModelDelegate(delegate) { delegate = new UserModelDelegate(delegate) {
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if(userModelAttrName.equals(name)){ if(userModelAttrName.equals(name)){
return Arrays.asList(attributeValue); return Stream.of(attributeValue);
} }
return super.getAttribute(name); return super.getAttributeStream(name);
} }
@Override @Override

View file

@ -37,12 +37,12 @@ import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashSet; 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;
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>
@ -338,16 +338,16 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (name.equalsIgnoreCase(userModelAttrName)) { if (name.equalsIgnoreCase(userModelAttrName)) {
Collection<String> ldapAttrValue = ldapUser.getAttributeAsSet(ldapAttrName); Collection<String> ldapAttrValue = ldapUser.getAttributeAsSet(ldapAttrName);
if (ldapAttrValue == null) { if (ldapAttrValue == null) {
return Collections.emptyList(); return Stream.empty();
} else { } else {
return new ArrayList<>(ldapAttrValue); return ldapAttrValue.stream();
} }
} else { } else {
return super.getAttribute(name); return super.getAttributeStream(name);
} }
} }

View file

@ -38,6 +38,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
/** /**
* Mapper specific to MSAD. It's able to read the userAccountControl and pwdLastSet attributes and set actions in Keycloak based on that. * Mapper specific to MSAD. It's able to read the userAccountControl and pwdLastSet attributes and set actions in Keycloak based on that.
@ -299,18 +300,14 @@ public class MSADUserAccountControlStorageMapper extends AbstractLDAPStorageMapp
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
Set<String> requiredActions = super.getRequiredActions();
if (ldapProvider.getEditMode() == UserStorageProvider.EditMode.WRITABLE) { if (ldapProvider.getEditMode() == UserStorageProvider.EditMode.WRITABLE) {
if (getPwdLastSet() == 0 || getUserAccountControl(ldapUser).has(UserAccountControl.PASSWORD_EXPIRED)) { if (getPwdLastSet() == 0 || getUserAccountControl(ldapUser).has(UserAccountControl.PASSWORD_EXPIRED)) {
requiredActions = new HashSet<>(requiredActions); return Stream.concat(super.getRequiredActionsStream(), Stream.of(RequiredAction.UPDATE_PASSWORD.toString()))
requiredActions.add(RequiredAction.UPDATE_PASSWORD.toString()); .distinct();
return requiredActions;
} }
} }
return super.getRequiredActionsStream();
return requiredActions;
} }
protected long getPwdLastSet() { protected long getPwdLastSet() {

View file

@ -38,6 +38,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
/** /**
* Mapper specific to MSAD LDS. It's able to read the msDS-UserAccountDisabled, msDS-UserPasswordExpired and pwdLastSet attributes and set actions in Keycloak based on that. * Mapper specific to MSAD LDS. It's able to read the msDS-UserAccountDisabled, msDS-UserPasswordExpired and pwdLastSet attributes and set actions in Keycloak based on that.
@ -257,17 +258,14 @@ public class MSADLDSUserAccountControlStorageMapper extends AbstractLDAPStorageM
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
Set<String> requiredActions = super.getRequiredActions(); Stream<String> requiredActions = super.getRequiredActionsStream();
if (ldapProvider.getEditMode() == UserStorageProvider.EditMode.WRITABLE) { if (ldapProvider.getEditMode() == UserStorageProvider.EditMode.WRITABLE) {
if (getPwdLastSet() == 0 || Boolean.parseBoolean(ldapUser.getAttributeAsString(LDAPConstants.MSDS_USER_PASSWORD_EXPIRED))) { if (getPwdLastSet() == 0 || Boolean.parseBoolean(ldapUser.getAttributeAsString(LDAPConstants.MSDS_USER_PASSWORD_EXPIRED))) {
requiredActions = new HashSet<>(requiredActions); return Stream.concat(requiredActions, Stream.of(RequiredAction.UPDATE_PASSWORD.toString())).distinct();
requiredActions.add(RequiredAction.UPDATE_PASSWORD.toString());
return requiredActions;
} }
} }
return requiredActions; return requiredActions;
} }

View file

@ -196,10 +196,10 @@ public class UserAdapter implements CachedUserModel {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (updated != null) return updated.getAttribute(name); if (updated != null) return updated.getAttributeStream(name);
List<String> result = cached.getAttributes(modelSupplier).get(name); List<String> result = cached.getAttributes(modelSupplier).get(name);
return (result == null) ? Collections.emptyList() : result; return (result == null) ? Stream.empty() : result.stream();
} }
@Override @Override
@ -209,9 +209,9 @@ public class UserAdapter implements CachedUserModel {
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
if (updated != null) return updated.getRequiredActions(); if (updated != null) return updated.getRequiredActionsStream();
return cached.getRequiredActions(modelSupplier); return cached.getRequiredActions(modelSupplier).stream();
} }
@Override @Override
@ -289,10 +289,9 @@ public class UserAdapter implements CachedUserModel {
@Override @Override
public boolean hasRole(RoleModel role) { public boolean hasRole(RoleModel role) {
if (updated != null) return updated.hasRole(role); if (updated != null) return updated.hasRole(role);
if (cached.getRoleMappings(modelSupplier).contains(role.getId())) return true; return cached.getRoleMappings(modelSupplier).contains(role.getId()) ||
getRoleMappingsStream().anyMatch(r -> r.hasRole(role)) ||
return getRoleMappingsStream().anyMatch(r -> r.hasRole(role)) ? RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
true : RoleUtils.hasRoleFromGroup(getGroupsStream(), role, true);
} }
@Override @Override
@ -363,8 +362,7 @@ public class UserAdapter implements CachedUserModel {
@Override @Override
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; return cached.getGroups(modelSupplier).contains(group.getId()) || RoleUtils.isMember(getGroupsStream(), group);
return RoleUtils.isMember(getGroupsStream(), group);
} }
@Override @Override

View file

@ -60,10 +60,12 @@ import org.keycloak.storage.client.ClientStorageProvider;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
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.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -452,26 +454,25 @@ public class UserCacheSession implements UserCache {
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return getDelegate().getGroupMembers(realm, group, firstResult, maxResults); return getDelegate().getGroupMembersStream(realm, group, firstResult, maxResults);
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return getDelegate().getGroupMembers(realm, group); return getDelegate().getGroupMembersStream(realm, group);
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
return getDelegate().getRoleMembers(realm, role, firstResult, maxResults); return getDelegate().getRoleMembersStream(realm, role, firstResult, maxResults);
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
return getDelegate().getRoleMembers(realm, role); return getDelegate().getRoleMembersStream(realm, role);
} }
@Override @Override
public UserModel getServiceAccount(ClientModel client) { public UserModel getServiceAccount(ClientModel client) {
// Just an attempt to find the user from cache by default serviceAccount username // Just an attempt to find the user from cache by default serviceAccount username
@ -534,12 +535,9 @@ public class UserCacheSession implements UserCache {
} }
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
return getDelegate().getUsers(realm, includeServiceAccounts); return getDelegate().getUsersStream(realm, includeServiceAccounts);
} }
@Override @Override
@ -578,64 +576,65 @@ public class UserCacheSession implements UserCache {
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {
return getDelegate().getUsers(realm, firstResult, maxResults, includeServiceAccounts); return getDelegate().getUsersStream(realm, firstResult, maxResults, includeServiceAccounts);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return getUsers(realm, false); return getUsersStream(realm, false);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return getUsers(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return getDelegate().searchForUser(search, realm); return getDelegate().searchForUserStream(search, realm);
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
return getDelegate().searchForUser(search, realm, firstResult, maxResults); return getDelegate().searchForUserStream(search, realm, firstResult, maxResults);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) {
return getDelegate().searchForUser(attributes, realm); return getDelegate().searchForUserStream(attributes, realm);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
return getDelegate().searchForUser(attributes, realm, firstResult, maxResults); return getDelegate().searchForUserStream(attributes, realm, firstResult, maxResults);
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
return getDelegate().searchForUserByUserAttribute(attrName, attrValue, realm); return getDelegate().searchForUserByUserAttributeStream(attrName, attrValue, realm);
} }
@Override @Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) {
logger.tracev("getFederatedIdentities: {0}", user.getUsername()); logger.tracev("getFederatedIdentities: {0}", user.getUsername());
String cacheKey = getFederatedIdentityLinksCacheKey(user.getId()); String cacheKey = getFederatedIdentityLinksCacheKey(user.getId());
if (realmInvalidations.contains(realm.getId()) || invalidations.contains(user.getId()) || invalidations.contains(cacheKey)) { if (realmInvalidations.contains(realm.getId()) || invalidations.contains(user.getId()) || invalidations.contains(cacheKey)) {
return getDelegate().getFederatedIdentities(user, realm); return getDelegate().getFederatedIdentitiesStream(user, realm);
} }
CachedFederatedIdentityLinks cachedLinks = cache.get(cacheKey, CachedFederatedIdentityLinks.class); CachedFederatedIdentityLinks cachedLinks = cache.get(cacheKey, CachedFederatedIdentityLinks.class);
if (cachedLinks == null) { if (cachedLinks == null) {
Long loaded = cache.getCurrentRevision(cacheKey); Long loaded = cache.getCurrentRevision(cacheKey);
Set<FederatedIdentityModel> federatedIdentities = getDelegate().getFederatedIdentities(user, realm); Set<FederatedIdentityModel> federatedIdentities = getDelegate().getFederatedIdentitiesStream(user, realm)
.collect(Collectors.toSet());
cachedLinks = new CachedFederatedIdentityLinks(loaded, cacheKey, realm, federatedIdentities); cachedLinks = new CachedFederatedIdentityLinks(loaded, cacheKey, realm, federatedIdentities);
cache.addRevisioned(cachedLinks, startupRevision); cache.addRevisioned(cachedLinks, startupRevision);
return federatedIdentities; return federatedIdentities.stream();
} else { } else {
return new HashSet<>(cachedLinks.getFederatedIdentities()); return cachedLinks.getFederatedIdentities().stream();
} }
} }
@ -708,31 +707,25 @@ public class UserCacheSession implements UserCache {
} }
@Override @Override
public List<UserConsentModel> getConsents(RealmModel realm, String userId) { public Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId) {
logger.tracev("getConsents: {0}", userId); logger.tracev("getConsents: {0}", userId);
String cacheKey = getConsentCacheKey(userId); String cacheKey = getConsentCacheKey(userId);
if (realmInvalidations.contains(realm.getId()) || invalidations.contains(userId) || invalidations.contains(cacheKey)) { if (realmInvalidations.contains(realm.getId()) || invalidations.contains(userId) || invalidations.contains(cacheKey)) {
return getDelegate().getConsents(realm, userId); return getDelegate().getConsentsStream(realm, userId);
} }
CachedUserConsents cached = cache.get(cacheKey, CachedUserConsents.class); CachedUserConsents cached = cache.get(cacheKey, CachedUserConsents.class);
if (cached == null) { if (cached == null) {
Long loaded = cache.getCurrentRevision(cacheKey); Long loaded = cache.getCurrentRevision(cacheKey);
List<UserConsentModel> consents = getDelegate().getConsents(realm, userId); List<UserConsentModel> consents = getDelegate().getConsentsStream(realm, userId).collect(Collectors.toList());
cached = new CachedUserConsents(loaded, cacheKey, realm, consents); cached = new CachedUserConsents(loaded, cacheKey, realm, consents);
cache.addRevisioned(cached, startupRevision); cache.addRevisioned(cached, startupRevision);
return consents; return consents.stream();
} else { } else {
List<UserConsentModel> result = new LinkedList<>(); return cached.getConsents().values().stream().map(cachedConsent -> toConsentModel(realm, cachedConsent))
for (CachedUserConsent cachedConsent : cached.getConsents().values()) { .filter(Objects::nonNull);
UserConsentModel consent = toConsentModel(realm, cachedConsent);
if (consent != null) {
result.add(consent);
}
}
return result;
} }
} }

View file

@ -62,7 +62,7 @@ public class CachedUser extends AbstractExtendableRevisioned implements InRealm
this.federationLink = user.getFederationLink(); this.federationLink = user.getFederationLink();
this.serviceAccountClientLink = user.getServiceAccountClientLink(); this.serviceAccountClientLink = user.getServiceAccountClientLink();
this.notBefore = notBefore; this.notBefore = notBefore;
this.requiredActions = new DefaultLazyLoader<>(UserModel::getRequiredActions, Collections::emptySet); this.requiredActions = new DefaultLazyLoader<>(userModel -> userModel.getRequiredActionsStream().collect(Collectors.toSet()), 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.getRoleMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet); this.roleMappings = new DefaultLazyLoader<>(userModel -> userModel.getRoleMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet);
this.groups = new DefaultLazyLoader<>(userModel -> userModel.getGroupsStream().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);

View file

@ -58,10 +58,25 @@ 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 javax.persistence.criteria.Subquery; import javax.persistence.criteria.Subquery;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
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 $
@ -232,17 +247,10 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
} }
@Override @Override
public List<UserConsentModel> getConsents(RealmModel realm, String userId) { public Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId) {
TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentsByUser", UserConsentEntity.class); TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentsByUser", UserConsentEntity.class);
query.setParameter("userId", userId); query.setParameter("userId", userId);
List<UserConsentEntity> results = query.getResultList(); return closing(query.getResultStream().map(entity -> toConsentModel(realm, entity)));
List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
for (UserConsentEntity entity : results) {
UserConsentModel model = toConsentModel(realm, entity);
consents.add(model);
}
return consents;
} }
@Override @Override
@ -369,7 +377,7 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
@Override @Override
public void grantToAllUsers(RealmModel realm, RoleModel role) { public void grantToAllUsers(RealmModel realm, RoleModel role) {
if (realm.equals(role.isClientRole() ? ((ClientModel)role.getContainer()).getRealm() : (RealmModel)role.getContainer())) { if (realm.equals(role.isClientRole() ? ((ClientModel)role.getContainer()).getRealm() : (RealmModel)role.getContainer())) {
int num = em.createNamedQuery("grantRoleToAllUsers") em.createNamedQuery("grantRoleToAllUsers")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("roleId", role.getId()) .setParameter("roleId", role.getId())
.executeUpdate(); .executeUpdate();
@ -378,61 +386,61 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
@Override @Override
public void preRemove(RealmModel realm) { public void preRemove(RealmModel realm) {
int num = em.createNamedQuery("deleteUserConsentClientScopesByRealm") em.createNamedQuery("deleteUserConsentClientScopesByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserConsentsByRealm") em.createNamedQuery("deleteUserConsentsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserRoleMappingsByRealm") em.createNamedQuery("deleteUserRoleMappingsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserRequiredActionsByRealm") em.createNamedQuery("deleteUserRequiredActionsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedIdentityByRealm") em.createNamedQuery("deleteFederatedIdentityByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteCredentialsByRealm") em.createNamedQuery("deleteCredentialsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserAttributesByRealm") em.createNamedQuery("deleteUserAttributesByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserGroupMembershipByRealm") em.createNamedQuery("deleteUserGroupMembershipByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUsersByRealm") em.createNamedQuery("deleteUsersByRealm")
.setParameter("realmId", realm.getId()).executeUpdate(); .setParameter("realmId", realm.getId()).executeUpdate();
} }
@Override @Override
public void removeImportedUsers(RealmModel realm, String storageProviderId) { public void removeImportedUsers(RealmModel realm, String storageProviderId) {
int num = em.createNamedQuery("deleteUserRoleMappingsByRealmAndLink") em.createNamedQuery("deleteUserRoleMappingsByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUserRequiredActionsByRealmAndLink") em.createNamedQuery("deleteUserRequiredActionsByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteFederatedIdentityByRealmAndLink") em.createNamedQuery("deleteFederatedIdentityByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteCredentialsByRealmAndLink") em.createNamedQuery("deleteCredentialsByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUserAttributesByRealmAndLink") em.createNamedQuery("deleteUserAttributesByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUserGroupMembershipsByRealmAndLink") em.createNamedQuery("deleteUserGroupMembershipsByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUserConsentClientScopesByRealmAndLink") em.createNamedQuery("deleteUserConsentClientScopesByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUserConsentsByRealmAndLink") em.createNamedQuery("deleteUserConsentsByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUsersByRealmAndLink") em.createNamedQuery("deleteUsersByRealmAndLink")
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("link", storageProviderId) .setParameter("link", storageProviderId)
.executeUpdate(); .executeUpdate();
@ -455,10 +463,10 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
public void preRemove(RealmModel realm, ClientModel client) { public void preRemove(RealmModel realm, ClientModel client) {
StorageId clientStorageId = new StorageId(client.getId()); StorageId clientStorageId = new StorageId(client.getId());
if (clientStorageId.isLocal()) { if (clientStorageId.isLocal()) {
int num = em.createNamedQuery("deleteUserConsentClientScopesByClient") em.createNamedQuery("deleteUserConsentClientScopesByClient")
.setParameter("clientId", client.getId()) .setParameter("clientId", client.getId())
.executeUpdate(); .executeUpdate();
num = em.createNamedQuery("deleteUserConsentsByClient") em.createNamedQuery("deleteUserConsentsByClient")
.setParameter("clientId", client.getId()) .setParameter("clientId", client.getId())
.executeUpdate(); .executeUpdate();
} else { } else {
@ -487,31 +495,18 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
TypedQuery<UserEntity> query = em.createNamedQuery("groupMembership", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("groupMembership", UserEntity.class);
query.setParameter("groupId", group.getId()); query.setParameter("groupId", group.getId());
List<UserEntity> results = query.getResultList(); return closing(query.getResultStream().map(entity -> new UserAdapter(session, realm, em, entity)));
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity user : results) {
users.add(new UserAdapter(session, realm, em, user));
}
return users;
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
TypedQuery<UserEntity> query = em.createNamedQuery("usersInRole", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("usersInRole", UserEntity.class);
query.setParameter("roleId", role.getId()); query.setParameter("roleId", role.getId());
List<UserEntity> results = query.getResultList(); return closing(query.getResultStream().map(entity -> new UserAdapter(session, realm, em, entity)));
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity user : results) {
users.add(new UserAdapter(session, realm, em, user));
} }
return users;
}
@Override @Override
public void preRemove(RealmModel realm, GroupModel group) { public void preRemove(RealmModel realm, GroupModel group) {
@ -590,8 +585,8 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
return getUsers(realm, -1, -1, includeServiceAccounts); return getUsersStream(realm, -1, -1, includeServiceAccounts);
} }
@Override @Override
@ -746,17 +741,17 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return getUsers(realm, false); return getUsersStream(realm, false);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return getUsers(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {
String queryName = includeServiceAccounts ? "getAllUsersByRealm" : "getAllUsersByRealmExcludeServiceAccount" ; String queryName = includeServiceAccounts ? "getAllUsersByRealm" : "getAllUsersByRealmExcludeServiceAccount" ;
TypedQuery<UserEntity> query = em.createNamedQuery(queryName, UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery(queryName, UserEntity.class);
@ -767,14 +762,11 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
if (maxResults != -1) { if (maxResults != -1) {
query.setMaxResults(maxResults); query.setMaxResults(maxResults);
} }
List<UserEntity> results = query.getResultList(); return closing(query.getResultStream().map(entity -> new UserAdapter(session, realm, em, entity)));
List<UserModel> users = new LinkedList<>();
for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
return users;
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
TypedQuery<UserEntity> query = em.createNamedQuery("groupMembership", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("groupMembership", UserEntity.class);
query.setParameter("groupId", group.getId()); query.setParameter("groupId", group.getId());
if (firstResult != -1) { if (firstResult != -1) {
@ -783,17 +775,11 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
if (maxResults != -1) { if (maxResults != -1) {
query.setMaxResults(maxResults); query.setMaxResults(maxResults);
} }
List<UserEntity> results = query.getResultList(); return closing(query.getResultStream().map(user -> new UserAdapter(session, realm, em, user)));
List<UserModel> users = new LinkedList<>();
for (UserEntity user : results) {
users.add(new UserAdapter(session, realm, em, user));
}
return users;
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
TypedQuery<UserEntity> query = em.createNamedQuery("usersInRole", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("usersInRole", UserEntity.class);
query.setParameter("roleId", role.getId()); query.setParameter("roleId", role.getId());
if (firstResult != -1) { if (firstResult != -1) {
@ -802,35 +788,29 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
if (maxResults != -1) { if (maxResults != -1) {
query.setMaxResults(maxResults); query.setMaxResults(maxResults);
} }
List<UserEntity> results = query.getResultList(); return closing(query.getResultStream().map(user -> new UserAdapter(session, realm, em, user)));
List<UserModel> users = new LinkedList<>();
for (UserEntity user : results) {
users.add(new UserAdapter(session, realm, em, user));
}
return users;
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return searchForUser(search, realm, -1, -1); return searchForUserStream(search, realm, -1, -1);
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
Map<String, String> attributes = new HashMap<>(); Map<String, String> attributes = new HashMap<>();
attributes.put(UserModel.SEARCH, search); attributes.put(UserModel.SEARCH, search);
session.setAttribute(UserModel.INCLUDE_SERVICE_ACCOUNT, false); session.setAttribute(UserModel.INCLUDE_SERVICE_ACCOUNT, false);
return searchForUser(attributes, realm, firstResult, maxResults); return searchForUserStream(attributes, realm, firstResult, maxResults);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) {
return searchForUser(attributes, realm, -1, -1); return searchForUserStream(attributes, realm, -1, -1);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<UserEntity> queryBuilder = builder.createQuery(UserEntity.class); CriteriaQuery<UserEntity> queryBuilder = builder.createQuery(UserEntity.class);
Root<UserEntity> root = queryBuilder.from(UserEntity.class); Root<UserEntity> root = queryBuilder.from(UserEntity.class);
@ -945,29 +925,18 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
query.setMaxResults(maxResults); query.setMaxResults(maxResults);
} }
List<UserModel> results = new ArrayList<>();
UserProvider users = session.users(); UserProvider users = session.users();
return closing(query.getResultStream().map(userEntity -> users.getUserById(userEntity.getId(), realm)));
for (UserEntity entity : query.getResultList()) {
results.add(users.getUserById(entity.getId(), realm));
}
return results;
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUsersByAttributeNameAndValue", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUsersByAttributeNameAndValue", UserEntity.class);
query.setParameter("name", attrName); query.setParameter("name", attrName);
query.setParameter("value", attrValue); query.setParameter("value", attrValue);
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>(); return closing(query.getResultStream().map(userEntity -> new UserAdapter(session, realm, em, userEntity)));
for (UserEntity user : results) {
users.add(new UserAdapter(session, realm, em, user));
}
return users;
} }
private FederatedIdentityEntity findFederatedIdentity(UserModel user, String identityProvider, LockModeType lockMode) { private FederatedIdentityEntity findFederatedIdentity(UserModel user, String identityProvider, LockModeType lockMode) {
@ -982,16 +951,13 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
@Override @Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) {
TypedQuery<FederatedIdentityEntity> query = em.createNamedQuery("findFederatedIdentityByUser", FederatedIdentityEntity.class); TypedQuery<FederatedIdentityEntity> query = em.createNamedQuery("findFederatedIdentityByUser", FederatedIdentityEntity.class);
UserEntity userEntity = em.getReference(UserEntity.class, user.getId()); UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
query.setParameter("user", userEntity); query.setParameter("user", userEntity);
List<FederatedIdentityEntity> results = query.getResultList();
Set<FederatedIdentityModel> set = new HashSet<FederatedIdentityModel>(); return closing(query.getResultStream().map(entity -> new FederatedIdentityModel(entity.getIdentityProvider(),
for (FederatedIdentityEntity entity : results) { entity.getUserId(), entity.getUserName(), entity.getToken())).distinct());
set.add(new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName(), entity.getToken()));
}
return set;
} }
@Override @Override

View file

@ -24,7 +24,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.GroupEntity;
import org.keycloak.models.jpa.entities.UserAttributeEntity; import org.keycloak.models.jpa.entities.UserAttributeEntity;
import org.keycloak.models.jpa.entities.UserEntity; import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.jpa.entities.UserGroupMembershipEntity; import org.keycloak.models.jpa.entities.UserGroupMembershipEntity;
@ -38,19 +37,13 @@ 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;
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.Collections;
import java.util.Comparator;
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.Set;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.persistence.LockModeType; import javax.persistence.LockModeType;
@ -238,23 +231,18 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (UserModel.FIRST_NAME.equals(name)) { if (UserModel.FIRST_NAME.equals(name)) {
return Collections.singletonList(user.getFirstName()); return Stream.of(user.getFirstName());
} else if (UserModel.LAST_NAME.equals(name)) { } else if (UserModel.LAST_NAME.equals(name)) {
return Collections.singletonList(user.getLastName()); return Stream.of(user.getLastName());
} else if (UserModel.EMAIL.equals(name)) { } else if (UserModel.EMAIL.equals(name)) {
return Collections.singletonList(user.getEmail()); return Stream.of(user.getEmail());
} else if (UserModel.USERNAME.equals(name)) { } else if (UserModel.USERNAME.equals(name)) {
return Collections.singletonList(user.getUsername()); return Stream.of(user.getUsername());
} }
List<String> result = new ArrayList<>(); return user.getAttributes().stream().filter(attribute -> Objects.equals(attribute.getName(), name)).
for (UserAttributeEntity attr : user.getAttributes()) { map(attribute -> attribute.getValue());
if (attr.getName().equals(name)) {
result.add(attr.getValue());
}
}
return result;
} }
@Override @Override
@ -271,12 +259,8 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
Set<String> result = new HashSet<>(); return user.getRequiredActions().stream().map(action -> action.getAction()).distinct();
for (UserRequiredActionEntity attr : user.getRequiredActions()) {
result.add(attr.getAction());
}
return result;
} }
@Override @Override

View file

@ -55,12 +55,11 @@ import org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.persistence.LockModeType; import javax.persistence.LockModeType;
@ -164,12 +163,12 @@ public class JpaUserFederatedStorageProvider implements
} }
@Override @Override
public List<String> getUsersByUserAttribute(RealmModel realm, String name, String value) { public Stream<String> getUsersByUserAttributeStream(RealmModel realm, String name, String value) {
TypedQuery<String> query = em.createNamedQuery("getFederatedAttributesByNameAndValue", String.class) TypedQuery<String> query = em.createNamedQuery("getFederatedAttributesByNameAndValue", String.class)
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("name", name) .setParameter("name", name)
.setParameter("value", value); .setParameter("value", value);
return query.getResultList(); return closing(query.getResultStream());
} }
@Override @Override
@ -242,16 +241,11 @@ public class JpaUserFederatedStorageProvider implements
} }
@Override @Override
public Set<FederatedIdentityModel> getFederatedIdentities(String userId, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(String userId, RealmModel realm) {
TypedQuery<BrokerLinkEntity> query = em.createNamedQuery("findBrokerLinkByUser", BrokerLinkEntity.class) TypedQuery<BrokerLinkEntity> query = em.createNamedQuery("findBrokerLinkByUser", BrokerLinkEntity.class)
.setParameter("userId", userId); .setParameter("userId", userId);
List<BrokerLinkEntity> results = query.getResultList(); return closing(query.getResultStream().map(entity -> new FederatedIdentityModel(entity.getIdentityProvider(),
Set<FederatedIdentityModel> set = new HashSet<>(); entity.getBrokerUserId(), entity.getBrokerUserName(), entity.getToken())).distinct());
for (BrokerLinkEntity entity : results) {
FederatedIdentityModel model = new FederatedIdentityModel(entity.getIdentityProvider(), entity.getBrokerUserId(), entity.getBrokerUserName(), entity.getToken());
set.add(model);
}
return set;
} }
@Override @Override
@ -300,17 +294,10 @@ public class JpaUserFederatedStorageProvider implements
} }
@Override @Override
public List<UserConsentModel> getConsents(RealmModel realm, String userId) { public Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId) {
TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentsByUser", FederatedUserConsentEntity.class); TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentsByUser", FederatedUserConsentEntity.class);
query.setParameter("userId", userId); query.setParameter("userId", userId);
List<FederatedUserConsentEntity> results = query.getResultList(); return closing(query.getResultStream().map(entity -> toConsentModel(realm, entity)));
List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
for (FederatedUserConsentEntity entity : results) {
UserConsentModel model = toConsentModel(realm, entity);
consents.add(model);
}
return consents;
} }
@Override @Override
@ -478,7 +465,7 @@ public class JpaUserFederatedStorageProvider implements
} }
@Override @Override
public List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max) { public Stream<String> getMembershipStream(RealmModel realm, GroupModel group, int firstResult, int max) {
TypedQuery<String> query = em.createNamedQuery("fedgroupMembership", String.class) TypedQuery<String> query = em.createNamedQuery("fedgroupMembership", String.class)
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId())
.setParameter("groupId", group.getId()); .setParameter("groupId", group.getId());
@ -489,28 +476,21 @@ public class JpaUserFederatedStorageProvider implements
if (max != -1) { if (max != -1) {
query.setMaxResults(max); query.setMaxResults(max);
} }
return closing(query.getResultStream());
return query.getResultList();
} }
@Override @Override
public Set<String> getRequiredActions(RealmModel realm, String userId) { public Stream<String> getRequiredActionsStream(RealmModel realm, String userId) {
Set<String> set = new HashSet<>(); return this.getRequiredActionEntitiesStream(realm, userId, LockModeType.NONE).
List<FederatedUserRequiredActionEntity> values = getRequiredActionEntities(realm, userId, LockModeType.NONE); map(FederatedUserRequiredActionEntity::getAction).distinct();
for (FederatedUserRequiredActionEntity entity : values) {
set.add(entity.getAction());
} }
return set; private Stream<FederatedUserRequiredActionEntity> getRequiredActionEntitiesStream(RealmModel realm, String userId, LockModeType lockMode) {
}
private List<FederatedUserRequiredActionEntity> getRequiredActionEntities(RealmModel realm, String userId, LockModeType lockMode) {
TypedQuery<FederatedUserRequiredActionEntity> query = em.createNamedQuery("getFederatedUserRequiredActionsByUser", FederatedUserRequiredActionEntity.class) TypedQuery<FederatedUserRequiredActionEntity> query = em.createNamedQuery("getFederatedUserRequiredActionsByUser", FederatedUserRequiredActionEntity.class)
.setParameter("userId", userId) .setParameter("userId", userId)
.setParameter("realmId", realm.getId()); .setParameter("realmId", realm.getId());
query.setLockMode(lockMode); query.setLockMode(lockMode);
return query.getResultList(); return closing(query.getResultStream());
} }
@Override @Override
@ -529,12 +509,9 @@ public class JpaUserFederatedStorageProvider implements
@Override @Override
public void removeRequiredAction(RealmModel realm, String userId, String action) { public void removeRequiredAction(RealmModel realm, String userId, String action) {
List<FederatedUserRequiredActionEntity> values = getRequiredActionEntities(realm, userId, LockModeType.PESSIMISTIC_WRITE); this.getRequiredActionEntitiesStream(realm, userId, LockModeType.PESSIMISTIC_WRITE).
for (FederatedUserRequiredActionEntity entity : values) { filter(entity -> Objects.equals(entity.getAction(), action)).collect(Collectors.toList()).forEach(em::remove);
if (action.equals(entity.getAction())) em.remove(entity);
}
em.flush(); em.flush();
} }
@Override @Override
@ -598,7 +575,7 @@ public class JpaUserFederatedStorageProvider implements
entity.setStorageProviderId(new StorageId(userId).getProviderId()); entity.setStorageProviderId(new StorageId(userId).getProviderId());
//add in linkedlist to last position //add in linkedlist to last position
List<FederatedUserCredentialEntity> credentials = getStoredCredentialEntities(userId); List<FederatedUserCredentialEntity> credentials = getStoredCredentialEntitiesStream(userId).collect(Collectors.toList());
int priority = credentials.isEmpty() ? JpaUserCredentialStore.PRIORITY_DIFFERENCE : credentials.get(credentials.size() - 1).getPriority() + JpaUserCredentialStore.PRIORITY_DIFFERENCE; int priority = credentials.isEmpty() ? JpaUserCredentialStore.PRIORITY_DIFFERENCE : credentials.get(credentials.size() - 1).getPriority() + JpaUserCredentialStore.PRIORITY_DIFFERENCE;
entity.setPriority(priority); entity.setPriority(priority);
@ -613,14 +590,8 @@ public class JpaUserFederatedStorageProvider implements
int currentPriority = entity.getPriority(); int currentPriority = entity.getPriority();
List<FederatedUserCredentialEntity> credentials = getStoredCredentialEntities(userId); this.getStoredCredentialEntitiesStream(userId).filter(credentialEntity -> credentialEntity.getPriority() > currentPriority)
.forEach(credentialEntity -> credentialEntity.setPriority(credentialEntity.getPriority() - JpaUserCredentialStore.PRIORITY_DIFFERENCE));
// Decrease priority of all credentials after our
for (FederatedUserCredentialEntity cred : credentials) {
if (cred.getPriority() > currentPriority) {
cred.setPriority(cred.getPriority() - JpaUserCredentialStore.PRIORITY_DIFFERENCE);
}
}
em.remove(entity); em.remove(entity);
return true; return true;
@ -659,32 +630,22 @@ public class JpaUserFederatedStorageProvider implements
} }
@Override @Override
public List<CredentialModel> getStoredCredentials(RealmModel realm, String userId) { public Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, String userId) {
List<FederatedUserCredentialEntity> results = getStoredCredentialEntities(userId); return this.getStoredCredentialEntitiesStream(userId).map(this::toModel);
List<CredentialModel> rtn = new LinkedList<>();
for (FederatedUserCredentialEntity entity : results) {
rtn.add(toModel(entity));
}
return rtn;
} }
private List<FederatedUserCredentialEntity> getStoredCredentialEntities(String userId) { private Stream<FederatedUserCredentialEntity> getStoredCredentialEntitiesStream(String userId) {
TypedQuery<FederatedUserCredentialEntity> query = em.createNamedQuery("federatedUserCredentialByUser", FederatedUserCredentialEntity.class) TypedQuery<FederatedUserCredentialEntity> query = em.createNamedQuery("federatedUserCredentialByUser", FederatedUserCredentialEntity.class)
.setParameter("userId", userId); .setParameter("userId", userId);
return query.getResultList(); return closing(query.getResultStream());
} }
@Override @Override
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, String userId, String type) { public Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, String userId, String type) {
TypedQuery<FederatedUserCredentialEntity> query = em.createNamedQuery("federatedUserCredentialByUserAndType", FederatedUserCredentialEntity.class) TypedQuery<FederatedUserCredentialEntity> query = em.createNamedQuery("federatedUserCredentialByUserAndType", FederatedUserCredentialEntity.class)
.setParameter("type", type) .setParameter("type", type)
.setParameter("userId", userId); .setParameter("userId", userId);
List<FederatedUserCredentialEntity> results = query.getResultList(); return closing(query.getResultStream().map(this::toModel));
List<CredentialModel> rtn = new LinkedList<>();
for (FederatedUserCredentialEntity entity : results) {
rtn.add(toModel(entity));
}
return rtn;
} }
@Override @Override
@ -699,12 +660,13 @@ public class JpaUserFederatedStorageProvider implements
} }
@Override @Override
public List<String> getStoredUsers(RealmModel realm, int first, int max) { public Stream<String> getStoredUsersStream(RealmModel realm, int first, int max) {
TypedQuery<String> query = em.createNamedQuery("getFederatedUserIds", String.class) TypedQuery<String> query = em.createNamedQuery("getFederatedUserIds", String.class)
.setParameter("realmId", realm.getId()) .setParameter("realmId", realm.getId());
.setFirstResult(first); if (first > 0)
query.setFirstResult(first);
if (max > 0) query.setMaxResults(max); if (max > 0) query.setMaxResults(max);
return query.getResultList(); return closing(query.getResultStream());
} }
@Override @Override
@ -744,11 +706,8 @@ public class JpaUserFederatedStorageProvider implements
@Override @Override
public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId) { public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId) {
List<FederatedUserCredentialEntity> sortedCreds = getStoredCredentialEntities(user.getId());
// 1 - Create new list and move everything to it. // 1 - Create new list and move everything to it.
List<FederatedUserCredentialEntity> newList = new ArrayList<>(); List<FederatedUserCredentialEntity> newList = this.getStoredCredentialEntitiesStream(user.getId()).collect(Collectors.toList());
newList.addAll(sortedCreds);
// 2 - Find indexes of our and newPrevious credential // 2 - Find indexes of our and newPrevious credential
int ourCredentialIndex = -1; int ourCredentialIndex = -1;

View file

@ -152,12 +152,9 @@ public class InMemoryUserAdapter extends UserModelDefaultMethods {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
List<String> value = attributes.get(name); List<String> value = this.attributes.get(name);
if (value == null) { return value != null ? value.stream() : Stream.empty();
return new LinkedList<>();
}
return value;
} }
@Override @Override
@ -166,8 +163,8 @@ public class InMemoryUserAdapter extends UserModelDefaultMethods {
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
return requiredActions; return this.requiredActions.stream();
} }
@Override @Override

View file

@ -91,12 +91,37 @@ public interface UserModel 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
* @deprecated Use {@link #getAttributeStream(String) getAttributeStream} instead.
*/ */
List<String> getAttribute(String name); @Deprecated
default List<String> getAttribute(String name) {
return this.getAttributeStream(name).collect(Collectors.toList());
}
/**
* Obtains all values associated with the specified attribute name.
*
* @param name the name of the attribute.
* @return a non-null {@code Stream} of attribute values.
*/
Stream<String> getAttributeStream(final String name);
Map<String, List<String>> getAttributes(); Map<String, List<String>> getAttributes();
Set<String> getRequiredActions(); /**
* @deprecated Use {@link #getRequiredActionsStream() getRequiredActionsStream} instead.
*/
@Deprecated
default Set<String> getRequiredActions() {
return this.getRequiredActionsStream().collect(Collectors.toSet());
}
/**
* Obtains the names of required actions associated with the user.
*
* @return a non-null {@code Stream} of required action names.
*/
Stream<String> getRequiredActionsStream();
void addRequiredAction(String action); void addRequiredAction(String action);
@ -122,18 +147,32 @@ public interface UserModel extends RoleMapperModel {
void setEmailVerified(boolean verified); void setEmailVerified(boolean verified);
/**
* @deprecated Use {@link #getGroupsStream() getGroupsStream} instead.
*/
@Deprecated @Deprecated
default Set<GroupModel> getGroups() { default Set<GroupModel> getGroups() {
return getGroupsStream().collect(Collectors.toSet()); return getGroupsStream().collect(Collectors.toSet());
} }
/**
* Obtains the groups associated with the user.
*
* @return a non-null {@code Stream} of groups.
*/
Stream<GroupModel> getGroupsStream(); Stream<GroupModel> getGroupsStream();
/**
* @deprecated Use {@link #getGroupsStream(String, Integer, Integer) getGroupsStream} instead.
*/
@Deprecated @Deprecated
default Set<GroupModel> getGroups(int first, int max) { default Set<GroupModel> getGroups(int first, int max) {
return getGroupsStream(null, first, max).collect(Collectors.toSet()); return getGroupsStream(null, first, max).collect(Collectors.toSet());
} }
/**
* @deprecated Use {@link #getGroupsStream(String, Integer, Integer) getGroupsStream} instead.
*/
@Deprecated @Deprecated
default Set<GroupModel> getGroups(String search, int first, int max) { default Set<GroupModel> getGroups(String search, int first, int max) {
return getGroupsStream(search, first, max) return getGroupsStream(search, first, max)
@ -141,7 +180,7 @@ public interface UserModel extends RoleMapperModel {
} }
/** /**
* Returns a paginated stream of groups within this.realm with search in the name * Returns a paginated stream of groups within this realm with search in the name
* *
* @param search Case insensitive string which will be searched for. Ignored if null. * @param search Case insensitive string which will be searched for. Ignored if null.
* @param first Index of first group to return. Ignored if negative or {@code null}. * @param first Index of first group to return. Ignored if negative or {@code null}.

View file

@ -26,6 +26,8 @@ import org.keycloak.storage.user.UserRegistrationProvider;
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>
@ -42,13 +44,47 @@ public interface UserProvider extends Provider,
boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider); boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
void preRemove(RealmModel realm, IdentityProviderModel provider); void preRemove(RealmModel realm, IdentityProviderModel provider);
void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel); void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
/**
* @deprecated Use {@link #getFederatedIdentitiesStream(UserModel, RealmModel) getFederatedIdentitiesStream} instead.
*/
@Deprecated
default Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
return this.getFederatedIdentitiesStream(user, realm).collect(Collectors.toSet());
}
/**
* Obtains the federated identities of the specified user.
*
* @param user a reference to the user.
* @param realm a reference to the realm.
* @return a non-null {@code Stream} of federated identities associated with the user.
*/
Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm);
FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm); FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm); UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
void addConsent(RealmModel realm, String userId, UserConsentModel consent); void addConsent(RealmModel realm, String userId, UserConsentModel consent);
UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientInternalId); UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientInternalId);
List<UserConsentModel> getConsents(RealmModel realm, String userId);
/**
* @deprecated Use {@link #getConsentsStream(RealmModel, String) getConsentsStream} instead.
*/
@Deprecated
default List<UserConsentModel> getConsents(RealmModel realm, String userId) {
return getConsentsStream(realm, userId).collect(Collectors.toList());
}
/**
* Obtains the consents associated with the user identified by the specified {@code userId}.
*
* @param realm a reference to the realm.
* @param userId the user identifier.
* @return a non-null {@code Stream} of consents associated with the user.
*/
Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId);
void updateConsent(RealmModel realm, String userId, UserConsentModel consent); void updateConsent(RealmModel realm, String userId, UserConsentModel consent);
boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId); boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId);
@ -56,8 +92,42 @@ public interface UserProvider extends Provider,
int getNotBeforeOfUser(RealmModel realm, UserModel user); int getNotBeforeOfUser(RealmModel realm, UserModel user);
UserModel getServiceAccount(ClientModel client); UserModel getServiceAccount(ClientModel client);
List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts);
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts); /**
* @deprecated Use {@link #getUsersStream(RealmModel, boolean) getUsersStream} instead.
*/
@Deprecated
default List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) {
return this.getUsersStream(realm, includeServiceAccounts).collect(Collectors.toList());
}
/**
* Obtains the users associated with the specified realm.
*
* @param realm a reference to the realm being used for the search.
* @param includeServiceAccounts {@code true} if service accounts should be included in the result; {@code false} otherwise.
* @return a non-null {@code Stream} of users associated withe the realm.
*/
Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts);
/**
* @deprecated Use {@link #getUsersStream(RealmModel, int, int, boolean) getUsersStream} instead.
*/
@Deprecated
default List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {
return this.getUsersStream(realm, firstResult, maxResults, includeServiceAccounts).collect(Collectors.toList());
}
/**
* Obtains the users associated with the specified realm.
*
* @param realm a reference to the realm being used for the search.
* @param firstResult first result to return. Ignored if negative.
* @param maxResults maximum number of results to return. Ignored if negative.
* @param includeServiceAccounts {@code true} if service accounts should be included in the result; {@code false} otherwise.
* @return a non-null {@code Stream} of users associated withe the realm.
*/
Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts);
/** /**
* only used for local storage * only used for local storage

View file

@ -86,8 +86,8 @@ public class UserModelDelegate implements UserModel {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
return delegate.getAttribute(name); return delegate.getAttributeStream(name);
} }
@Override @Override
@ -96,8 +96,8 @@ public class UserModelDelegate implements UserModel {
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
return delegate.getRequiredActions(); return delegate.getRequiredActionsStream();
} }
@Override @Override

View file

@ -30,11 +30,8 @@ import org.keycloak.models.utils.RoleUtils;
import org.keycloak.storage.ReadOnlyException; import org.keycloak.storage.ReadOnlyException;
import org.keycloak.storage.StorageId; import org.keycloak.storage.StorageId;
import java.util.Collections;
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.stream.Stream; import java.util.stream.Stream;
/** /**
@ -62,8 +59,8 @@ public abstract class AbstractUserAdapter extends UserModelDefaultMethods {
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
return Collections.emptySet(); return Stream.empty();
} }
@Override @Override
@ -303,11 +300,11 @@ public abstract class AbstractUserAdapter extends UserModelDefaultMethods {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (name.equals(UserModel.USERNAME)) { if (name.equals(UserModel.USERNAME)) {
return Collections.singletonList(getUsername()); return Stream.of(getUsername());
} }
return Collections.emptyList(); return Stream.empty();
} }
@Override @Override

View file

@ -30,11 +30,8 @@ import org.keycloak.models.utils.RoleUtils;
import org.keycloak.storage.StorageId; import org.keycloak.storage.StorageId;
import org.keycloak.storage.federated.UserFederatedStorageProvider; import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.Collections;
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.stream.Stream; import java.util.stream.Stream;
/** /**
@ -71,8 +68,8 @@ public abstract class AbstractUserAdapterFederatedStorage extends UserModelDefau
} }
@Override @Override
public Set<String> getRequiredActions() { public Stream<String> getRequiredActionsStream() {
return getFederatedStorage().getRequiredActions(realm, this.getId()); return getFederatedStorage().getRequiredActionsStream(realm, this.getId());
} }
@Override @Override
@ -360,12 +357,12 @@ public abstract class AbstractUserAdapterFederatedStorage extends UserModelDefau
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (UserModel.USERNAME.equals(name)) { if (UserModel.USERNAME.equals(name)) {
return Collections.singletonList(getUsername()); return Stream.of(getUsername());
} }
List<String> result = getFederatedStorage().getAttributes(realm, this.getId()).get(mapAttribute(name)); List<String> result = getFederatedStorage().getAttributes(realm, this.getId()).get(mapAttribute(name));
return (result == null) ? Collections.emptyList() : result; return (result == null) ? Stream.empty() : result.stream();
} }
private String mapAttribute(String attributeName) { private String mapAttribute(String attributeName) {

View file

@ -20,6 +20,8 @@ import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import java.util.List; import java.util.List;
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>
@ -30,5 +32,22 @@ public interface UserAttributeFederatedStorage {
void setAttribute(RealmModel realm, String userId, String name, List<String> values); void setAttribute(RealmModel realm, String userId, String name, List<String> values);
void removeAttribute(RealmModel realm, String userId, String name); void removeAttribute(RealmModel realm, String userId, String name);
MultivaluedHashMap<String, String> getAttributes(RealmModel realm, String userId); MultivaluedHashMap<String, String> getAttributes(RealmModel realm, String userId);
List<String> getUsersByUserAttribute(RealmModel realm, String name, String value);
/**
* @deprecated Use {@link #getUsersByUserAttributeStream(RealmModel, String, String) getUsersByUserAttributeStream} instead.
*/
@Deprecated
default List<String> getUsersByUserAttribute(RealmModel realm, String name, String value) {
return this.getUsersByUserAttributeStream(realm, name, value).collect(Collectors.toList());
}
/**
* Searches for federated users that have an attribute with the specified {@code name} and {@code value}.
*
* @param realm a reference to the realm.
* @param name the attribute name.
* @param value the attribute value.
* @return a non-null {@code Stream} of users that match the search criteria.
*/
Stream<String> getUsersByUserAttributeStream(RealmModel realm, String name, String value);
} }

View file

@ -21,6 +21,8 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
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>
@ -32,6 +34,23 @@ public interface UserBrokerLinkFederatedStorage {
boolean removeFederatedIdentity(RealmModel realm, String userId, String socialProvider); boolean removeFederatedIdentity(RealmModel realm, String userId, String socialProvider);
void preRemove(RealmModel realm, IdentityProviderModel provider); void preRemove(RealmModel realm, IdentityProviderModel provider);
void updateFederatedIdentity(RealmModel realm, String userId, FederatedIdentityModel federatedIdentityModel); void updateFederatedIdentity(RealmModel realm, String userId, FederatedIdentityModel federatedIdentityModel);
Set<FederatedIdentityModel> getFederatedIdentities(String userId, RealmModel realm);
/**
* @deprecated Use {@link #getFederatedIdentitiesStream(String, RealmModel) getFederatedIdentitiesStream} instead.
*/
@Deprecated
default Set<FederatedIdentityModel> getFederatedIdentities(String userId, RealmModel realm) {
return this.getFederatedIdentitiesStream(userId, realm).collect(Collectors.toSet());
}
/**
* Obtains the identities of the federated user identified by {@code userId}.
*
* @param userId the user identifier.
* @param realm a reference to the realm.
* @return a non-null {@code Stream} of federated identities associated with the user.
*/
Stream<FederatedIdentityModel> getFederatedIdentitiesStream(String userId, RealmModel realm);
FederatedIdentityModel getFederatedIdentity(String userId, String socialProvider, RealmModel realm); FederatedIdentityModel getFederatedIdentity(String userId, String socialProvider, RealmModel realm);
} }

View file

@ -20,6 +20,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserConsentModel;
import java.util.List; import java.util.List;
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>
@ -28,7 +30,24 @@ import java.util.List;
public interface UserConsentFederatedStorage { public interface UserConsentFederatedStorage {
void addConsent(RealmModel realm, String userId, UserConsentModel consent); void addConsent(RealmModel realm, String userId, UserConsentModel consent);
UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientInternalId); UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientInternalId);
List<UserConsentModel> getConsents(RealmModel realm, String userId);
/**
* @deprecated Use {@link #getConsentsStream(RealmModel, String) getConsentsStream} instead.
*/
@Deprecated
default List<UserConsentModel> getConsents(RealmModel realm, String userId) {
return this.getConsentsStream(realm, userId).collect(Collectors.toList());
}
/**
* Obtains the consents associated with the federated user identified by {@code userId}.
*
* @param realm a reference to the realm.
* @param userId the user identifier.
* @return a non-null {@code Stream} of consents associated with the user.
*/
Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId);
void updateConsent(RealmModel realm, String userId, UserConsentModel consent); void updateConsent(RealmModel realm, String userId, UserConsentModel consent);
boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId); boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId);
} }

View file

@ -28,6 +28,8 @@ import org.keycloak.models.UserModel;
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;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -43,7 +45,24 @@ public interface UserFederatedStorageProvider extends Provider,
UserRoleMappingsFederatedStorage, UserRoleMappingsFederatedStorage,
UserFederatedUserCredentialStore { UserFederatedUserCredentialStore {
List<String> getStoredUsers(RealmModel realm, int first, int max); /**
* @deprecated Use {@link #getStoredUsersStream(RealmModel, int, int) getStoredUsersStream} instead.
*/
@Deprecated
default List<String> getStoredUsers(RealmModel realm, int first, int max) {
return getStoredUsersStream(realm, first, max).collect(Collectors.toList());
}
/**
* Obtains the ids of all federated users in the realm.
*
* @param realm a reference to the realm.
* @param first first result to return. Ignored if negative.
* @param max maximum number of results to return. Ignored if negative.
* @return a non-null {@code Stream} of federated user ids.
*/
Stream<String> getStoredUsersStream(RealmModel realm, int first, int max);
int getStoredUsersCount(RealmModel realm); int getStoredUsersCount(RealmModel realm);
void preRemove(RealmModel realm); void preRemove(RealmModel realm);

View file

@ -21,6 +21,8 @@ import org.keycloak.models.RealmModel;
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;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -31,7 +33,41 @@ public interface UserFederatedUserCredentialStore extends Provider {
CredentialModel createCredential(RealmModel realm, String userId, CredentialModel cred); CredentialModel createCredential(RealmModel realm, String userId, CredentialModel cred);
boolean removeStoredCredential(RealmModel realm, String userId, String id); boolean removeStoredCredential(RealmModel realm, String userId, String id);
CredentialModel getStoredCredentialById(RealmModel realm, String userId, String id); CredentialModel getStoredCredentialById(RealmModel realm, String userId, String id);
List<CredentialModel> getStoredCredentials(RealmModel realm, String userId);
List<CredentialModel> getStoredCredentialsByType(RealmModel realm, String userId, String type); /**
* @deprecated Use {@link #getStoredCredentialsStream(RealmModel, String) getStoredCredentialsStream} instead.
*/
@Deprecated
default List<CredentialModel> getStoredCredentials(RealmModel realm, String userId) {
return this.getStoredCredentialsStream(realm, userId).collect(Collectors.toList());
}
/**
* Obtains the credentials associated with the federated user identified by {@code userId}.
*
* @param realm a reference to the realm.
* @param userId the user identifier.
* @return a non-null {@code Stream} of credentials.
*/
Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, String userId);
/**
* @deprecated Use {@link #getStoredCredentialsByTypeStream(RealmModel, String, String) getStoredCredentialsByTypeStream} instead.
*/
@Deprecated
default List<CredentialModel> getStoredCredentialsByType(RealmModel realm, String userId, String type) {
return this.getStoredCredentialsByTypeStream(realm, userId, type).collect(Collectors.toList());
}
/**
* Obtains the credentials of type {@code type} that are associated with the federated user identified by {@code userId}.
*
* @param realm a reference to the realm.
* @param userId the user identifier.
* @param type the credential type.
* @return a non-null {@code Stream} of credentials.
*/
Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, String userId, String type);
CredentialModel getStoredCredentialByNameAndType(RealmModel realm, String userId, String name, String type); CredentialModel getStoredCredentialByNameAndType(RealmModel realm, String userId, String name, String type);
} }

View file

@ -38,6 +38,24 @@ public interface UserGroupMembershipFederatedStorage {
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);
/**
* @deprecated Use {@link #getMembershipStream(RealmModel, GroupModel, int, int) getMembershipStream} instead.
*/
@Deprecated
default List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max) {
return this.getMembershipStream(realm, group, firstResult, max).collect(Collectors.toList());
}
/**
* Obtains the federated users that are members of the given {@code group} in the specified {@code realm}.
*
* @param realm a reference to the realm.
* @param group a reference to the group whose federated members are being searched.
* @param firstResult first result to return. Ignored if negative.
* @param max maximum number of results to return. Ignored if negative.
* @return a non-null {@code Stream} of federated user ids that are members of the group in the realm.
*/
Stream<String> getMembershipStream(RealmModel realm, GroupModel group, int firstResult, int max);
} }

View file

@ -19,13 +19,31 @@ package org.keycloak.storage.federated;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
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 UserRequiredActionsFederatedStorage { public interface UserRequiredActionsFederatedStorage {
Set<String> getRequiredActions(RealmModel realm, String userId);
/**
* @deprecated Use {@link #getRequiredActionsStream(RealmModel, String) getRequiredActionsStream} instead.
*/
@Deprecated
default Set<String> getRequiredActions(RealmModel realm, String userId) {
return this.getRequiredActionsStream(realm, userId).collect(Collectors.toSet());
}
/**
* Obtains the names of required actions associated with the federated user identified by {@code userId}.
*
* @param realm a reference to the realm.
* @param userId the user identifier.
* @return a non-null {@code Stream} of required action names.
*/
Stream<String> getRequiredActionsStream(RealmModel realm, String userId);
void addRequiredAction(RealmModel realm, String userId, String action); void addRequiredAction(RealmModel realm, String userId, String action);
void removeRequiredAction(RealmModel realm, String userId, String action); void removeRequiredAction(RealmModel realm, String userId, String action);
} }

View file

@ -31,11 +31,21 @@ public interface UserRoleMappingsFederatedStorage {
void grantRole(RealmModel realm, String userId, RoleModel role); void grantRole(RealmModel realm, String userId, RoleModel role);
/**
* @deprecated Use {@link #getRoleMappingsStream(RealmModel, String) getRoleMappingsStream} instead.
*/
@Deprecated @Deprecated
default Set<RoleModel> getRoleMappings(RealmModel realm,String userId) { default Set<RoleModel> getRoleMappings(RealmModel realm,String userId) {
return getRoleMappingsStream(realm, userId).collect(Collectors.toSet()); return getRoleMappingsStream(realm, userId).collect(Collectors.toSet());
} }
/**
* Obtains the roles associated with the federated user identified by {@code userId}.
*
* @param realm a reference to the realm.
* @param userId the user identifier.
* @return a non-null {@code Stream} of roles.
*/
Stream<RoleModel> getRoleMappingsStream(RealmModel realm, String userId); Stream<RoleModel> getRoleMappingsStream(RealmModel realm, String userId);
void deleteRoleMapping(RealmModel realm, String userId, RoleModel role); void deleteRoleMapping(RealmModel realm, String userId, RoleModel role);

View file

@ -21,10 +21,11 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
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;
import java.util.stream.Stream;
/** /**
* Optional capability interface implemented by UserStorageProviders. * Optional capability interface implemented by UserStorageProviders.
@ -56,8 +57,7 @@ public interface UserQueryProvider {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
return countUsersInGroups(getUsersStream(realm), groupIds);
return countUsersInGroups(getUsers(realm), groupIds);
} }
/** /**
@ -68,7 +68,7 @@ public interface UserQueryProvider {
* @return number of users that match the search * @return number of users that match the search
*/ */
default int getUsersCount(String search, RealmModel realm) { default int getUsersCount(String search, RealmModel realm) {
return searchForUser(search, realm).size(); return (int) searchForUserStream(search, realm).count();
} }
/** /**
@ -84,9 +84,7 @@ public interface UserQueryProvider {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
return countUsersInGroups(searchForUserStream(search, realm), groupIds);
List<UserModel> users = searchForUser(search, realm);
return countUsersInGroups(users, groupIds);
} }
/** /**
@ -97,7 +95,7 @@ public interface UserQueryProvider {
* @return number of users that match the given filters * @return number of users that match the given filters
*/ */
default int getUsersCount(Map<String, String> params, RealmModel realm) { default int getUsersCount(Map<String, String> params, RealmModel realm) {
return searchForUser(params, realm).size(); return (int) searchForUserStream(params, realm).count();
} }
/** /**
@ -113,9 +111,7 @@ public interface UserQueryProvider {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
return countUsersInGroups(searchForUserStream(params, realm), groupIds);
List<UserModel> users = searchForUser(params, realm);
return countUsersInGroups(users, groupIds);
} }
/** /**
@ -126,10 +122,8 @@ public interface UserQueryProvider {
* @param groupIds id of groups that should be checked for * @param groupIds id of groups that should be checked for
* @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(Stream<UserModel> users, Set<String> groupIds) {
return (int) users.stream() return (int) users.filter(u -> u.getGroupsStream().map(GroupModel::getId).anyMatch(groupIds::contains)).count();
.filter(u -> u.getGroupsStream().anyMatch(group -> groupIds.contains(group.getId())))
.count();
} }
/** /**
@ -143,8 +137,39 @@ public interface UserQueryProvider {
throw new RuntimeException("Not implemented"); throw new RuntimeException("Not implemented");
} }
List<UserModel> getUsers(RealmModel realm); /**
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults); * @deprecated Use {@link #getUsersStream(RealmModel) getUsersStream} instead.
*/
@Deprecated
default List<UserModel> getUsers(RealmModel realm) {
return this.getUsersStream(realm).collect(Collectors.toList());
}
/**
* Searches all users in the realm.
*
* @param realm a reference to the realm.
* @return a non-null {@code Stream} of users.
*/
Stream<UserModel> getUsersStream(RealmModel realm);
/**
* @deprecated Use {@link #getUsersStream(RealmModel, int, int) getUsersStream} instead.
*/
@Deprecated
default List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
return this.getUsersStream(realm, firstResult, maxResults).collect(Collectors.toList());
}
/**
* Searches all users in the realm, starting from the {@code firstResult} and containing at most {@code maxResults}.
*
* @param realm a reference to the realm.
* @param firstResult first result to return. Ignored if negative.
* @param maxResults maximum number of results to return. Ignored if negative.
* @return a non-null {@code Stream} of users.
*/
Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults);
/** /**
* Search for users with username, email or first + last name that is like search string. * Search for users with username, email or first + last name that is like search string.
@ -156,8 +181,24 @@ public interface UserQueryProvider {
* @param search * @param search
* @param realm * @param realm
* @return * @return
* @deprecated Use {@link #searchForUserStream(String, RealmModel) searchForUserStream} instead.
*/ */
List<UserModel> searchForUser(String search, RealmModel realm); @Deprecated
default List<UserModel> searchForUser(String search, RealmModel realm) {
return this.searchForUserStream(search, realm).collect(Collectors.toList());
}
/**
* Searches for users with username, email or first + last name that is like search string. If possible, implementations
* should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE).
* <p/>
* This method is used by the admin console search box
*
* @param search case sensitive search string.
* @param realm a reference to the realm.
* @return a non-null {@code Stream} of users that match the search string.
*/
Stream<UserModel> searchForUserStream(String search, RealmModel realm);
/** /**
* Search for users with username, email or first + last name that is like search string. * Search for users with username, email or first + last name that is like search string.
@ -171,8 +212,26 @@ public interface UserQueryProvider {
* @param firstResult * @param firstResult
* @param maxResults * @param maxResults
* @return * @return
* @deprecated Use {@link #searchForUserStream(String, RealmModel, int, int) searchForUserStream} instead.
*/ */
List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults); @Deprecated
default List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
return this.searchForUserStream(search, realm, firstResult, maxResults).collect(Collectors.toList());
}
/**
* Searches for users with username, email or first + last name that is like search string. If possible, implementations
* should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE).
* <p/>
* This method is used by the admin console search box
*
* @param search case sensitive search string.
* @param realm a reference to the realm.
* @param firstResult first result to return. Ignored if negative.
* @param maxResults maximum number of results to return. Ignored if negative.
* @return a non-null {@code Stream} of users that match the search criteria.
*/
Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults);
/** /**
* Search for user by parameter. Valid parameters are: * Search for user by parameter. Valid parameters are:
@ -189,8 +248,30 @@ public interface UserQueryProvider {
* @param params * @param params
* @param realm * @param realm
* @return * @return
* @deprecated Use {@link #searchForUserStream(Map, RealmModel) searchForUserStream} instead.
*/ */
List<UserModel> searchForUser(Map<String, String> params, RealmModel realm); @Deprecated
default List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
return this.searchForUserStream(params, realm).collect(Collectors.toList());
}
/**
* Searches for user by parameter. If possible, implementations should treat the parameter values as partial match patterns
* (i.e. in RDMBS terms use LIKE). Valid parameters are:
* <ul>
* <li><b>first</b> - first name</li>
* <li><b>last</b> - last name</li>
* <li><b>email</b> - email</li>
* <li><b>username</b> - username</li>
* <li><b>enabled</b> - if user is enabled (true/false)</li>
* </ul>
* This method is used by the REST API when querying users.
*
* @param params a map containing the search parameters.
* @param realm a reference to the realm.
* @return a non-null {@code Stream} of users that match the search parameters.
*/
Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm);
/** /**
* Search for user by parameter. Valid parameters are: * Search for user by parameter. Valid parameters are:
@ -209,8 +290,60 @@ public interface UserQueryProvider {
* @param firstResult * @param firstResult
* @param maxResults * @param maxResults
* @return * @return
* @deprecated Use {@link #searchForUserStream(Map, RealmModel, int, int) searchForUserStream} instead.
*/ */
List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults); @Deprecated
default List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
return this.searchForUserStream(params, realm, firstResult, maxResults).collect(Collectors.toList());
}
/**
* Searches for user by parameter. If possible, implementations should treat the parameter values as partial match patterns
* (i.e. in RDMBS terms use LIKE). Valid parameters are:
* <ul>
* <li><b>first</b> - first name</li>
* <li><b>last</b> - last name</li>
* <li><b>email</b> - email</li>
* <li><b>username</b> - username</li>
* <li><b>enabled</b> - if user is enabled (true/false)</li>
* </ul>
* This method is used by the REST API when querying users.
*
* @param params a map containing the search parameters.
* @param realm a reference to the realm.
* @param firstResult first result to return. Ignored if negative.
* @param maxResults maximum number of results to return. Ignored if negative.
* @return a non-null {@code Stream} of users that match the search criteria.
*/
Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, int firstResult, int maxResults);
/**
* Get users that belong to a specific group. Implementations do not have to search in UserFederatedStorageProvider
* as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
*
* @param realm
* @param group
* @return
* @deprecated Use {@link #getGroupMembersStream(RealmModel, GroupModel) getGroupMembersStream} instead.
*/
@Deprecated
default List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
return this.getGroupMembersStream(realm, group).collect(Collectors.toList());
}
/**
* Obtains users that belong to a specific group. Implementations do not have to search in {@code UserFederatedStorageProvider}
* as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
*
* @param realm a reference to the realm.
* @param group a reference to the group.
* @return a non-null {@code Stream} of users that belong to the group.
*/
Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group);
/** /**
* Get users that belong to a specific group. Implementations do not have to search in UserFederatedStorageProvider * Get users that belong to a specific group. Implementations do not have to search in UserFederatedStorageProvider
@ -223,51 +356,77 @@ public interface UserQueryProvider {
* @param firstResult * @param firstResult
* @param maxResults * @param maxResults
* @return * @return
* @deprecated Use {@link #getGroupMembersStream(RealmModel, GroupModel, int, int) getGroupMembersStream} instead.
*/ */
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults); @Deprecated
default List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return this.getGroupMembersStream(realm, group, firstResult, maxResults).collect(Collectors.toList());
}
/**
* Obtains users that belong to a specific group. Implementations do not have to search in {@code UserFederatedStorageProvider}
* as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
*
* @param realm a reference to the realm.
* @param group a reference to the group.
* @param firstResult first result to return. Ignored if negative.
* @param maxResults maximum number of results to return. Ignored if negative.
* @return a non-null {@code Stream} of users that belong to the group.
*/
Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults);
/** /**
* Get users that belong to a specific role. * Get users that belong to a specific role.
* *
*
*
* @param realm * @param realm
* @param role * @param role
* @return * @return
* @deprecated Use {@link #getRoleMembersStream(RealmModel, RoleModel) getRoleMembersStream} instead.
*/ */
default List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) @Deprecated
{ default List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) {
return Collections.EMPTY_LIST; return this.getRoleMembersStream(realm, role).collect(Collectors.toList());
}
/**
* Obtains users that have the specified role.
*
* @param realm a reference to the realm.
* @param role a reference to the role.
* @return a non-null {@code Stream} of users that have the specified role.
*/
default Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
return Stream.empty();
} }
/** /**
* Search for users that have a specific role with a specific roleId. * Search for users that have a specific role with a specific roleId.
* *
*
*
* @param firstResult * @param firstResult
* @param maxResults * @param maxResults
* @param role * @param role
* @return * @return
* @deprecated Use {@link #getRoleMembersStream(RealmModel, RoleModel, int, int) getRoleMembersStream} instead.
*/ */
default List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) @Deprecated
{ default List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
return Collections.EMPTY_LIST; return this.getRoleMembersStream(realm, role, firstResult, maxResults).collect(Collectors.toList());
} }
/** /**
* Get users that belong to a specific group. Implementations do not have to search in UserFederatedStorageProvider * Searches for users that have the specified role.
* as this is done automatically.
* *
* @see org.keycloak.storage.federated.UserFederatedStorageProvider * @param realm a reference to the realm.
* * @param role a reference to the role.
* * @param firstResult first result to return. Ignored if negative.
* * @param maxResults maximum number of results to return. Ignored if negative.
* @param realm * @return a non-null {@code Stream} of users that have the specified role.
* @param group
* @return
*/ */
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group); default Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
return Stream.empty();
}
/** /**
* Search for users that have a specific attribute with a specific value. * Search for users that have a specific attribute with a specific value.
@ -275,13 +434,29 @@ public interface UserQueryProvider {
* as this is done automatically. * as this is done automatically.
* *
* @see org.keycloak.storage.federated.UserFederatedStorageProvider * @see org.keycloak.storage.federated.UserFederatedStorageProvider
*
* *
* @param attrName * @param attrName
* @param attrValue * @param attrValue
* @param realm * @param realm
* @return * @return
* @deprecated Use {@link #searchForUserByUserAttributeStream(String, String, RealmModel) searchForUserByUserAttributeStream}
* instead.
*/ */
List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm); @Deprecated
default List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
return this.searchForUserByUserAttributeStream(attrName, attrValue, realm).collect(Collectors.toList());
}
/**
* Searches for users that have a specific attribute with a specific value. Implementations do not have to search in
* {@code UserFederatedStorageProvider} as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
*
* @param attrName the attribute name.
* @param attrValue the attribute value.
* @param realm a reference to the realm.
* @return a non-null {@code Stream} of users that match the search criteria.
*/
Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm);
} }

View file

@ -46,6 +46,7 @@ import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
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>
@ -130,8 +131,8 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
return userCtx.getAttribute(name); return userCtx.getAttribute(name).stream();
} }
@Override @Override

View file

@ -17,6 +17,7 @@
package org.keycloak.storage; package org.keycloak.storage;
import com.google.common.collect.Streams;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.component.ComponentFactory; import org.keycloak.component.ComponentFactory;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
@ -50,14 +51,12 @@ import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserRegistrationProvider; import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
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.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction; import static org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction;
@ -130,10 +129,7 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
if (userCache != null) { if (userCache != null) {
userCache.evict(realm, user); userCache.evict(realm, user);
} }
runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() { runJobInTransaction(session.getKeycloakSessionFactory(), session -> {
@Override
public void run(KeycloakSession session) {
RealmModel realmModel = session.realms().getRealm(realm.getId()); RealmModel realmModel = session.realms().getRealm(realm.getId());
if (realmModel == null) return; if (realmModel == null) return;
UserModel deletedUser = session.userLocalStorage().getUserById(userId, realmModel); UserModel deletedUser = session.userLocalStorage().getUserById(userId, realmModel);
@ -141,8 +137,6 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
new UserManager(session).removeUser(realmModel, deletedUser, session.userLocalStorage()); new UserManager(session).removeUser(realmModel, deletedUser, session.userLocalStorage());
logger.debugf("Removed invalid user '%s'", userName); logger.debugf("Removed invalid user '%s'", userName);
} }
}
}); });
} }
@ -270,70 +264,70 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
{@link UserQueryProvider} methods implementation start here */ {@link UserQueryProvider} methods implementation start here */
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return getGroupMembers(realm, group, -1, -1); return getGroupMembersStream(realm, group, -1, -1);
} }
@Override @Override
public List<UserModel> getGroupMembers(final RealmModel realm, final GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(final RealmModel realm, final GroupModel group, int firstResult, int maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).getGroupMembers(realm, group).stream(); return ((UserQueryProvider)provider).getGroupMembersStream(realm, group);
} else if (provider instanceof UserFederatedStorageProvider) { } else if (provider instanceof UserFederatedStorageProvider) {
Stream<String> ids = ((UserFederatedStorageProvider)provider).getMembership(realm, group, -1, -1).stream(); return ((UserFederatedStorageProvider)provider).getMembershipStream(realm, group, -1, -1).
return ids.map(id -> getUserById(id, realm)); map(id -> getUserById(id, realm));
} }
return Stream.empty(); return Stream.empty();
}, realm, firstResult, maxResults); }, realm, firstResult, maxResults);
return importValidation(realm, results).collect(Collectors.toList()); return importValidation(realm, results);
} }
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
return getRoleMembers(realm, role, -1, -1); return getRoleMembersStream(realm, role, -1, -1);
} }
@Override @Override
public List<UserModel> getRoleMembers(final RealmModel realm, final RoleModel role, int firstResult, int maxResults) { public Stream<UserModel> getRoleMembersStream(final RealmModel realm, final RoleModel role, int firstResult, int maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).getRoleMembers(realm, role).stream(); return ((UserQueryProvider)provider).getRoleMembersStream(realm, role);
} }
return Stream.empty(); return Stream.empty();
}, realm, firstResult, maxResults); }, realm, firstResult, maxResults);
return importValidation(realm, results).collect(Collectors.toList()); return importValidation(realm, results);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return getUsers(realm, false); return getUsersStream(realm, false);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return getUsers(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
return getUsers(realm, 0, Integer.MAX_VALUE - 1, includeServiceAccounts); return getUsersStream(realm, 0, Integer.MAX_VALUE - 1, includeServiceAccounts);
} }
@Override @Override
public List<UserModel> getUsers(final RealmModel realm, int firstResult, int maxResults, final boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(final RealmModel realm, int firstResult, int maxResults, final boolean includeServiceAccounts) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserProvider) { // it is local storage if (provider instanceof UserProvider) { // it is local storage
return ((UserProvider) provider).getUsers(realm, includeServiceAccounts).stream(); return ((UserProvider) provider).getUsersStream(realm, includeServiceAccounts);
} else if (provider instanceof UserQueryProvider) { } else if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).getUsers(realm).stream(); return ((UserQueryProvider)provider).getUsersStream(realm);
} }
return Stream.empty(); return Stream.empty();
} }
, realm, firstResult, maxResults); , realm, firstResult, maxResults);
return importValidation(realm, results).collect(Collectors.toList()); return importValidation(realm, results);
} }
@Override @Override
@ -377,51 +371,49 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(search, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).searchForUser(search, realm).stream(); return ((UserQueryProvider)provider).searchForUserStream(search, realm);
} }
return Stream.empty(); return Stream.empty();
}, realm, firstResult, maxResults); }, realm, firstResult, maxResults);
return importValidation(realm, results).collect(Collectors.toList()); return importValidation(realm, results);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) {
return searchForUser(attributes, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(attributes, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
if (attributes.containsKey(UserModel.SEARCH)) { if (attributes.containsKey(UserModel.SEARCH)) {
return ((UserQueryProvider)provider).searchForUser(attributes.get(UserModel.SEARCH), realm).stream(); return ((UserQueryProvider)provider).searchForUserStream(attributes.get(UserModel.SEARCH), realm);
} else { } else {
return ((UserQueryProvider)provider).searchForUser(attributes, realm).stream(); return ((UserQueryProvider)provider).searchForUserStream(attributes, realm);
} }
} }
return Stream.empty(); return Stream.empty();
} }
, realm, firstResult, maxResults); , realm, firstResult, maxResults);
return importValidation(realm, results).collect(Collectors.toList()); return importValidation(realm, results);
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).searchForUserByUserAttribute(attrName, attrValue, realm).stream(); return ((UserQueryProvider)provider).searchForUserByUserAttributeStream(attrName, attrValue, realm);
} else if (provider instanceof UserFederatedStorageProvider) { } else if (provider instanceof UserFederatedStorageProvider) {
return ((UserFederatedStorageProvider)provider).getUsersByUserAttribute(realm, attrName, attrValue).stream() return ((UserFederatedStorageProvider)provider).getUsersByUserAttributeStream(realm, attrName, attrValue)
.map(id -> getUserById(id, realm)) .map(id -> getUserById(id, realm))
.filter(Objects::nonNull); .filter(Objects::nonNull);
@ -432,7 +424,7 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
// removeDuplicates method may cause concurrent issues, it should not be used on parallel streams // removeDuplicates method may cause concurrent issues, it should not be used on parallel streams
results = removeDuplicates(results); results = removeDuplicates(results);
return importValidation(realm, results).collect(Collectors.toList()); return importValidation(realm, results);
} }
/** {@link UserQueryProvider} methods implementation end here /** {@link UserQueryProvider} methods implementation end here
@ -545,11 +537,11 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public List<UserConsentModel> getConsents(RealmModel realm, String userId) { public Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId) {
if (StorageId.isLocalStorage(userId)) { if (StorageId.isLocalStorage(userId)) {
return localStorage().getConsents(realm, userId); return localStorage().getConsentsStream(realm, userId);
} else { } else {
return getFederatedStorage().getConsents(realm, userId); return getFederatedStorage().getConsentsStream(realm, userId);
} }
} }
@ -608,14 +600,13 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) {
if (user == null) throw new IllegalStateException("Federated user no longer valid"); if (user == null) throw new IllegalStateException("Federated user no longer valid");
Set<FederatedIdentityModel> set = new HashSet<>(); Stream<FederatedIdentityModel> stream = StorageId.isLocalStorage(user) ?
if (StorageId.isLocalStorage(user)) { localStorage().getFederatedIdentitiesStream(user, realm) : Stream.empty();
set.addAll(localStorage().getFederatedIdentities(user, realm)); if (getFederatedStorage() != null)
} stream = Streams.concat(stream, getFederatedStorage().getFederatedIdentitiesStream(user.getId(), realm));
if (getFederatedStorage() != null) set.addAll(getFederatedStorage().getFederatedIdentities(user.getId(), realm)); return stream.distinct();
return set;
} }
@Override @Override

View file

@ -18,13 +18,10 @@
package org.keycloak.testsuite.federation; package org.keycloak.testsuite.federation;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
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;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
@ -319,58 +316,57 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return getUsers(realm, -1, -1); return getUsersStream(realm, -1, -1);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return users.values() return users.values()
.stream() .stream()
.skip(firstResult).limit(maxResults) .skip(firstResult).limit(maxResults)
.map(myUser -> createUser(realm, myUser.username)) .map(myUser -> createUser(realm, myUser.username));
.collect(Collectors.toList());
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return searchForUser(search, realm, -1, -1); return searchForUserStream(search, realm, -1, -1);
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
UserModel user = getUserByUsername(search, realm); UserModel user = getUserByUsername(search, realm);
return user == null ? Collections.emptyList() : Arrays.asList(user); return user == null ? Stream.empty() : Stream.of(user);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) {
// Assume that this is not supported // Assume that this is not supported
return Collections.emptyList(); return Stream.empty();
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
// Assume that this is not supported // Assume that this is not supported
return Collections.emptyList(); return Stream.empty();
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
// Assume that this is not supported // Assume that this is not supported
return Collections.emptyList(); return Stream.empty();
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
// Assume that this is not supported // Assume that this is not supported
return Collections.emptyList(); return Stream.empty();
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
// Assume that this is not supported // Assume that this is not supported
return Collections.emptyList(); return Stream.empty();
} }
@Override @Override

View file

@ -21,7 +21,6 @@ import org.keycloak.component.ComponentModel;
import org.keycloak.credential.CredentialInput; import org.keycloak.credential.CredentialInput;
import org.keycloak.credential.CredentialInputUpdater; import org.keycloak.credential.CredentialInputUpdater;
import org.keycloak.credential.CredentialInputValidator; import org.keycloak.credential.CredentialInputValidator;
import org.keycloak.credential.CredentialModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -35,11 +34,10 @@ import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider; import org.keycloak.storage.user.UserQueryProvider;
import java.util.Collections; import java.util.Collections;
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.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>
@ -224,79 +222,67 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
checkForceFail(); checkForceFail();
UserModel hardcoded = getUserByUsername(username, realm); UserModel model = getUserByUsername(username, realm);
List<UserModel> list = new LinkedList<>(); return model != null ? Stream.of(model) : Stream.empty();
list.add(hardcoded);
return list;
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
checkForceFail(); checkForceFail();
UserModel hardcoded = getUserByUsername(username, realm); UserModel model = getUserByUsername(username, realm);
List<UserModel> list = new LinkedList<>(); return model != null ? Stream.of(model) : Stream.empty();
list.add(hardcoded);
return list;
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
checkForceFail(); checkForceFail();
if (!search.equals(username)) return Collections.EMPTY_LIST; if (!search.equals(username)) return Stream.empty();
UserModel hardcoded = getUserByUsername(username, realm); UserModel model = getUserByUsername(username, realm);
List<UserModel> list = new LinkedList<>(); return model != null ? Stream.of(model) : Stream.empty();
list.add(hardcoded);
return list;
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
checkForceFail(); checkForceFail();
if (!search.equals(username)) return Collections.EMPTY_LIST; if (!search.equals(username)) return Stream.empty();
UserModel hardcoded = getUserByUsername(username, realm); UserModel model = getUserByUsername(username, realm);
List<UserModel> list = new LinkedList<>(); return model != null ? Stream.of(model) : Stream.empty();
list.add(hardcoded);
return list;
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) {
checkForceFail(); checkForceFail();
if (!username.equals(params.get("username")))return Collections.EMPTY_LIST; if (!username.equals(params.get("username")))return Stream.empty();
UserModel hardcoded = getUserByUsername(username, realm); UserModel model = getUserByUsername(username, realm);
List<UserModel> list = new LinkedList<>(); return model != null ? Stream.of(model) : Stream.empty();
list.add(hardcoded);
return list;
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
checkForceFail(); checkForceFail();
if (!username.equals(params.get("username")))return Collections.EMPTY_LIST; if (!username.equals(params.get("username")))return Stream.empty();
UserModel hardcoded = getUserByUsername(username, realm); UserModel model = getUserByUsername(username, realm);
List<UserModel> list = new LinkedList<>(); return model != null ? Stream.of(model) : Stream.empty();
list.add(hardcoded);
return list;
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
checkForceFail(); checkForceFail();
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
checkForceFail(); checkForceFail();
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
checkForceFail(); checkForceFail();
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override

View file

@ -40,14 +40,12 @@ import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserRegistrationProvider; import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.Collections; import java.util.Collections;
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.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED; import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
@ -293,49 +291,48 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return userPasswords.keySet().stream() return userPasswords.keySet().stream()
.map(userName -> createUser(realm, userName)) .map(userName -> createUser(realm, userName));
.collect(Collectors.toList());
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return userPasswords.keySet().stream() Stream<String> userStream = userPasswords.keySet().stream().sorted();
.sorted() if (firstResult > 0)
.skip(firstResult) userStream = userStream.skip(firstResult);
.limit(maxResults) if (maxResults >= 0)
.map(userName -> createUser(realm, userName)) userStream = userStream.limit(maxResults);
.collect(Collectors.toList()); return userStream.map(userName -> createUser(realm, userName));
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return userPasswords.keySet().stream() return userPasswords.keySet().stream()
.sorted() .sorted()
.filter(userName -> userName.contains(search)) .filter(userName -> userName.contains(search))
.map(userName -> createUser(realm, userName)) .map(userName -> createUser(realm, userName));
.collect(Collectors.toList());
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
return userPasswords.keySet().stream() Stream<String> userStream = userPasswords.keySet().stream()
.sorted() .sorted()
.filter(userName -> userName.contains(search)) .filter(userName -> userName.contains(search));
.skip(firstResult) if (firstResult > 0)
.limit(maxResults) userStream = userStream.skip(firstResult);
.map(userName -> createUser(realm, userName)) if (maxResults >= 0)
.collect(Collectors.toList()); userStream = userStream.limit(maxResults);
return userStream.map(userName -> createUser(realm, userName));
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) {
return searchForUser(params, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(params, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
Stream<String> userStream = userPasswords.keySet().stream() Stream<String> userStream = userPasswords.keySet().stream()
.sorted(); .sorted();
@ -358,33 +355,31 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
} }
return userStream if (firstResult > 0)
.skip(firstResult) userStream = userStream.skip(firstResult);
.limit(maxResults) if (maxResults >= 0)
.map(userName -> createUser(realm, userName)) userStream = userStream.limit(maxResults);
.collect(Collectors.toList()); return userStream.map(userName -> createUser(realm, userName));
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return getMembership(realm, group, firstResult, maxResults).stream() return getMembershipStream(realm, group, firstResult, maxResults)
.map(userName -> createUser(realm, userName)) .map(userName -> createUser(realm, userName));
.collect(Collectors.toList());
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return getGroupMembers(realm, group, 0, Integer.MAX_VALUE - 1); return getGroupMembersStream(realm, group, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
if (isImportEnabled()) { if (isImportEnabled()) {
return session.userLocalStorage().searchForUserByUserAttribute(attrName, attrValue, realm); return session.userLocalStorage().searchForUserByUserAttributeStream(attrName, attrValue, realm);
} else { } else {
return session.userFederatedStorage().getUsersByUserAttribute(realm, attrName, attrValue).stream() return session.userFederatedStorage().getUsersByUserAttributeStream(realm, attrName, attrValue)
.map(userName -> createUser(realm, userName)) .map(userName -> createUser(realm, userName));
.collect(Collectors.toList());
} }
} }
@ -412,15 +407,17 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max) { public Stream<String> getMembershipStream(RealmModel realm, GroupModel group, int firstResult, int max) {
return userGroups.entrySet().stream() Stream<String> userStream = userGroups.entrySet().stream()
.filter(me -> me.getValue().contains(group.getId())) .filter(me -> me.getValue().contains(group.getId()))
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.filter(realmUser -> realmUser.startsWith(realm.getId())) .filter(realmUser -> realmUser.startsWith(realm.getId()))
.map(realmUser -> realmUser.substring(realmUser.indexOf("/") + 1)) .map(realmUser -> realmUser.substring(realmUser.indexOf("/") + 1));
.skip(firstResult) if (firstResult > 0)
.limit(max) userStream = userStream.skip(firstResult);
.collect(Collectors.toList()); if (max >= 0)
userStream = userStream.limit(max);
return userStream;
} }
@Override @Override

View file

@ -33,13 +33,11 @@ import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
import org.keycloak.storage.user.UserLookupProvider; import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider; import org.keycloak.storage.user.UserQueryProvider;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Properties; import java.util.Properties;
import java.util.function.Predicate; import java.util.function.Predicate;
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>
@ -146,67 +144,59 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
List<UserModel> users = new LinkedList<>(); return userPasswords.keySet().stream().map(obj -> createUser(realm, (String) obj));
for (Object username : userPasswords.keySet()) {
users.add(createUser(realm, (String)username));
}
return users;
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) {
return searchForUser(attributes, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(attributes, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
if (maxResults == 0) return Collections.EMPTY_LIST; Stream<Object> stream = userPasswords.keySet().stream();
List<UserModel> users = new LinkedList<>(); if (firstResult > 0)
int count = 0; stream = stream.skip(firstResult);
for (Object un : userPasswords.keySet()) { if (maxResults >= 0)
if (count++ < firstResult) continue; stream = stream.limit(maxResults);
String username = (String)un; return stream.map(obj -> createUser(realm, (String) obj));
users.add(createUser(realm, username));
if (users.size() + 1 > maxResults) break;
}
return users;
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
return searchForUser(search, realm, firstResult, maxResults, username -> username.contains(search)); return searchForUserStream(search, realm, firstResult, maxResults, username -> username.contains(search));
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
String search = Optional.ofNullable(attributes.get(UserModel.USERNAME)) String search = Optional.ofNullable(attributes.get(UserModel.USERNAME))
.orElseGet(()-> attributes.get(UserModel.SEARCH)); .orElseGet(()-> attributes.get(UserModel.SEARCH));
if (search == null) return Collections.EMPTY_LIST; if (search == null) return Stream.empty();
Predicate<String> p = Boolean.valueOf(attributes.getOrDefault(UserModel.EXACT, Boolean.FALSE.toString())) Predicate<String> p = Boolean.valueOf(attributes.getOrDefault(UserModel.EXACT, Boolean.FALSE.toString()))
? username -> username.equals(search) ? username -> username.equals(search)
: username -> username.contains(search); : username -> username.contains(search);
return searchForUser(search, realm, firstResult, maxResults, p); return searchForUserStream(search, realm, firstResult, maxResults, p);
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1); return searchForUserStream(search, realm, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
return Collections.EMPTY_LIST; return Stream.empty();
} }
@Override @Override
@ -214,20 +204,8 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
} }
private List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults, Predicate<String> matcher) { private Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults, Predicate<String> matcher) {
if (maxResults == 0) return Collections.EMPTY_LIST; return userPasswords.keySet().stream().filter(obj -> matcher.test((String) obj)).skip(firstResult < 0 ? 0 : firstResult)
List<UserModel> users = new LinkedList<>(); .limit(maxResults < 0 ? 0 : maxResults).map(obj -> createUser(realm, (String) obj));
int count = 0;
for (Object un : userPasswords.keySet()) {
String username = (String)un;
if (matcher.test(username)) {
if (count++ < firstResult) {
continue;
}
users.add(createUser(realm, username));
if (users.size() + 1 > maxResults) break;
}
}
return users;
} }
} }

View file

@ -44,7 +44,13 @@ import org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory; import org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory;
import org.keycloak.storage.ldap.mappers.membership.role.RoleMapperConfig; import org.keycloak.storage.ldap.mappers.membership.role.RoleMapperConfig;
import java.util.*; import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
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>
@ -101,21 +107,21 @@ public class LDAPTestUtils {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (UserModel.LAST_NAME.equals(name)) { if (UserModel.LAST_NAME.equals(name)) {
return Collections.singletonList(lastName); return Stream.of(lastName);
} else if (UserModel.FIRST_NAME.equals(name)) { } else if (UserModel.FIRST_NAME.equals(name)) {
return Collections.singletonList(firstName); return Stream.of(firstName);
} else if (UserModel.EMAIL.equals(name)) { } else if (UserModel.EMAIL.equals(name)) {
return Collections.singletonList(email); return Stream.of(email);
} else if (UserModel.USERNAME.equals(name)) { } else if (UserModel.USERNAME.equals(name)) {
return Collections.singletonList(username); return Stream.of(username);
} else if ("postal_code".equals(name) && postalCode != null && postalCode.length > 0) { } else if ("postal_code".equals(name) && postalCode != null && postalCode.length > 0) {
return Arrays.asList(postalCode); return Stream.of(postalCode);
} else if ("street".equals(name) && street != null) { } else if ("street".equals(name) && street != null) {
return Collections.singletonList(street); return Stream.of(street);
} else { } else {
return Collections.emptyList(); return Stream.empty();
} }
} }
}; };

View file

@ -45,6 +45,7 @@ import javax.ws.rs.core.Response;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
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>
@ -227,19 +228,19 @@ public class LDAPBinaryAttributesTest extends AbstractLDAPTest {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (UserModel.LAST_NAME.equals(name)) { if (UserModel.LAST_NAME.equals(name)) {
return Collections.singletonList(lastName); return Stream.of(lastName);
} else if (UserModel.FIRST_NAME.equals(name)) { } else if (UserModel.FIRST_NAME.equals(name)) {
return Collections.singletonList(firstName); return Stream.of(firstName);
} else if (UserModel.EMAIL.equals(name)) { } else if (UserModel.EMAIL.equals(name)) {
return Collections.singletonList(email); return Stream.of(email);
} else if (UserModel.USERNAME.equals(name)) { } else if (UserModel.USERNAME.equals(name)) {
return Collections.singletonList(username); return Stream.of(username);
} else if (LDAPConstants.JPEG_PHOTO.equals(name)) { } else if (LDAPConstants.JPEG_PHOTO.equals(name)) {
return Arrays.asList(jpegPhoto); return Stream.of(jpegPhoto);
} else { } else {
return Collections.emptyList(); return Stream.empty();
} }
} }
}; };

View file

@ -17,8 +17,15 @@
package org.keycloak.testsuite.util.cli; package org.keycloak.testsuite.util.cli;
import java.util.*; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -166,28 +173,26 @@ public class LdapManyObjectsInitializerCommand extends AbstractCommand {
} }
@Override @Override
public List<String> getAttribute(String name) { public Stream<String> getAttributeStream(String name) {
if (UserModel.FIRST_NAME.equals(name)) { if (UserModel.FIRST_NAME.equals(name)) {
return Collections.singletonList(firstName); return Stream.of(firstName);
} else if (UserModel.LAST_NAME.equals(name)) { } else if (UserModel.LAST_NAME.equals(name)) {
return Collections.singletonList(lastName); return Stream.of(lastName);
} else if (UserModel.EMAIL.equals(name)) { } else if (UserModel.EMAIL.equals(name)) {
return Collections.singletonList(email); return Stream.of(email);
} else if (UserModel.USERNAME.equals(name)) { } else if (UserModel.USERNAME.equals(name)) {
return Collections.singletonList(username); return Stream.of(username);
} else if ("street".equals(name)) { } else if ("street".equals(name)) {
Stream.Builder<String> builder = Stream.builder();
List<String> groupNamesList = new ArrayList<>();
for (int i = startOffsetGroups; i < startOffsetGroups + countGroups; i++) { for (int i = startOffsetGroups; i < startOffsetGroups + countGroups; i++) {
String groupName = "group" + i; String groupName = "group" + i;
LDAPDn groupDn = LDAPDn.fromString(groupsDN); LDAPDn groupDn = LDAPDn.fromString(groupsDN);
groupDn.addFirst("cn", groupName); groupDn.addFirst("cn", groupName);
groupNamesList.add(groupDn.toString()); builder.add(groupDn.toString());
} }
return groupNamesList; return builder.build();
} else { } else {
return Collections.emptyList(); return Stream.empty();
} }
} }
}; };