KEYCLOAK-15524 Cleanup user related interfaces

This commit is contained in:
Michal Hajas 2020-12-04 08:33:42 +01:00 committed by Hynek Mlnařík
parent dae4a3eaf2
commit ba8e2fef6b
145 changed files with 1625 additions and 1381 deletions

View file

@ -349,7 +349,7 @@ public class UMAPolicyProviderFactory implements PolicyProviderFactory<UmaPermis
UserPolicyRepresentation rep = UserPolicyRepresentation.class.cast(associatedRep); UserPolicyRepresentation rep = UserPolicyRepresentation.class.cast(associatedRep);
for (String user : rep.getUsers()) { for (String user : rep.getUsers()) {
representation.addUser(authorization.getKeycloakSession().users().getUserById(user, realm).getUsername()); representation.addUser(authorization.getKeycloakSession().users().getUserById(realm, user).getUsername());
} }
} }
} }

View file

@ -119,7 +119,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
UserProvider userProvider = authorizationProvider.getKeycloakSession().users(); UserProvider userProvider = authorizationProvider.getKeycloakSession().users();
RealmModel realm = authorizationProvider.getRealm(); RealmModel realm = authorizationProvider.getRealm();
config.put("users", JsonSerialization.writeValueAsString(userRep.getUsers().stream().map(id -> userProvider.getUserById(id, realm).getUsername()).collect(Collectors.toList()))); config.put("users", JsonSerialization.writeValueAsString(userRep.getUsers().stream().map(id -> userProvider.getUserById(realm, id).getUsername()).collect(Collectors.toList())));
} catch (IOException cause) { } catch (IOException cause) {
throw new RuntimeException("Failed to export user policy [" + policy.getName() + "]", cause); throw new RuntimeException("Failed to export user policy [" + policy.getName() + "]", cause);
} }
@ -142,12 +142,12 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
UserModel user = null; UserModel user = null;
try { try {
user = userProvider.getUserByUsername(userId, realm); user = userProvider.getUserByUsername(realm, userId);
} catch (Exception ignore) { } catch (Exception ignore) {
} }
if (user == null) { if (user == null) {
user = userProvider.getUserById(userId, realm); user = userProvider.getUserById(realm, userId);
} }
if (user == null) { if (user == null) {

View file

@ -48,7 +48,7 @@ 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>
*/ */
public class KerberosFederationProvider implements UserStorageProvider, public class KerberosFederationProvider implements UserStorageProvider,
UserLookupProvider, UserLookupProvider.Streams,
CredentialInputValidator, CredentialInputValidator,
CredentialInputUpdater.Streams, CredentialInputUpdater.Streams,
CredentialAuthentication, CredentialAuthentication,
@ -83,7 +83,7 @@ public class KerberosFederationProvider implements UserStorageProvider,
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
KerberosUsernamePasswordAuthenticator authenticator = factory.createKerberosUsernamePasswordAuthenticator(kerberosConfig); KerberosUsernamePasswordAuthenticator authenticator = factory.createKerberosUsernamePasswordAuthenticator(kerberosConfig);
if (authenticator.isUserAvailable(username)) { if (authenticator.isUserAvailable(username)) {
// Case when method was called with username including kerberos realm like john@REALM.ORG . Authenticator already checked that kerberos realm was correct // Case when method was called with username including kerberos realm like john@REALM.ORG . Authenticator already checked that kerberos realm was correct
@ -98,12 +98,12 @@ public class KerberosFederationProvider implements UserStorageProvider,
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
return null; return null;
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
return null; return null;
} }
@ -234,9 +234,9 @@ public class KerberosFederationProvider implements UserStorageProvider,
* @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider * @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
*/ */
protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) { protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
UserModel user = session.userLocalStorage().getUserByUsername(username, realm); UserModel user = session.userLocalStorage().getUserByUsername(realm, username);
if (user != null) { if (user != null) {
user = session.users().getUserById(user.getId(), realm); // make sure we get a cached instance user = session.users().getUserById(realm, user.getId()); // make sure we get a cached instance
logger.debug("Kerberos authenticated user " + username + " found in Keycloak storage"); logger.debug("Kerberos authenticated user " + username + " found in Keycloak storage");
if (!model.getId().equals(user.getFederationLink())) { if (!model.getId().equals(user.getFederationLink())) {

View file

@ -79,6 +79,8 @@ import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider; import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserRegistrationProvider; import org.keycloak.storage.user.UserRegistrationProvider;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -88,11 +90,12 @@ public class LDAPStorageProvider implements UserStorageProvider,
CredentialInputValidator, CredentialInputValidator,
CredentialInputUpdater.Streams, CredentialInputUpdater.Streams,
CredentialAuthentication, CredentialAuthentication,
UserLookupProvider, UserLookupProvider.Streams,
UserRegistrationProvider, UserRegistrationProvider,
UserQueryProvider.Streams, UserQueryProvider.Streams,
ImportedUserValidation { ImportedUserValidation {
private static final Logger logger = Logger.getLogger(LDAPStorageProvider.class); private static final Logger logger = Logger.getLogger(LDAPStorageProvider.class);
private static final int DEFAULT_MAX_RESULTS = Integer.MAX_VALUE >> 1;
protected LDAPStorageProviderFactory factory; protected LDAPStorageProviderFactory factory;
protected KeycloakSession session; protected KeycloakSession session;
@ -176,7 +179,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
// We need to avoid having CachedUserModel as cache is upper-layer then LDAP. Hence having CachedUserModel here may cause StackOverflowError // We need to avoid having CachedUserModel as cache is upper-layer then LDAP. Hence having CachedUserModel here may cause StackOverflowError
if (local instanceof CachedUserModel) { if (local instanceof CachedUserModel) {
local = session.userStorageManager().getUserById(local.getId(), realm); local = session.userStorageManager().getUserById(realm, local.getId());
existing = userManager.getManagedProxiedUser(local.getId()); existing = userManager.getManagedProxiedUser(local.getId());
if (existing != null) { if (existing != null) {
@ -245,7 +248,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
@Override @Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
try (LDAPQuery ldapQuery = LDAPUtils.createQueryForUserSearch(this, realm)) { try (LDAPQuery ldapQuery = LDAPUtils.createQueryForUserSearch(this, realm)) {
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
@ -256,7 +259,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
return ldapObjects.stream().map(ldapUser -> { return ldapObjects.stream().map(ldapUser -> {
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(realm, ldapUsername);
if (localUser == null) { if (localUser == null) {
return importUserFromLDAP(session, realm, ldapUser); return importUserFromLDAP(session, realm, ldapUser);
} else { } else {
@ -323,12 +326,12 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
UserModel alreadyLoadedInSession = userManager.getManagedProxiedUser(id); UserModel alreadyLoadedInSession = userManager.getManagedProxiedUser(id);
if (alreadyLoadedInSession != null) return alreadyLoadedInSession; if (alreadyLoadedInSession != null) return alreadyLoadedInSession;
StorageId storageId = new StorageId(id); StorageId storageId = new StorageId(id);
return getUserByUsername(storageId.getExternalId(), realm); return getUserByUsername(realm, storageId.getExternalId());
} }
@Override @Override
@ -342,29 +345,20 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
return Stream.empty(); return Stream.empty();
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
return searchForUserStream(search, realm, 0, Integer.MAX_VALUE - 1);
}
@Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer 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 searchForUserStream(attributes, realm, firstResult, maxResults); return searchForUserStream(realm, attributes, firstResult, maxResults);
} }
@Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) {
return searchForUserStream(params, realm, 0, Integer.MAX_VALUE - 1);
}
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params, Integer firstResult, Integer 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(' ');
@ -385,41 +379,34 @@ public class LDAPStorageProvider implements UserStorageProvider,
Stream<LDAPObject> stream = searchLDAP(realm, params).stream() Stream<LDAPObject> stream = searchLDAP(realm, params).stream()
.filter(ldapObject -> { .filter(ldapObject -> {
String ldapUsername = LDAPUtils.getUsername(ldapObject, this.ldapIdentityStore.getConfig()); String ldapUsername = LDAPUtils.getUsername(ldapObject, this.ldapIdentityStore.getConfig());
return (session.userLocalStorage().getUserByUsername(ldapUsername, realm) == null); return (session.userLocalStorage().getUserByUsername(realm, ldapUsername) == null);
}); });
if (firstResult > 0)
stream = stream.skip(firstResult);
if (maxResults >= 0)
stream = stream.limit(maxResults);
return stream.map(ldapObject -> importUserFromLDAP(session, realm, ldapObject));
}
@Override return paginatedStream(stream, firstResult, maxResults).map(ldapObject -> importUserFromLDAP(session, realm, ldapObject));
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return getGroupMembersStream(realm, group, 0, Integer.MAX_VALUE - 1);
} }
@Override @Override
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) {
int first = firstResult == null ? 0 : firstResult;
int max = maxResults == null ? DEFAULT_MAX_RESULTS : maxResults;
return realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName()) return realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
.sorted(ldapMappersComparator.sortAsc()) .sorted(ldapMappersComparator.sortAsc())
.map(mapperModel -> .map(mapperModel ->
mapperManager.getMapper(mapperModel).getGroupMembers(realm, group, firstResult, maxResults)) mapperManager.getMapper(mapperModel).getGroupMembers(realm, group, first, max))
.filter(((Predicate<List>) List::isEmpty).negate()) .filter(((Predicate<List>) List::isEmpty).negate())
.map(List::stream) .map(List::stream)
.findFirst().orElse(Stream.empty()); .findFirst().orElse(Stream.empty());
} }
@Override
public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
return getRoleMembersStream(realm, role, 0, Integer.MAX_VALUE - 1);
}
@Override @Override
public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) { public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) {
int first = firstResult == null ? 0 : firstResult;
int max = maxResults == null ? DEFAULT_MAX_RESULTS : maxResults;
return realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName()) return realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
.sorted(ldapMappersComparator.sortAsc()) .sorted(ldapMappersComparator.sortAsc())
.map(mapperModel -> mapperManager.getMapper(mapperModel).getRoleMembers(realm, role, firstResult, maxResults)) .map(mapperModel -> mapperManager.getMapper(mapperModel).getRoleMembers(realm, role, first, max))
.filter(((Predicate<List>) List::isEmpty).negate()) .filter(((Predicate<List>) List::isEmpty).negate())
.map(List::stream) .map(List::stream)
.findFirst().orElse(Stream.empty()); .findFirst().orElse(Stream.empty());
@ -428,7 +415,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
public List<UserModel> loadUsersByUsernames(List<String> usernames, RealmModel realm) { public List<UserModel> loadUsersByUsernames(List<String> usernames, RealmModel realm) {
List<UserModel> result = new ArrayList<>(); List<UserModel> result = new ArrayList<>();
for (String username : usernames) { for (String username : usernames) {
UserModel kcUser = session.users().getUserByUsername(username, realm); UserModel kcUser = session.users().getUserByUsername(realm, username);
if (kcUser == null) { if (kcUser == null) {
logger.warnf("User '%s' referenced by membership wasn't found in LDAP", username); logger.warnf("User '%s' referenced by membership wasn't found in LDAP", username);
} else if (model.isImportEnabled() && !model.getId().equals(kcUser.getFederationLink())) { } else if (model.isImportEnabled() && !model.getId().equals(kcUser.getFederationLink())) {
@ -514,7 +501,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
LDAPObject ldapUser = loadLDAPUserByUsername(realm, username); LDAPObject ldapUser = loadLDAPUserByUsername(realm, username);
if (ldapUser == null) { if (ldapUser == null) {
return null; return null;
@ -575,7 +562,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
LDAPObject ldapUser = queryByEmail(realm, email); LDAPObject ldapUser = queryByEmail(realm, email);
if (ldapUser == null) { if (ldapUser == null) {
return null; return null;
@ -583,7 +570,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
// Check here if user already exists // Check here if user already exists
String ldapUsername = LDAPUtils.getUsername(ldapUser, ldapIdentityStore.getConfig()); String ldapUsername = LDAPUtils.getUsername(ldapUser, ldapIdentityStore.getConfig());
UserModel user = session.userLocalStorage().getUserByUsername(ldapUsername, realm); UserModel user = session.userLocalStorage().getUserByUsername(realm, ldapUsername);
if (user != null) { if (user != null) {
LDAPUtils.checkUuid(ldapUser, ldapIdentityStore.getConfig()); LDAPUtils.checkUuid(ldapUser, ldapIdentityStore.getConfig());
@ -771,7 +758,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
* @return finded or newly created user * @return finded or newly created user
*/ */
protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) { protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
UserModel user = session.userLocalStorage().getUserByUsername(username, realm); UserModel user = session.userLocalStorage().getUserByUsername(realm, username);
if (user != null) { if (user != null) {
logger.debugf("Kerberos authenticated user [%s] found in Keycloak storage", username); logger.debugf("Kerberos authenticated user [%s] found in Keycloak storage", username);
if (!model.getId().equals(user.getFederationLink())) { if (!model.getId().equals(user.getFederationLink())) {
@ -796,7 +783,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
// Creating user to local storage // Creating user to local storage
logger.debugf("Kerberos authenticated user [%s] not in Keycloak storage. Creating him", username); logger.debugf("Kerberos authenticated user [%s] not in Keycloak storage. Creating him", username);
return getUserByUsername(username, realm); return getUserByUsername(realm, username);
} }
public LDAPObject loadLDAPUserByUsername(RealmModel realm, String username) { public LDAPObject loadLDAPUserByUsername(RealmModel realm, String username) {

View file

@ -593,7 +593,7 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
String username = LDAPUtils.getUsername(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig()); String username = LDAPUtils.getUsername(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
exists.value = true; exists.value = true;
LDAPUtils.checkUuid(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig()); LDAPUtils.checkUuid(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
UserModel currentUser = session.userLocalStorage().getUserByUsername(username, currentRealm); UserModel currentUser = session.userLocalStorage().getUserByUsername(currentRealm, username);
if (currentUser == null) { if (currentUser == null) {
@ -649,7 +649,7 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
} }
if (username != null) { if (username != null) {
UserModel existing = session.userLocalStorage().getUserByUsername(username, currentRealm); UserModel existing = session.userLocalStorage().getUserByUsername(currentRealm, username);
if (existing != null) { if (existing != null) {
UserCache userCache = session.userCache(); UserCache userCache = session.userCache();
if (userCache != null) { if (userCache != null) {

View file

@ -149,7 +149,7 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
// lowercase before search // lowercase before search
email = KeycloakModelUtils.toLowerCaseSafe(email); email = KeycloakModelUtils.toLowerCaseSafe(email);
UserModel that = session.userLocalStorage().getUserByEmail(email, realm); UserModel that = session.userLocalStorage().getUserByEmail(realm, email);
if (that != null && !that.getId().equals(user.getId())) { if (that != null && !that.getId().equals(user.getId())) {
session.getTransactionManager().setRollbackOnly(); session.getTransactionManager().setRollbackOnly();
String exceptionMessage = String.format("Can't import user '%s' from LDAP because email '%s' already exists in Keycloak. Existing user with this email is '%s'", user.getUsername(), email, that.getUsername()); String exceptionMessage = String.format("Can't import user '%s' from LDAP because email '%s' already exists in Keycloak. Existing user with this email is '%s'", user.getUsername(), email, that.getUsername());
@ -166,7 +166,7 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
} }
boolean usernameChanged = !username.equals(user.getUsername()); boolean usernameChanged = !username.equals(user.getUsername());
if (realm.isEditUsernameAllowed() && usernameChanged) { if (realm.isEditUsernameAllowed() && usernameChanged) {
UserModel that = session.users().getUserByUsername(username, realm); UserModel that = session.users().getUserByUsername(realm, username);
if (that != null && !that.getId().equals(user.getId())) { if (that != null && !that.getId().equals(user.getId())) {
throw new ModelDuplicateException( throw new ModelDuplicateException(
String.format("Cannot change the username to '%s' because the username already exists in keycloak", username), String.format("Cannot change the username to '%s' because the username already exists in keycloak", username),

View file

@ -44,7 +44,7 @@ import java.util.stream.Stream;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SSSDFederationProvider implements UserStorageProvider, public class SSSDFederationProvider implements UserStorageProvider,
UserLookupProvider, UserLookupProvider.Streams,
CredentialInputUpdater.Streams, CredentialInputUpdater.Streams,
CredentialInputValidator, CredentialInputValidator,
ImportedUserValidation { ImportedUserValidation {
@ -68,7 +68,7 @@ public class SSSDFederationProvider implements UserStorageProvider,
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
return findOrCreateAuthenticatedUser(realm, username); return findOrCreateAuthenticatedUser(realm, username);
} }
@ -85,7 +85,7 @@ public class SSSDFederationProvider implements UserStorageProvider,
* @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider * @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
*/ */
protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) { protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
UserModel user = session.userLocalStorage().getUserByUsername(username, realm); UserModel user = session.userLocalStorage().getUserByUsername(realm, username);
if (user != null) { if (user != null) {
logger.debug("SSSD authenticated user " + username + " found in Keycloak storage"); logger.debug("SSSD authenticated user " + username + " found in Keycloak storage");
@ -130,12 +130,12 @@ public class SSSDFederationProvider implements UserStorageProvider,
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
return null; return null;
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
return null; return null;
} }

View file

@ -380,6 +380,6 @@ public class UserAdapter implements CachedUserModel.Streams {
} }
private UserModel getUserModel() { private UserModel getUserModel() {
return userProviderCache.getDelegate().getUserById(cached.getId(), realm); return userProviderCache.getDelegate().getUserById(realm, cached.getId());
} }
} }

View file

@ -183,11 +183,11 @@ public class UserCacheSession implements UserCache.Streams {
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
logger.tracev("getuserById {0}", id); logger.tracev("getuserById {0}", id);
if (isRegisteredForInvalidation(realm, id)) { if (isRegisteredForInvalidation(realm, id)) {
logger.trace("registered for invalidation return delegate"); logger.trace("registered for invalidation return delegate");
return getDelegate().getUserById(id, realm); return getDelegate().getUserById(realm, id);
} }
if (managedUsers.containsKey(id)) { if (managedUsers.containsKey(id)) {
logger.trace("return managedusers"); logger.trace("return managedusers");
@ -204,7 +204,7 @@ public class UserCacheSession implements UserCache.Streams {
if (cached == null) { if (cached == null) {
logger.trace("not cached"); logger.trace("not cached");
Long loaded = cache.getCurrentRevision(id); Long loaded = cache.getCurrentRevision(id);
UserModel delegate = getDelegate().getUserById(id, realm); UserModel delegate = getDelegate().getUserById(realm, id);
if (delegate == null) { if (delegate == null) {
logger.trace("delegate returning null"); logger.trace("delegate returning null");
return null; return null;
@ -238,17 +238,17 @@ public class UserCacheSession implements UserCache.Streams {
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
logger.tracev("getUserByUsername: {0}", username); logger.tracev("getUserByUsername: {0}", username);
username = username.toLowerCase(); username = username.toLowerCase();
if (realmInvalidations.contains(realm.getId())) { if (realmInvalidations.contains(realm.getId())) {
logger.tracev("realmInvalidations"); logger.tracev("realmInvalidations");
return getDelegate().getUserByUsername(username, realm); return getDelegate().getUserByUsername(realm, username);
} }
String cacheKey = getUserByUsernameCacheKey(realm.getId(), username); String cacheKey = getUserByUsernameCacheKey(realm.getId(), username);
if (invalidations.contains(cacheKey)) { if (invalidations.contains(cacheKey)) {
logger.tracev("invalidations"); logger.tracev("invalidations");
return getDelegate().getUserByUsername(username, realm); return getDelegate().getUserByUsername(realm, username);
} }
UserListQuery query = cache.get(cacheKey, UserListQuery.class); UserListQuery query = cache.get(cacheKey, UserListQuery.class);
@ -256,7 +256,7 @@ public class UserCacheSession implements UserCache.Streams {
if (query == null) { if (query == null) {
logger.tracev("query null"); logger.tracev("query null");
Long loaded = cache.getCurrentRevision(cacheKey); Long loaded = cache.getCurrentRevision(cacheKey);
UserModel model = getDelegate().getUserByUsername(username, realm); UserModel model = getDelegate().getUserByUsername(realm, username);
if (model == null) { if (model == null) {
logger.tracev("model from delegate null"); logger.tracev("model from delegate null");
return null; return null;
@ -279,11 +279,11 @@ public class UserCacheSession implements UserCache.Streams {
userId = query.getUsers().iterator().next(); userId = query.getUsers().iterator().next();
if (invalidations.contains(userId)) { if (invalidations.contains(userId)) {
logger.tracev("invalidated cache return delegate"); logger.tracev("invalidated cache return delegate");
return getDelegate().getUserByUsername(username, realm); return getDelegate().getUserByUsername(realm, username);
} }
logger.trace("return getUserById"); logger.trace("return getUserById");
return getUserById(userId, realm); return getUserById(realm, userId);
} }
} }
@ -312,7 +312,7 @@ public class UserCacheSession implements UserCache.Streams {
// its also hard to test stuff // its also hard to test stuff
if (model.shouldInvalidate(cached)) { if (model.shouldInvalidate(cached)) {
registerUserInvalidation(realm, cached); registerUserInvalidation(realm, cached);
return getDelegate().getUserById(cached.getId(), realm); return getDelegate().getUserById(realm, cached.getId());
} }
} }
return new UserAdapter(cached, this, session, realm); return new UserAdapter(cached, this, session, realm);
@ -368,22 +368,22 @@ public class UserCacheSession implements UserCache.Streams {
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
if (email == null) return null; if (email == null) return null;
email = email.toLowerCase(); email = email.toLowerCase();
if (realmInvalidations.contains(realm.getId())) { if (realmInvalidations.contains(realm.getId())) {
return getDelegate().getUserByEmail(email, realm); return getDelegate().getUserByEmail(realm, email);
} }
String cacheKey = getUserByEmailCacheKey(realm.getId(), email); String cacheKey = getUserByEmailCacheKey(realm.getId(), email);
if (invalidations.contains(cacheKey)) { if (invalidations.contains(cacheKey)) {
return getDelegate().getUserByEmail(email, realm); return getDelegate().getUserByEmail(realm, email);
} }
UserListQuery query = cache.get(cacheKey, UserListQuery.class); UserListQuery query = cache.get(cacheKey, UserListQuery.class);
String userId = null; String userId = null;
if (query == null) { if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey); Long loaded = cache.getCurrentRevision(cacheKey);
UserModel model = getDelegate().getUserByEmail(email, realm); UserModel model = getDelegate().getUserByEmail(realm, email);
if (model == null) return null; if (model == null) return null;
userId = model.getId(); userId = model.getId();
if (invalidations.contains(userId)) return model; if (invalidations.contains(userId)) return model;
@ -399,10 +399,10 @@ public class UserCacheSession implements UserCache.Streams {
} else { } else {
userId = query.getUsers().iterator().next(); userId = query.getUsers().iterator().next();
if (invalidations.contains(userId)) { if (invalidations.contains(userId)) {
return getDelegate().getUserByEmail(email, realm); return getDelegate().getUserByEmail(realm, email);
} }
return getUserById(userId, realm); return getUserById(realm, userId);
} }
} }
@ -412,23 +412,23 @@ public class UserCacheSession implements UserCache.Streams {
} }
@Override @Override
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) { public UserModel getUserByFederatedIdentity(RealmModel realm, FederatedIdentityModel socialLink) {
if (socialLink == null) return null; if (socialLink == null) return null;
if (!realm.isIdentityFederationEnabled()) return null; if (!realm.isIdentityFederationEnabled()) return null;
if (realmInvalidations.contains(realm.getId())) { if (realmInvalidations.contains(realm.getId())) {
return getDelegate().getUserByFederatedIdentity(socialLink, realm); return getDelegate().getUserByFederatedIdentity(realm, socialLink);
} }
String cacheKey = getUserByFederatedIdentityCacheKey(realm.getId(), socialLink); String cacheKey = getUserByFederatedIdentityCacheKey(realm.getId(), socialLink);
if (invalidations.contains(cacheKey)) { if (invalidations.contains(cacheKey)) {
return getDelegate().getUserByFederatedIdentity(socialLink, realm); return getDelegate().getUserByFederatedIdentity(realm, socialLink);
} }
UserListQuery query = cache.get(cacheKey, UserListQuery.class); UserListQuery query = cache.get(cacheKey, UserListQuery.class);
String userId = null; String userId = null;
if (query == null) { if (query == null) {
Long loaded = cache.getCurrentRevision(cacheKey); Long loaded = cache.getCurrentRevision(cacheKey);
UserModel model = getDelegate().getUserByFederatedIdentity(socialLink, realm); UserModel model = getDelegate().getUserByFederatedIdentity(realm, socialLink);
if (model == null) return null; if (model == null) return null;
userId = model.getId(); userId = model.getId();
if (invalidations.contains(userId)) return model; if (invalidations.contains(userId)) return model;
@ -446,10 +446,10 @@ public class UserCacheSession implements UserCache.Streams {
userId = query.getUsers().iterator().next(); userId = query.getUsers().iterator().next();
if (invalidations.contains(userId)) { if (invalidations.contains(userId)) {
invalidations.add(cacheKey); invalidations.add(cacheKey);
return getDelegate().getUserByFederatedIdentity(socialLink, realm); return getDelegate().getUserByFederatedIdentity(realm, socialLink);
} }
return getUserById(userId, realm); return getUserById(realm, userId);
} }
} }
@ -527,11 +527,11 @@ public class UserCacheSession implements UserCache.Streams {
userId = query.getUsers().iterator().next(); userId = query.getUsers().iterator().next();
if (invalidations.contains(userId)) { if (invalidations.contains(userId)) {
logger.tracev("invalidated cache return delegate"); logger.tracev("invalidated cache return delegate");
return getDelegate().getUserByUsername(username, realm); return getDelegate().getUserByUsername(realm, username);
} }
logger.trace("return getUserById"); logger.trace("return getUserById");
return getUserById(userId, realm); return getUserById(realm, userId);
} }
} }
@ -545,34 +545,29 @@ public class UserCacheSession implements UserCache.Streams {
return getDelegate().getUsersCount(realm, includeServiceAccount); return getDelegate().getUsersCount(realm, includeServiceAccount);
} }
@Override
public int getUsersCount(RealmModel realm) {
return getUsersCount(realm, false);
}
@Override @Override
public int getUsersCount(RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, Set<String> groupIds) {
return getDelegate().getUsersCount(realm, groupIds); return getDelegate().getUsersCount(realm, groupIds);
} }
@Override @Override
public int getUsersCount(String search, RealmModel realm) { public int getUsersCount(RealmModel realm, String search) {
return getDelegate().getUsersCount(search, realm); return getDelegate().getUsersCount(realm, search);
} }
@Override @Override
public int getUsersCount(String search, RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, String search, Set<String> groupIds) {
return getDelegate().getUsersCount(search, realm, groupIds); return getDelegate().getUsersCount(realm, search, groupIds);
} }
@Override @Override
public int getUsersCount(Map<String, String> params, RealmModel realm) { public int getUsersCount(RealmModel realm, Map<String, String> params) {
return getDelegate().getUsersCount(params, realm); return getDelegate().getUsersCount(realm, params);
} }
@Override @Override
public int getUsersCount(Map<String, String> params, RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, Map<String, String> params, Set<String> groupIds) {
return getDelegate().getUsersCount(params, realm, groupIds); return getDelegate().getUsersCount(realm, params, groupIds);
} }
@Override @Override
@ -586,49 +581,49 @@ public class UserCacheSession implements UserCache.Streams {
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
return getUsersStream(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search) {
return getDelegate().searchForUserStream(search, realm); return getDelegate().searchForUserStream(realm, search);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
return getDelegate().searchForUserStream(search, realm, firstResult, maxResults); return getDelegate().searchForUserStream(realm, search, firstResult, maxResults);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> attributes) {
return getDelegate().searchForUserStream(attributes, realm); return getDelegate().searchForUserStream(realm, attributes);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> attributes, Integer firstResult, Integer maxResults) {
return getDelegate().searchForUserStream(attributes, realm, firstResult, maxResults); return getDelegate().searchForUserStream(realm, attributes, firstResult, maxResults);
} }
@Override @Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
return getDelegate().searchForUserByUserAttributeStream(attrName, attrValue, realm); return getDelegate().searchForUserByUserAttributeStream(realm, attrName, attrValue);
} }
@Override @Override
public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user) {
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().getFederatedIdentitiesStream(user, realm); return getDelegate().getFederatedIdentitiesStream(realm, user);
} }
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().getFederatedIdentitiesStream(user, realm) Set<FederatedIdentityModel> federatedIdentities = getDelegate().getFederatedIdentitiesStream(realm, user)
.collect(Collectors.toSet()); .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);
@ -639,15 +634,15 @@ public class UserCacheSession implements UserCache.Streams {
} }
@Override @Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) { public FederatedIdentityModel getFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
logger.tracev("getFederatedIdentity: {0} {1}", user.getUsername(), socialProvider); logger.tracev("getFederatedIdentity: {0} {1}", user.getUsername(), socialProvider);
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().getFederatedIdentity(user, socialProvider, realm); return getDelegate().getFederatedIdentity(realm, user, socialProvider);
} }
return getFederatedIdentitiesStream(user, realm) return getFederatedIdentitiesStream(realm, user)
.filter(socialLink -> Objects.equals(socialLink.getIdentityProvider(), socialProvider)) .filter(socialLink -> Objects.equals(socialLink.getIdentityProvider(), socialProvider))
.findFirst().orElse(null); .findFirst().orElse(null);
} }
@ -748,7 +743,7 @@ public class UserCacheSession implements UserCache.Streams {
@Override @Override
public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) { public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) {
if (!isRegisteredForInvalidation(realm, user.getId())) { if (!isRegisteredForInvalidation(realm, user.getId())) {
UserModel foundUser = getUserById(user.getId(), realm); UserModel foundUser = getUserById(realm, user.getId());
if (foundUser instanceof UserAdapter) { if (foundUser instanceof UserAdapter) {
((UserAdapter) foundUser).invalidate(); ((UserAdapter) foundUser).invalidate();
} }
@ -764,7 +759,7 @@ public class UserCacheSession implements UserCache.Streams {
return getDelegate().getNotBeforeOfUser(realm, user); return getDelegate().getNotBeforeOfUser(realm, user);
} }
UserModel foundUser = getUserById(user.getId(), realm); UserModel foundUser = getUserById(realm, user.getId());
if (foundUser instanceof UserAdapter) { if (foundUser instanceof UserAdapter) {
return ((UserAdapter) foundUser).cached.getNotBefore(); return ((UserAdapter) foundUser).cached.getNotBefore();
} else { } else {
@ -793,7 +788,7 @@ public class UserCacheSession implements UserCache.Streams {
// just in case the transaction is rolled back you need to invalidate the user and all cache queries for that user // just in case the transaction is rolled back you need to invalidate the user and all cache queries for that user
protected void fullyInvalidateUser(RealmModel realm, UserModel user) { protected void fullyInvalidateUser(RealmModel realm, UserModel user) {
Stream<FederatedIdentityModel> federatedIdentities = realm.isIdentityFederationEnabled() ? Stream<FederatedIdentityModel> federatedIdentities = realm.isIdentityFederationEnabled() ?
getFederatedIdentitiesStream(user, realm) : Stream.empty(); getFederatedIdentitiesStream(realm, user) : Stream.empty();
UserFullInvalidationEvent event = UserFullInvalidationEvent.create(user.getId(), user.getUsername(), user.getEmail(), realm.getId(), realm.isIdentityFederationEnabled(), federatedIdentities); UserFullInvalidationEvent event = UserFullInvalidationEvent.create(user.getId(), user.getUsername(), user.getEmail(), realm.getId(), realm.isIdentityFederationEnabled(), federatedIdentities);
@ -827,7 +822,7 @@ public class UserCacheSession implements UserCache.Streams {
@Override @Override
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) { public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
// Needs to invalidate both directions // Needs to invalidate both directions
FederatedIdentityModel socialLink = getFederatedIdentity(user, socialProvider, realm); FederatedIdentityModel socialLink = getFederatedIdentity(realm, user, socialProvider);
UserFederationLinkRemovedEvent event = UserFederationLinkRemovedEvent.create(user.getId(), realm.getId(), socialLink); UserFederationLinkRemovedEvent event = UserFederationLinkRemovedEvent.create(user.getId(), realm.getId(), socialLink);
cache.federatedIdentityLinkRemovedInvalidation(user.getId(), realm.getId(), event.getIdentityProviderId(), event.getSocialUserId(), invalidations); cache.federatedIdentityLinkRemovedInvalidation(user.getId(), realm.getId(), event.getIdentityProviderId(), event.getSocialUserId(), invalidations);

View file

@ -282,7 +282,7 @@ public class AuthenticationSessionAdapter implements AuthenticationSessionModel
@Override @Override
public UserModel getAuthenticatedUser() { public UserModel getAuthenticatedUser() {
return entity.getAuthUserId() == null ? null : session.users().getUserById(entity.getAuthUserId(), getRealm()); } return entity.getAuthUserId() == null ? null : session.users().getUserById(getRealm(), entity.getAuthUserId()); }
@Override @Override
public void setAuthenticatedUser(UserModel user) { public void setAuthenticatedUser(UserModel user) {

View file

@ -175,7 +175,7 @@ public class UserSessionAdapter implements UserSessionModel {
return entity.getBrokerUserId(); return entity.getBrokerUserId();
} }
public UserModel getUser() { public UserModel getUser() {
return session.users().getUserById(entity.getUser(), realm); return session.users().getUserById(realm, entity.getUser());
} }
@Override @Override

View file

@ -57,6 +57,7 @@ import java.util.stream.Stream;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.models.jpa.PaginationUtils.paginateQuery;
import static org.keycloak.utils.StreamsUtil.closing; import static org.keycloak.utils.StreamsUtil.closing;
@ -288,12 +289,7 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
} }
protected Stream<RoleModel> getRolesStream(TypedQuery<RoleEntity> query, RealmModel realm, Integer first, Integer max) { protected Stream<RoleModel> getRolesStream(TypedQuery<RoleEntity> query, RealmModel realm, Integer first, Integer max) {
if(Objects.nonNull(first) && Objects.nonNull(max) Stream<RoleEntity> results = paginateQuery(query, first, max).getResultStream();
&& first >= 0 && max >= 0) {
query= query.setFirstResult(first).setMaxResults(max);
}
Stream<RoleEntity> results = query.getResultStream();
return closing(results.map(role -> new RoleAdapter(session, realm, em, role))); return closing(results.map(role -> new RoleAdapter(session, realm, em, role)));
} }
@ -452,18 +448,6 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
.map(g -> session.groups().getGroupById(realm, g)); .map(g -> session.groups().getGroupById(realm, g));
} }
private static <T> TypedQuery<T> paginateQuery(TypedQuery<T> query, Integer first, Integer max) {
if (first != null && first > 0) {
query = query.setFirstResult(first);
}
if (max != null && max >= 0) {
query = query.setMaxResults(max);
}
return query;
}
@Override @Override
public Stream<GroupModel> getGroupsStream(RealmModel realm, Stream<String> ids) { public Stream<GroupModel> getGroupsStream(RealmModel realm, Stream<String> ids) {
return ids.map(id -> session.groups().getGroupById(realm, id)).sorted(GroupModel.COMPARE_BY_NAME); return ids.map(id -> session.groups().getGroupById(realm, id)).sorted(GroupModel.COMPARE_BY_NAME);
@ -515,13 +499,8 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
public Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) { public Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) {
TypedQuery<GroupEntity> query = em.createNamedQuery("groupsInRole", GroupEntity.class); TypedQuery<GroupEntity> query = em.createNamedQuery("groupsInRole", GroupEntity.class);
query.setParameter("roleId", role.getId()); query.setParameter("roleId", role.getId());
if (firstResult != null && firstResult > 0) {
query = query.setFirstResult(firstResult); Stream<GroupEntity> results = paginateQuery(query, firstResult, maxResults).getResultStream();
}
if (maxResults != null && maxResults > 0) {
query = query.setMaxResults(maxResults);
}
Stream<GroupEntity> results = query.getResultStream();
return closing(results return closing(results
.map(g -> (GroupModel) new GroupAdapter(realm, em, g)) .map(g -> (GroupModel) new GroupAdapter(realm, em, g))
@ -657,14 +636,9 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
@Override @Override
public Stream<ClientModel> getClientsStream(RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<ClientModel> getClientsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
TypedQuery<String> query = em.createNamedQuery("getClientIdsByRealm", String.class); TypedQuery<String> query = em.createNamedQuery("getClientIdsByRealm", String.class);
if (firstResult != null && firstResult > 0) {
query.setFirstResult(firstResult);
}
if (maxResults != null && maxResults > 0) {
query.setMaxResults(maxResults);
}
query.setParameter("realm", realm.getId()); query.setParameter("realm", realm.getId());
Stream<String> clients = query.getResultStream(); Stream<String> clients = paginateQuery(query, firstResult, maxResults).getResultStream();
return closing(clients.map(c -> session.clients().getClientById(realm, c)).filter(Objects::nonNull)); return closing(clients.map(c -> session.clients().getClientById(realm, c)).filter(Objects::nonNull));
} }
@ -706,15 +680,10 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
@Override @Override
public Stream<ClientModel> searchClientsByClientIdStream(RealmModel realm, String clientId, Integer firstResult, Integer maxResults) { public Stream<ClientModel> searchClientsByClientIdStream(RealmModel realm, String clientId, Integer firstResult, Integer maxResults) {
TypedQuery<String> query = em.createNamedQuery("searchClientsByClientId", String.class); TypedQuery<String> query = em.createNamedQuery("searchClientsByClientId", String.class);
if (firstResult != null && firstResult > 0) {
query.setFirstResult(firstResult);
}
if (maxResults != null && maxResults > 0) {
query.setMaxResults(maxResults);
}
query.setParameter("clientId", clientId); query.setParameter("clientId", clientId);
query.setParameter("realm", realm.getId()); query.setParameter("realm", realm.getId());
Stream<String> results = query.getResultStream();
Stream<String> results = paginateQuery(query, firstResult, maxResults).getResultStream();
return closing(results.map(c -> session.clients().getClientById(realm, c))); return closing(results.map(c -> session.clients().getClientById(realm, c)));
} }

View file

@ -65,12 +65,12 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.persistence.LockModeType; import javax.persistence.LockModeType;
import static org.keycloak.models.jpa.PaginationUtils.paginateQuery;
import static org.keycloak.utils.StreamsUtil.closing; import static org.keycloak.utils.StreamsUtil.closing;
@ -97,18 +97,6 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
credentialStore = new JpaUserCredentialStore(session, em); credentialStore = new JpaUserCredentialStore(session, em);
} }
private static <T> TypedQuery<T> paginateQuery(TypedQuery<T> query, Integer first, Integer max) {
if (first != null && first > 0) {
query = query.setFirstResult(first);
}
if (max != null && max >= 0) {
query = query.setMaxResults(max);
}
return query;
}
@Override @Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) { public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
if (id == null) { if (id == null) {
@ -364,12 +352,18 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
@Override @Override
public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) { public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) {
UserEntity entity = em.getReference(UserEntity.class, user.getId()); UserEntity entity = em.getReference(UserEntity.class, user.getId());
if (entity == null) {
throw new ModelException("User does not exists");
}
entity.setNotBefore(notBefore); entity.setNotBefore(notBefore);
} }
@Override @Override
public int getNotBeforeOfUser(RealmModel realm, UserModel user) { public int getNotBeforeOfUser(RealmModel realm, UserModel user) {
UserEntity entity = em.getReference(UserEntity.class, user.getId()); UserEntity entity = em.getReference(UserEntity.class, user.getId());
if (entity == null) {
throw new ModelException("User does not exists");
}
return entity.getNotBefore(); return entity.getNotBefore();
} }
@ -514,14 +508,14 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
UserEntity userEntity = em.find(UserEntity.class, id); UserEntity userEntity = em.find(UserEntity.class, id);
if (userEntity == null || !realm.getId().equals(userEntity.getRealmId())) return null; if (userEntity == null || !realm.getId().equals(userEntity.getRealmId())) return null;
return new UserAdapter(session, realm, em, userEntity); return new UserAdapter(session, realm, em, userEntity);
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByUsername", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByUsername", UserEntity.class);
query.setParameter("username", username.toLowerCase()); query.setParameter("username", username.toLowerCase());
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
@ -531,7 +525,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class);
query.setParameter("email", email.toLowerCase()); query.setParameter("email", email.toLowerCase());
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
@ -549,7 +543,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public UserModel getUserByFederatedIdentity(FederatedIdentityModel identity, RealmModel realm) { public UserModel getUserByFederatedIdentity(RealmModel realm, FederatedIdentityModel identity) {
TypedQuery<UserEntity> query = em.createNamedQuery("findUserByFederatedIdentityAndRealm", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("findUserByFederatedIdentityAndRealm", UserEntity.class);
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
query.setParameter("identityProvider", identity.getIdentityProvider()); query.setParameter("identityProvider", identity.getIdentityProvider());
@ -583,11 +577,6 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
} }
@Override
public Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
return getUsersStream(realm, -1, -1, includeServiceAccounts);
}
@Override @Override
public int getUsersCount(RealmModel realm, boolean includeServiceAccount) { public int getUsersCount(RealmModel realm, boolean includeServiceAccount) {
String namedQuery = "getRealmUserCountExcludeServiceAccount"; String namedQuery = "getRealmUserCountExcludeServiceAccount";
@ -602,11 +591,6 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
return ((Number)count).intValue(); return ((Number)count).intValue();
} }
@Override
public int getUsersCount(RealmModel realm) {
return getUsersCount(realm, false);
}
@Override @Override
public int getUsersCount(RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
@ -622,7 +606,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public int getUsersCount(String search, RealmModel realm) { public int getUsersCount(RealmModel realm, String search) {
TypedQuery<Long> query = em.createNamedQuery("searchForUserCount", Long.class); TypedQuery<Long> query = em.createNamedQuery("searchForUserCount", Long.class);
query.setParameter("realmId", realm.getId()); query.setParameter("realmId", realm.getId());
query.setParameter("search", "%" + search.toLowerCase() + "%"); query.setParameter("search", "%" + search.toLowerCase() + "%");
@ -632,7 +616,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public int getUsersCount(String search, RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, String search, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
@ -647,7 +631,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public int getUsersCount(Map<String, String> params, RealmModel realm) { public int getUsersCount(RealmModel realm, Map<String, String> params) {
CriteriaBuilder qb = em.getCriteriaBuilder(); CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Long> userQuery = qb.createQuery(Long.class); CriteriaQuery<Long> userQuery = qb.createQuery(Long.class);
Root<UserEntity> from = userQuery.from(UserEntity.class); Root<UserEntity> from = userQuery.from(UserEntity.class);
@ -691,7 +675,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public int getUsersCount(Map<String, String> params, RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, Map<String, String> params, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
@ -740,12 +724,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
return getUsersStream(realm, false);
}
@Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
return getUsersStream(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@ -776,25 +755,15 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
return searchForUserStream(search, realm, -1, -1);
}
@Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer 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 searchForUserStream(attributes, realm, firstResult, maxResults); return searchForUserStream(realm, attributes, firstResult, maxResults);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> attributes, Integer firstResult, Integer maxResults) {
return searchForUserStream(attributes, realm, -1, -1);
}
@Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, Integer firstResult, Integer 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);
@ -903,11 +872,11 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
UserProvider users = session.users(); UserProvider users = session.users();
return closing(paginateQuery(query, firstResult, maxResults).getResultStream()) return closing(paginateQuery(query, firstResult, maxResults).getResultStream())
.map(userEntity -> users.getUserById(userEntity.getId(), realm)); .map(userEntity -> users.getUserById(realm, userEntity.getId()));
} }
@Override @Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
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);
@ -928,7 +897,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
@Override @Override
public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user) {
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);
@ -938,7 +907,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String identityProvider, RealmModel realm) { public FederatedIdentityModel getFederatedIdentity(RealmModel realm, UserModel user, String identityProvider) {
FederatedIdentityEntity entity = findFederatedIdentity(user, identityProvider, LockModeType.NONE); FederatedIdentityEntity entity = findFederatedIdentity(user, identityProvider, LockModeType.NONE);
return (entity != null) ? new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName(), entity.getToken()) : null; return (entity != null) ? new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName(), entity.getToken()) : null;
} }

View file

@ -0,0 +1,43 @@
/*
* Copyright 2020 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.jpa;
import javax.persistence.TypedQuery;
public class PaginationUtils {
public static final int DEFAULT_MAX_RESULTS = Integer.MAX_VALUE >> 1;
public static <T> TypedQuery<T> paginateQuery(TypedQuery<T> query, Integer first, Integer max) {
if (first != null && first > 0) {
query = query.setFirstResult(first);
// Workaround for https://hibernate.atlassian.net/browse/HHH-14295
if (max == null || max < 0) {
max = DEFAULT_MAX_RESULTS;
}
}
if (max != null && max >= 0) {
query = query.setMaxResults(max);
}
return query;
}
}

View file

@ -77,7 +77,7 @@ public class MapAuthenticationSessionAdapter implements AuthenticationSessionMod
@Override @Override
public UserModel getAuthenticatedUser() { public UserModel getAuthenticatedUser() {
return entity.getAuthUserId() == null ? null : session.users().getUserById(entity.getAuthUserId(), getRealm()); return entity.getAuthUserId() == null ? null : session.users().getUserById(getRealm(), entity.getAuthUserId());
} }
@Override @Override

View file

@ -38,7 +38,9 @@ import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorage;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
public class MapClientProvider implements ClientProvider { public class MapClientProvider implements ClientProvider {
@ -130,14 +132,7 @@ public class MapClientProvider implements ClientProvider {
@Override @Override
public Stream<ClientModel> getClientsStream(RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<ClientModel> getClientsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
Stream<ClientModel> s = getClientsStream(realm); return paginatedStream(getClientsStream(realm), firstResult, maxResults);
if (firstResult != null && firstResult >= 0) {
s = s.skip(firstResult);
}
if (maxResults != null && maxResults >= 0) {
s = s.limit(maxResults);
}
return s;
} }
private Stream<MapClientEntity> getNotRemovedUpdatedClientsStream() { private Stream<MapClientEntity> getNotRemovedUpdatedClientsStream() {
@ -281,14 +276,7 @@ public class MapClientProvider implements ClientProvider {
.filter(entity -> entity.getClientId() != null && entity.getClientId().toLowerCase().contains(clientIdLower)) .filter(entity -> entity.getClientId() != null && entity.getClientId().toLowerCase().contains(clientIdLower))
.sorted(COMPARE_BY_CLIENT_ID); .sorted(COMPARE_BY_CLIENT_ID);
if (firstResult != null && firstResult >= 0) { return paginatedStream(s, firstResult, maxResults).map(entityToAdapterFunc(realm));
s = s.skip(firstResult);
}
if (maxResults != null && maxResults >= 0) {
s = s.limit(maxResults);
}
return s.map(entityToAdapterFunc(realm));
} }
@Override @Override

View file

@ -36,6 +36,7 @@ import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
public class MapGroupProvider implements GroupProvider { public class MapGroupProvider implements GroupProvider {
@ -124,15 +125,7 @@ public class MapGroupProvider implements GroupProvider {
groupModelStream = groupModelStream.filter(groupModel -> groupModel.getName().toLowerCase().contains(s)); groupModelStream = groupModelStream.filter(groupModel -> groupModel.getName().toLowerCase().contains(s));
} }
if (first != null && first > 0) { return paginatedStream(groupModelStream, first, max);
groupModelStream = groupModelStream.skip(first);
}
if (max != null && max >= 0) {
groupModelStream = groupModelStream.limit(max);
}
return groupModelStream;
} }
@Override @Override
@ -157,15 +150,7 @@ public class MapGroupProvider implements GroupProvider {
LOG.tracef("getGroupsByRole(%s, %s, %d, %d)%s", realm, role, firstResult, maxResults, getShortStackTrace()); LOG.tracef("getGroupsByRole(%s, %s, %d, %d)%s", realm, role, firstResult, maxResults, getShortStackTrace());
Stream<GroupModel> groupModelStream = getGroupsStream(realm).filter(groupModel -> groupModel.hasRole(role)); Stream<GroupModel> groupModelStream = getGroupsStream(realm).filter(groupModel -> groupModel.hasRole(role));
if (firstResult != null && firstResult > 0) { return paginatedStream(groupModelStream, firstResult, maxResults);
groupModelStream = groupModelStream.skip(firstResult);
}
if (maxResults != null && maxResults >= 0) {
groupModelStream = groupModelStream.limit(maxResults);
}
return groupModelStream;
} }
@Override @Override
@ -179,15 +164,7 @@ public class MapGroupProvider implements GroupProvider {
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
Stream<GroupModel> groupModelStream = getTopLevelGroupsStream(realm); Stream<GroupModel> groupModelStream = getTopLevelGroupsStream(realm);
if (firstResult != null && firstResult > 0) { return paginatedStream(groupModelStream, firstResult, maxResults);
groupModelStream = groupModelStream.skip(firstResult);
}
if (maxResults != null && maxResults >= 0) {
groupModelStream = groupModelStream.limit(maxResults);
}
return groupModelStream;
} }
@ -197,15 +174,8 @@ public class MapGroupProvider implements GroupProvider {
Stream<GroupModel> groupModelStream = getGroupsStream(realm) Stream<GroupModel> groupModelStream = getGroupsStream(realm)
.filter(groupModel -> groupModel.getName().contains(search)); .filter(groupModel -> groupModel.getName().contains(search));
if (firstResult != null && firstResult > 0) {
groupModelStream = groupModelStream.skip(firstResult);
}
if (maxResults != null && maxResults >= 0) { return paginatedStream(groupModelStream, firstResult, maxResults);
groupModelStream = groupModelStream.limit(maxResults);
}
return groupModelStream;
} }
@Override @Override

View file

@ -35,6 +35,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorage;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.map.common.StreamUtils; import org.keycloak.models.map.common.StreamUtils;
@ -126,14 +128,7 @@ public class MapRoleProvider implements RoleProvider {
@Override @Override
public Stream<RoleModel> getRealmRolesStream(RealmModel realm, Integer first, Integer max) { public Stream<RoleModel> getRealmRolesStream(RealmModel realm, Integer first, Integer max) {
Stream<RoleModel> s = getRealmRolesStream(realm); return paginatedStream(getRealmRolesStream(realm), first, max);
if (first != null && first >= 0) {
s = s.skip(first);
}
if (max != null && max >= 0) {
s = s.limit(max);
}
return s;
} }
@Override @Override
@ -171,14 +166,7 @@ public class MapRoleProvider implements RoleProvider {
@Override @Override
public Stream<RoleModel> getClientRolesStream(ClientModel client, Integer first, Integer max) { public Stream<RoleModel> getClientRolesStream(ClientModel client, Integer first, Integer max) {
Stream<RoleModel> s = getClientRolesStream(client); return paginatedStream(getClientRolesStream(client), first, max);
if (first != null && first > 0) {
s = s.skip(first);
}
if (max != null && max >= 0) {
s = s.limit(max);
}
return s;
} }
@Override @Override
@ -326,14 +314,7 @@ public class MapRoleProvider implements RoleProvider {
) )
.sorted(COMPARE_BY_NAME); .sorted(COMPARE_BY_NAME);
if (first != null && first > 0) { return paginatedStream(s.map(entityToAdapterFunc(realm)), first, max);
s = s.skip(first);
}
if (max != null && max >= 0) {
s = s.limit(max);
}
return s.map(entityToAdapterFunc(realm));
} }
@Override @Override
@ -350,14 +331,7 @@ public class MapRoleProvider implements RoleProvider {
) )
.sorted(COMPARE_BY_NAME); .sorted(COMPARE_BY_NAME);
if (first != null && first > 0) { return paginatedStream(s,first, max).map(entityToAdapterFunc(client.getRealm()));
s = s.skip(first);
}
if (max != null && max >= 0) {
s = s.limit(max);
}
return s.map(entityToAdapterFunc(client.getRealm()));
} }
@Override @Override

View file

@ -68,6 +68,7 @@ import static org.keycloak.models.UserModel.EMAIL_VERIFIED;
import static org.keycloak.models.UserModel.FIRST_NAME; import static org.keycloak.models.UserModel.FIRST_NAME;
import static org.keycloak.models.UserModel.LAST_NAME; import static org.keycloak.models.UserModel.LAST_NAME;
import static org.keycloak.models.UserModel.USERNAME; import static org.keycloak.models.UserModel.USERNAME;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
public class MapUserProvider implements UserProvider.Streams, UserCredentialStore.Streams { public class MapUserProvider implements UserProvider.Streams, UserCredentialStore.Streams {
@ -96,12 +97,12 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
@Override @Override
public boolean checkEmailUniqueness(RealmModel realm, String email) { public boolean checkEmailUniqueness(RealmModel realm, String email) {
return getUserByEmail(email, realm) != null; return getUserByEmail(realm, email) != null;
} }
@Override @Override
public boolean checkUsernameUniqueness(RealmModel realm, String username) { public boolean checkUsernameUniqueness(RealmModel realm, String username) {
return getUserByUsername(username, realm) != null; return getUserByUsername(realm, username) != null;
} }
}; };
} }
@ -157,18 +158,6 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
.filter(entityRealmFilter(realm)); .filter(entityRealmFilter(realm));
} }
private <T> Stream<T> paginatedStream(Stream<T> originalStream, Integer first, Integer max) {
if (first != null && first > 0) {
originalStream = originalStream.skip(first);
}
if (max != null && max >= 0) {
originalStream = originalStream.limit(max);
}
return originalStream;
}
@Override @Override
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) { public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
if (user == null || user.getId() == null) { if (user == null || user.getId() == null) {
@ -206,7 +195,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user) {
LOG.tracef("getFederatedIdentitiesStream(%s, %s)%s", realm, user.getId(), getShortStackTrace()); LOG.tracef("getFederatedIdentitiesStream(%s, %s)%s", realm, user.getId(), getShortStackTrace());
return getEntityById(realm, user.getId()) return getEntityById(realm, user.getId())
.map(AbstractUserEntity::getFederatedIdentities).orElseGet(Stream::empty) .map(AbstractUserEntity::getFederatedIdentities).orElseGet(Stream::empty)
@ -214,7 +203,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) { public FederatedIdentityModel getFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
LOG.tracef("getFederatedIdentity(%s, %s, %s)%s", realm, user.getId(), socialProvider, getShortStackTrace()); LOG.tracef("getFederatedIdentity(%s, %s, %s)%s", realm, user.getId(), socialProvider, getShortStackTrace());
return getEntityById(realm, user.getId()) return getEntityById(realm, user.getId())
.map(userEntity -> userEntity.getFederatedIdentity(socialProvider)) .map(userEntity -> userEntity.getFederatedIdentity(socialProvider))
@ -223,7 +212,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) { public UserModel getUserByFederatedIdentity(RealmModel realm, FederatedIdentityModel socialLink) {
LOG.tracef("getUserByFederatedIdentity(%s, %s)%s", realm, socialLink, getShortStackTrace()); LOG.tracef("getUserByFederatedIdentity(%s, %s)%s", realm, socialLink, getShortStackTrace());
return getUnsortedUserEntitiesStream(realm) return getUnsortedUserEntitiesStream(realm)
.filter(userEntity -> Objects.nonNull(userEntity.getFederatedIdentity(socialLink.getIdentityProvider()))) .filter(userEntity -> Objects.nonNull(userEntity.getFederatedIdentity(socialLink.getIdentityProvider())))
@ -231,7 +220,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
.collect(Collectors.collectingAndThen( .collect(Collectors.collectingAndThen(
Collectors.toList(), Collectors.toList(),
list -> { list -> {
if (list.size() == 0) { if (list.isEmpty()) {
return null; return null;
} else if (list.size() != 1) { } else if (list.size() != 1) {
throw new IllegalStateException("More results found for identityProvider=" + socialLink.getIdentityProvider() + throw new IllegalStateException("More results found for identityProvider=" + socialLink.getIdentityProvider() +
@ -246,8 +235,8 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
public void addConsent(RealmModel realm, String userId, UserConsentModel consent) { public void addConsent(RealmModel realm, String userId, UserConsentModel consent) {
LOG.tracef("addConsent(%s, %s, %s)%s", realm, userId, consent, getShortStackTrace()); LOG.tracef("addConsent(%s, %s, %s)%s", realm, userId, consent, getShortStackTrace());
UserConsentEntity consentEntity = UserConsentEntity.fromModel(consent); getRegisteredEntityByIdOrThrow(realm, userId)
getRegisteredEntityById(realm, userId).ifPresent(userEntity -> userEntity.addUserConsent(consentEntity)); .addUserConsent(UserConsentEntity.fromModel(consent));
} }
@Override @Override
@ -298,15 +287,15 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
@Override @Override
public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) { public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) {
LOG.tracef("setNotBeforeForUser(%s, %s, %d)%s", realm, user.getId(), notBefore, getShortStackTrace()); LOG.tracef("setNotBeforeForUser(%s, %s, %d)%s", realm, user.getId(), notBefore, getShortStackTrace());
getRegisteredEntityById(realm, user.getId()).ifPresent(userEntity -> userEntity.setNotBefore(notBefore)); getRegisteredEntityByIdOrThrow(realm, user.getId()).setNotBefore(notBefore);
} }
@Override @Override
public int getNotBeforeOfUser(RealmModel realm, UserModel user) { public int getNotBeforeOfUser(RealmModel realm, UserModel user) {
LOG.tracef("getNotBeforeOfUser(%s, %s)%s", realm, user.getId(), getShortStackTrace()); LOG.tracef("getNotBeforeOfUser(%s, %s)%s", realm, user.getId(), getShortStackTrace());
return getEntityById(realm, user.getId()) return getEntityById(realm, user.getId())
.map(AbstractUserEntity::getNotBefore) .orElseThrow(this::userDoesntExistException)
.orElse(0); .getNotBefore();
} }
@Override @Override
@ -317,7 +306,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
.collect(Collectors.collectingAndThen( .collect(Collectors.collectingAndThen(
Collectors.toList(), Collectors.toList(),
list -> { list -> {
if (list.size() == 0) { if (list.isEmpty()) {
return null; return null;
} else if (list.size() != 1) { } else if (list.size() != 1) {
throw new IllegalStateException("More service account linked users found for client=" + client.getClientId() + throw new IllegalStateException("More service account linked users found for client=" + client.getClientId() +
@ -479,13 +468,13 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
LOG.tracef("getUserById(%s, %s)%s", realm, id, getShortStackTrace()); LOG.tracef("getUserById(%s, %s)%s", realm, id, getShortStackTrace());
return getEntityById(realm, id).map(entityToAdapterFunc(realm)).orElse(null); return getEntityById(realm, id).map(entityToAdapterFunc(realm)).orElse(null);
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
if (username == null) return null; if (username == null) return null;
final String usernameLowercase = username.toLowerCase(); final String usernameLowercase = username.toLowerCase();
@ -497,12 +486,12 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
LOG.tracef("getUserByEmail(%s, %s)%s", realm, email, getShortStackTrace()); LOG.tracef("getUserByEmail(%s, %s)%s", realm, email, getShortStackTrace());
List<MapUserEntity> usersWithEmail = getUnsortedUserEntitiesStream(realm) List<MapUserEntity> usersWithEmail = getUnsortedUserEntitiesStream(realm)
.filter(userEntity -> Objects.equals(userEntity.getEmail(), email)) .filter(userEntity -> Objects.equals(userEntity.getEmail(), email.toLowerCase()))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (usersWithEmail.size() == 0) return null; if (usersWithEmail.isEmpty()) return null;
if (usersWithEmail.size() > 1) { if (usersWithEmail.size() > 1) {
// Realm settings have been changed from allowing duplicate emails to not allowing them // Realm settings have been changed from allowing duplicate emails to not allowing them
@ -523,21 +512,15 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
return new MapUserAdapter(session, realm, userEntity) { return new MapUserAdapter(session, realm, userEntity) {
@Override @Override
public boolean checkEmailUniqueness(RealmModel realm, String email) { public boolean checkEmailUniqueness(RealmModel realm, String email) {
return getUserByEmail(email, realm) != null; return getUserByEmail(realm, email) != null;
} }
@Override @Override
public boolean checkUsernameUniqueness(RealmModel realm, String username) { public boolean checkUsernameUniqueness(RealmModel realm, String username) {
return getUserByUsername(username, realm) != null; return getUserByUsername(realm, username) != null;
} }
}; };
} }
@Override
public int getUsersCount(RealmModel realm) {
LOG.tracef("getUsersCount(%s)%s", realm, getShortStackTrace());
return getUsersCount(realm, false);
}
@Override @Override
public int getUsersCount(RealmModel realm, boolean includeServiceAccount) { public int getUsersCount(RealmModel realm, boolean includeServiceAccount) {
LOG.tracef("getUsersCount(%s, %s)%s", realm, includeServiceAccount, getShortStackTrace()); LOG.tracef("getUsersCount(%s, %s)%s", realm, includeServiceAccount, getShortStackTrace());
@ -564,46 +547,22 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
LOG.tracef("getUsersStream(%s)%s", realm, getShortStackTrace());
return getUsersStream(realm, null, null, false);
}
@Override
public Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
LOG.tracef("getUsersStream(%s)%s", realm, getShortStackTrace());
return getUsersStream(realm, null, null, includeServiceAccounts);
}
@Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
LOG.tracef("getUsersStream(%s, %d, %d)%s", realm, firstResult, maxResults, getShortStackTrace()); LOG.tracef("getUsersStream(%s, %d, %d)%s", realm, firstResult, maxResults, getShortStackTrace());
return getUsersStream(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
LOG.tracef("searchForUserStream(%s, %s)%s", realm, search, getShortStackTrace());
return searchForUserStream(search, realm, null, null);
}
@Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults) {
LOG.tracef("searchForUserStream(%s, %s, %d, %d)%s", realm, search, firstResult, maxResults, getShortStackTrace()); LOG.tracef("searchForUserStream(%s, %s, %d, %d)%s", realm, search, firstResult, maxResults, getShortStackTrace());
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 searchForUserStream(attributes, realm, firstResult, maxResults); return searchForUserStream(realm, attributes, firstResult, maxResults);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> attributes, Integer firstResult, Integer maxResults) {
LOG.tracef("searchForUserStream(%s, %s)%s", realm, params, getShortStackTrace());
return searchForUserStream(params, realm, null, null);
}
@Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, Integer firstResult, Integer maxResults) {
LOG.tracef("searchForUserStream(%s, %s, %d, %d)%s", realm, attributes, firstResult, maxResults, getShortStackTrace()); LOG.tracef("searchForUserStream(%s, %s, %d, %d)%s", realm, attributes, firstResult, maxResults, getShortStackTrace());
/* Find all predicates based on attributes map */ /* Find all predicates based on attributes map */
List<Predicate<MapUserEntity>> predicatesList = new ArrayList<>(); List<Predicate<MapUserEntity>> predicatesList = new ArrayList<>();
@ -735,13 +694,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
} }
@Override @Override
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
LOG.tracef("getGroupMembersStream(%s, %s)%s", realm, group.getId(), getShortStackTrace());
return getGroupMembersStream(realm, group, null, null);
}
@Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
LOG.tracef("searchForUserByUserAttributeStream(%s, %s, %s)%s", realm, attrName, attrValue, getShortStackTrace()); LOG.tracef("searchForUserByUserAttributeStream(%s, %s, %s)%s", realm, attrName, attrValue, getShortStackTrace());
return getUnsortedUserEntitiesStream(realm) return getUnsortedUserEntitiesStream(realm)
.filter(userEntity -> userEntity.getAttribute(attrName).contains(attrValue)) .filter(userEntity -> userEntity.getAttribute(attrName).contains(attrValue))

View file

@ -61,7 +61,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider; import org.keycloak.models.UserProvider;
import org.keycloak.models.dblock.DBLockManager; import org.keycloak.models.dblock.DBLockManager;
import org.keycloak.models.dblock.DBLockProvider; import org.keycloak.models.dblock.DBLockProvider;
import org.keycloak.models.utils.DefaultKeyProviders;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.provider.ServerInfoAwareProviderFactory; import org.keycloak.provider.ServerInfoAwareProviderFactory;
@ -497,7 +496,7 @@ public class QuarkusJpaConnectionProviderFactory implements JpaConnectionProvide
UserProvider users = session.users(); UserProvider users = session.users();
if (users.getUserByUsername(userRep.getUsername(), realm) != null) { if (users.getUserByUsername(realm, userRep.getUsername()) != null) {
ServicesLogger.LOGGER.notCreatingExistingUser(userRep.getUsername()); ServicesLogger.LOGGER.notCreatingExistingUser(userRep.getUsername());
} else { } else {
UserModel user = users.addUser(realm, userRep.getUsername()); UserModel user = users.addUser(realm, userRep.getUsername());

View file

@ -165,13 +165,13 @@ public class DefaultEvaluation implements Evaluation {
private UserModel getUser(String id, KeycloakSession session) { private UserModel getUser(String id, KeycloakSession session) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(realm, id);
if (Objects.isNull(user)) { if (Objects.isNull(user)) {
user = session.users().getUserByUsername(id, realm); user = session.users().getUserByUsername(realm ,id);
} }
if (Objects.isNull(user)) { if (Objects.isNull(user)) {
user = session.users().getUserByEmail(id, realm); user = session.users().getUserByEmail(realm, id);
} }
if (Objects.isNull(user)) { if (Objects.isNull(user)) {
user = session.users().getServiceAccount(realm.getClientById(id)); user = session.users().getServiceAccount(realm.getClientById(id));

View file

@ -120,7 +120,7 @@ public class PersistentUserSessionAdapter implements OfflineUserSessionModel {
@Override @Override
public UserModel getUser() { public UserModel getUser() {
if (user == null) { if (user == null) {
user = session.users().getUserById(userId, realm); user = session.users().getUserById(realm, userId);
} }
return user; return user;
} }

View file

@ -205,13 +205,13 @@ public final class KeycloakModelUtils {
*/ */
public static UserModel findUserByNameOrEmail(KeycloakSession session, RealmModel realm, String username) { public static UserModel findUserByNameOrEmail(KeycloakSession session, RealmModel realm, String username) {
if (realm.isLoginWithEmailAllowed() && username.indexOf('@') != -1) { if (realm.isLoginWithEmailAllowed() && username.indexOf('@') != -1) {
UserModel user = session.users().getUserByEmail(username, realm); UserModel user = session.users().getUserByEmail(realm, username);
if (user != null) { if (user != null) {
return user; return user;
} }
} }
return session.users().getUserByUsername(username, realm); return session.users().getUserByUsername(realm, username);
} }
/** /**

View file

@ -885,7 +885,7 @@ public class ModelToRepresentation {
ClientModel clientModel = realm.getClientById(resourceServer); ClientModel clientModel = realm.getClientById(resourceServer);
owner.setName(clientModel.getClientId()); owner.setName(clientModel.getClientId());
} else { } else {
UserModel userModel = keycloakSession.users().getUserById(owner.getId(), realm); UserModel userModel = keycloakSession.users().getUserById(realm, owner.getId());
if (userModel == null) { if (userModel == null) {
throw new RuntimeException("Could not find the user [" + owner.getId() + "] who owns the Resource [" + resource.getId() + "]."); throw new RuntimeException("Could not find the user [" + owner.getId() + "] who owns the Resource [" + resource.getId() + "].");
@ -934,8 +934,8 @@ public class ModelToRepresentation {
representation.setResourceName(resource.getName()); representation.setResourceName(resource.getName());
KeycloakSession keycloakSession = authorization.getKeycloakSession(); KeycloakSession keycloakSession = authorization.getKeycloakSession();
RealmModel realm = authorization.getRealm(); RealmModel realm = authorization.getRealm();
UserModel userOwner = keycloakSession.users().getUserById(ticket.getOwner(), realm); UserModel userOwner = keycloakSession.users().getUserById(realm, ticket.getOwner());
UserModel requester = keycloakSession.users().getUserById(ticket.getRequester(), realm); UserModel requester = keycloakSession.users().getUserById(realm, ticket.getRequester());
representation.setRequesterName(requester.getUsername()); representation.setRequesterName(requester.getUsername());
if (userOwner != null) { if (userOwner != null) {
representation.setOwnerName(userOwner.getUsername()); representation.setOwnerName(userOwner.getUsername());

View file

@ -2257,7 +2257,7 @@ public class RepresentationToModel {
owner.setId(resourceServer.getId()); owner.setId(resourceServer.getId());
resource.setOwner(owner); resource.setOwner(owner);
} else if (owner.getName() != null) { } else if (owner.getName() != null) {
UserModel user = session.users().getUserByUsername(owner.getName(), realm); UserModel user = session.users().getUserByUsername(realm, owner.getName());
if (user != null) { if (user != null) {
owner.setId(user.getId()); owner.setId(user.getId());
@ -2572,10 +2572,10 @@ public class RepresentationToModel {
RealmModel realm = authorization.getRealm(); RealmModel realm = authorization.getRealm();
KeycloakSession keycloakSession = authorization.getKeycloakSession(); KeycloakSession keycloakSession = authorization.getKeycloakSession();
UserProvider users = keycloakSession.users(); UserProvider users = keycloakSession.users();
UserModel ownerModel = users.getUserById(ownerId, realm); UserModel ownerModel = users.getUserById(realm, ownerId);
if (ownerModel == null) { if (ownerModel == null) {
ownerModel = users.getUserByUsername(ownerId, realm); ownerModel = users.getUserByUsername(realm, ownerId);
} }
if (ownerModel == null) { if (ownerModel == null) {

View file

@ -24,6 +24,15 @@ import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
public class StreamsUtil { public class StreamsUtil {
/**
* Returns the original stream that is closed on terminating operation.
*
* It is used, for example, for closing hibernate provided streams since it is required by hibernate documentation.
*
* @param stream the stream which is expected to be closed on termination
* @return stream that will be closed on terminating operation
*/
public static <T> Stream<T> closing(Stream<T> stream) { public static <T> Stream<T> closing(Stream<T> stream) {
return Stream.of(stream).flatMap(Function.identity()); return Stream.of(stream).flatMap(Function.identity());
} }
@ -42,4 +51,26 @@ public class StreamsUtil {
throw ex; throw ex;
} }
} }
/**
* Returns the original stream that is limited with {@link Stream#skip(long) skip} and
* {@link Stream#limit(long) limit} functions based on values of {@code first} and {@code max} parameters.
*
* @param originalStream Stream to be limited.
* @param first Index of first item to be returned by the stream. Ignored if negative, zero {@code null}.
* @param max Maximum number of items to be returned by the stream. Ignored if negative or {@code null}.
* @param <T> Type of items in the stream
* @return Stream
*/
public static <T> Stream<T> paginatedStream(Stream<T> originalStream, Integer first, Integer max) {
if (first != null && first > 0) {
originalStream = originalStream.skip(first);
}
if (max != null && max >= 0) {
originalStream = originalStream.limit(max);
}
return originalStream;
}
} }

View file

@ -38,7 +38,7 @@ public interface GroupProvider extends Provider, GroupLookupProvider {
* @param id Id. * @param id Id.
* @param realm Realm. * @param realm Realm.
* @return GroupModel with the corresponding id. * @return GroupModel with the corresponding id.
* @deprecated Use method {@code getGroupById(realm, id)} * @deprecated Use method {@link #getGroupById(RealmModel, String) getGroupById}
*/ */
default GroupModel getGroupById(String id, RealmModel realm) { default GroupModel getGroupById(String id, RealmModel realm) {
return getGroupById(realm, id); return getGroupById(realm, id);
@ -140,7 +140,7 @@ public interface GroupProvider extends Provider, GroupLookupProvider {
* @param firstResult First result to return. Ignored if negative. * @param firstResult First result to return. Ignored if negative.
* @param maxResults Maximum number of results to return. Ignored if negative. * @param maxResults Maximum number of results to return. Ignored if negative.
* @return List of groups with the given role. * @return List of groups with the given role.
* @deprecated Use {@link #getGroupsByRoleStream(RealmModel, RoleModel, int, int) getGroupsByRoleStream} instead. * @deprecated Use {@link #getGroupsByRoleStream(RealmModel, RoleModel, Integer, Integer) getGroupsByRoleStream} instead.
*/ */
@Deprecated @Deprecated
default List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults) { default List<GroupModel> getGroupsByRole(RealmModel realm, RoleModel role, int firstResult, int maxResults) {

View file

@ -38,73 +38,35 @@ public interface UserProvider extends Provider,
UserQueryProvider, UserQueryProvider,
UserRegistrationProvider, UserRegistrationProvider,
UserBulkUpdateProvider { UserBulkUpdateProvider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
void preRemove(RealmModel realm, IdentityProviderModel provider);
void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
/** /**
* @deprecated Use {@link #getFederatedIdentitiesStream(UserModel, RealmModel) getFederatedIdentitiesStream} instead. * Sets the notBefore value for the given user
*/
@Deprecated
Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
/**
* Obtains the federated identities of the specified user.
* *
* @param user a reference to the user. * @param realm a reference to the realm
* @param realm a reference to the realm. * @param user the user model
* @return a non-null {@link Stream} of federated identities associated with the user. * @param notBefore new value for notBefore
*/
default Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) {
Set<FederatedIdentityModel> value = this.getFederatedIdentities(user, realm);
return value != null ? value.stream() : Stream.empty();
}
FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
void addConsent(RealmModel realm, String userId, UserConsentModel consent);
UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientInternalId);
/**
* @deprecated Use {@link #getConsentsStream(RealmModel, String) getConsentsStream} instead.
*/
@Deprecated
List<UserConsentModel> getConsents(RealmModel realm, String userId);
/**
* Obtains the consents associated with the user identified by the specified {@code userId}.
* *
* @param realm a reference to the realm. * @throws ModelException when user doesn't exist in the storage
* @param userId the user identifier.
* @return a non-null {@link Stream} of consents associated with the user.
*/ */
default Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId) {
List<UserConsentModel> value = this.getConsents(realm, userId);
return value != null ? value.stream() : Stream.empty();
}
/**
*
* @param realm
* @param userId
* @param consent
* @throws ModelException when consent doesn't exist for the userId
*/
void updateConsent(RealmModel realm, String userId, UserConsentModel consent);
boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId);
void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore); void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore);
/**
* Gets the notBefore value for the given user
*
* @param realm a reference to the realm
* @param user the user model
* @return the value of notBefore
*
* @throws ModelException when user doesn't exist in the storage
*/
int getNotBeforeOfUser(RealmModel realm, UserModel user); int getNotBeforeOfUser(RealmModel realm, UserModel user);
/** /**
* Return a UserModel representing service account of the client
* *
* @param client * @param client the client model
* @throws IllegalArgumentException when there are more service accounts associated with the given clientId * @throws IllegalArgumentException when there are more service accounts associated with the given clientId
* @return * @return userModel representing service account of the client
*/ */
UserModel getServiceAccount(ClientModel client); UserModel getServiceAccount(ClientModel client);
@ -136,8 +98,8 @@ public interface UserProvider extends Provider,
* Obtains the users associated with the specified realm. * Obtains the users associated with the specified realm.
* *
* @param realm a reference to the realm being used for the search. * @param realm a reference to the realm being used for the search.
* @param firstResult first result to return. Ignored if negative. * @param firstResult first result to return. Ignored if negative, zero, or {@code null}.
* @param maxResults maximum number of results to return. Ignored if negative. * @param maxResults maximum number of results to return. Ignored if negative or {@code null}.
* @param includeServiceAccounts {@code true} if service accounts should be included in the result; {@code false} otherwise. * @param includeServiceAccounts {@code true} if service accounts should be included in the result; {@code false} otherwise.
* @return a non-null {@link Stream} of users associated withe the realm. * @return a non-null {@link Stream} of users associated withe the realm.
*/ */
@ -147,53 +109,297 @@ public interface UserProvider extends Provider,
} }
/** /**
* Adds a new user into the storage.
* <p/>
* only used for local storage * only used for local storage
* *
* @param realm * @param realm the realm that user will be created in
* @param id * @param id id of the new user. Should be generated to a random value if {@code null}.
* @param username * @param username username
* @param addDefaultRoles * @param addDefaultRoles if {@code true}, the user should join all realm default roles
* @param addDefaultRequiredActions * @param addDefaultRequiredActions if {@code true}, all default required actions are added to the created user
* @return * @return model of created user
*
* @throws NullPointerException when username or realm is {@code null}
* @throws ModelDuplicateException when a user with given id or username already exists
*/ */
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions); UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
void preRemove(RealmModel realm);
/** /**
* Removes any imported users from a specific User Storage Provider. * Removes any imported users from a specific User Storage Provider.
* *
* @param realm * @param realm a reference to the realm
* @param storageProviderId * @param storageProviderId id of the user storage provider
*/ */
void removeImportedUsers(RealmModel realm, String storageProviderId); void removeImportedUsers(RealmModel realm, String storageProviderId);
/** /**
* Set federation link to null to imported users of a specific User Storage Provider * Set federation link to {@code null} to imported users of a specific User Storage Provider
* *
* @param realm * @param realm a reference to the realm
* @param storageProviderId * @param storageProviderId id of the storage provider
*/ */
void unlinkUsers(RealmModel realm, String storageProviderId); void unlinkUsers(RealmModel realm, String storageProviderId);
/* USER CONSENTS methods */
/**
* Add user consent for the user.
*
* @param realm a reference to the realm
* @param userId id of the user
* @param consent all details corresponding to the granted consent
*
* @throws ModelException If there is no user with userId
*/
void addConsent(RealmModel realm, String userId, UserConsentModel consent);
/**
* Returns UserConsentModel given by a user with the userId for the client with clientInternalId
*
* @param realm a reference to the realm
* @param userId id of the user
* @param clientInternalId id of the client
* @return consent given by the user to the client or {@code null} if no consent or user exists
*
* @throws ModelException when there are more consents fulfilling specified parameters
*/
UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientInternalId);
/**
* @deprecated Use {@link #getConsentsStream(RealmModel, String) getConsentsStream} instead.
*/
@Deprecated
List<UserConsentModel> getConsents(RealmModel realm, String userId);
/**
* 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 {@link Stream} of consents associated with the user.
*/
default Stream<UserConsentModel> getConsentsStream(RealmModel realm, String userId) {
List<UserConsentModel> value = this.getConsents(realm, userId);
return value != null ? value.stream() : Stream.empty();
}
/**
* Update client scopes in the stored user consent
*
* @param realm a reference to the realm
* @param userId id of the user
* @param consent new details of the user consent
*
* @throws ModelException when consent doesn't exist for the userId
*/
void updateConsent(RealmModel realm, String userId, UserConsentModel consent);
/**
* Remove a user consent given by the user id and client id
*
* @param realm a reference to the realm
* @param userId id of the user
* @param clientInternalId id of the client
* @return {@code true} if the consent was removed, {@code false} otherwise
*/
boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId);
/* FEDERATED IDENTITIES methods */
/**
* Adds a federated identity link for the user within the realm
*
* @param realm a reference to the realm
* @param user the user model
* @param socialLink the federated identity model containing all details of the association between the user and
* the identity provider
*/
void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
/**
* Removes federation link between the user and the identity provider given by its id
*
* @param realm a reference to the realm
* @param user the user model
* @param socialProvider alias of the identity provider, see {@link IdentityProviderModel#getAlias()}
* @return {@code true} if the association was removed, {@code false} otherwise
*/
boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
/**
* Update details of association between the federatedUser and the idp given by the federatedIdentityModel
*
* @param realm a reference to the realm
* @param federatedUser the user model
* @param federatedIdentityModel the federated identity model containing all details of the association between
* the user and the identity provider
*/
void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
/**
* @deprecated Use {@link #getFederatedIdentitiesStream(RealmModel, UserModel) getFederatedIdentitiesStream} instead.
*/
@Deprecated
Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
/**
* Obtains the federated identities of the specified user.
*
* @param realm a reference to the realm.
* @param user the reference to the user.
* @return a non-null {@link Stream} of federated identities associated with the user.
*/
default Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user) {
Set<FederatedIdentityModel> value = this.getFederatedIdentities(user, realm);
return value != null ? value.stream() : Stream.empty();
}
/**
* Returns details of the association between the user and the socialProvider.
*
* @param realm a reference to the realm
* @param user the user model
* @param socialProvider the id of the identity provider
* @return federatedIdentityModel or {@code null} if no association exists
*/
default FederatedIdentityModel getFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
return getFederatedIdentity(user, socialProvider, realm);
}
/**
* @deprecated Use {@link #getFederatedIdentity(RealmModel, UserModel, String) getFederatedIdentity} instead.
*/
@Deprecated
FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
/**
* Returns a userModel that corresponds to the given socialLink.
*
* @param realm a reference to the realm
* @param socialLink the socialLink
* @return the user corresponding to socialLink and {@code null} if no such user exists
*
* @throws IllegalStateException when there are more users for the given socialLink
*/
default UserModel getUserByFederatedIdentity(RealmModel realm, FederatedIdentityModel socialLink) {
return getUserByFederatedIdentity(socialLink, realm);
}
/**
* @deprecated Use {@link #getUserByFederatedIdentity(RealmModel, FederatedIdentityModel) getUserByFederatedIdentity} instead.
*/
@Deprecated
UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
/* PRE REMOVE methods - for cleaning user related properties when some other entity is removed */
/**
* Called when a realm is removed.
* Should remove all users that belong to the realm.
*
* @param realm a reference to the realm
*/
void preRemove(RealmModel realm);
/**
* Called when an identity provider is removed.
* Should remove all federated identities assigned to users from the provider.
*
* @param realm a reference to the realm
* @param provider provider model
*/
void preRemove(RealmModel realm, IdentityProviderModel provider);
/**
* Called when a role is removed.
* Should remove the role membership for each user.
*
* @param realm a reference to the realm
* @param role the role model
*/
void preRemove(RealmModel realm, RoleModel role); void preRemove(RealmModel realm, RoleModel role);
/**
* Called when a group is removed.
* Should remove the group membership for each user.
*
* @param realm a reference to the realm
* @param group the group model
*/
void preRemove(RealmModel realm, GroupModel group); void preRemove(RealmModel realm, GroupModel group);
/**
* Called when a client is removed.
* Should remove all user consents associated with the client
*
* @param realm a reference to the realm
* @param client the client model
*/
void preRemove(RealmModel realm, ClientModel client); void preRemove(RealmModel realm, ClientModel client);
/**
* Called when a protocolMapper is removed
*
* @param protocolMapper the protocolMapper model
*/
void preRemove(ProtocolMapperModel protocolMapper); void preRemove(ProtocolMapperModel protocolMapper);
/**
* Called when a client scope is removed.
* Should remove the clientScope from each user consent
*
* @param clientScope the clientScope model
*/
void preRemove(ClientScopeModel clientScope); void preRemove(ClientScopeModel clientScope);
/**
* Called when a component is removed.
* Should remove all data in UserStorage associated with removed component.
* For example,
* <ul>
* <li>if component corresponds to UserStorageProvider all imported users from the provider should be removed,</li>
* <li>if component corresponds to ClientStorageProvider all consents granted for clients imported from the
* provider should be removed</li>
* </ul>
*
* @param realm a reference to the realm
* @param component the component model
*/
void preRemove(RealmModel realm, ComponentModel component);
void close(); void close();
void preRemove(RealmModel realm, ComponentModel component); /**
* The {@link UserProvider.Streams} interface makes all collection-based methods in {@link UserProvider} default by
* providing implementations that delegate to the {@link Stream}-based variants instead of the other way around.
* <p/>
* It allows for implementations to focus on the {@link Stream}-based approach for processing sets of data and benefit
* from the potential memory and performance optimizations of that approach.
*/
interface Streams extends UserProvider, UserQueryProvider.Streams, UserLookupProvider.Streams {
interface Streams extends UserProvider, UserQueryProvider.Streams {
@Override @Override
default Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) { FederatedIdentityModel getFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
return this.getFederatedIdentitiesStream(user, realm).collect(Collectors.toSet());
@Override
default FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
return getFederatedIdentity(realm, user, socialProvider);
} }
@Override @Override
Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm); UserModel getUserByFederatedIdentity(RealmModel realm, FederatedIdentityModel socialLink);
@Override
default UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
return getUserByFederatedIdentity(realm, socialLink);
}
@Override
default Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
return this.getFederatedIdentitiesStream(realm, user).collect(Collectors.toSet());
}
@Override
Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user);
@Override @Override
default List<UserConsentModel> getConsents(RealmModel realm, String userId) { default List<UserConsentModel> getConsents(RealmModel realm, String userId) {
@ -209,7 +415,9 @@ public interface UserProvider extends Provider,
} }
@Override @Override
Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts); default Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
return getUsersStream(realm, null, null, includeServiceAccounts);
}
@Override @Override
default List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) { default List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {

View file

@ -22,6 +22,19 @@ import org.keycloak.models.RoleModel;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
/** /**
* A class implementing this interface represents a user storage provider to Keycloak.
* <p/>
* This interface contains only very basic methods for manipulating users. However, the storage provider capabilities
* are extended by implementing one or more of the following capability interfaces:
* <ul>
* <li>{@link org.keycloak.storage.user.UserLookupProvider UserLookupProvider} - Provide basic lookup methods. After implementing it is possible to login using users from the storage.</li>
* <li>{@link org.keycloak.storage.user.UserQueryProvider UserQueryProvider} - Provide complex lookup methods. After implementing it is possible to manage users from admin console.</li>
* <li>{@link org.keycloak.storage.user.UserRegistrationProvider UserRegistrationProvider} - Provide methods for adding users. After implementing it is possible to store registered users in the storage.</li>
* <li>{@link org.keycloak.storage.user.UserBulkUpdateProvider UserBulkUpdateProvider} - After implementing it is possible to perform bulk operations on all users from storage (for example, addition of a role to all users).</li>
* <li>{@link org.keycloak.storage.user.ImportedUserValidation ImportedUserValidation} - Provider method for validating users within Keycloak local storage that are imported from the storage.</li>
* <li>{@link org.keycloak.storage.user.ImportSynchronization ImportSynchronization} - Provider methods for synchronization of the storage with Keycloak local storage. After implementing it is possible to sync users in the Admin console.</li>
* </ul>
*
* @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 $
*/ */

View file

@ -22,6 +22,11 @@ import org.keycloak.storage.UserStorageProviderModel;
import java.util.Date; import java.util.Date;
/** /**
*
* This is an optional capability interface that is intended to be implemented by any
* {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports syncing users to keycloak local
* storage. You must implement this interface if you want to be able to use sync functionality within the Admin console.
*
* @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 $
*/ */

View file

@ -20,8 +20,12 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
/** /**
* If your UserStorageProvider is importing users into local storage, you can validate that import whenever the * This is an optional capability interface that is intended to be implemented by any
* user is queried from local storage. * {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports validating users. You must
* implement this interface if your storage imports users into the Keycloak local storage and you want to sync these
* users with your storage. The idea is, that whenever keycloak queries users imported from your storage, the method
* {@link #validate(RealmModel, UserModel) validate()} is called and if it returns null, the user is removed from
* local storage and reloaded from your storage by corresponding method.
* *
* @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 $

View file

@ -20,6 +20,9 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
/** /**
* This is an optional capability interface that is intended to be implemented by any
* {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports bulk operations.
*
* @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 $
*/ */

View file

@ -20,23 +20,93 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
/** /**
* Optional capability interface implemented by UserStorageProviders. This interface is required * This is an optional capability interface that is intended to be implemented by any
* if you want the UserStorageProvider to support basic login capabilities. * {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports basic user querying. You must
* implement this interface if you want to be able to log in to keycloak using users from your storage.
* <p/>
* Note that all methods in this interface should limit search only to data available within the storage that is
* represented by this provider. They should not lookup other storage providers for additional information.
* Optional capability interface implemented by UserStorageProviders.
* *
* @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 UserLookupProvider { public interface UserLookupProvider {
/**
* Returns a user with the given id belonging to the realm
*
* @param id id of the user
* @param realm the realm model
* @return found user model, or {@code null} if no such user exists
*/
default UserModel getUserById(RealmModel realm, String id) {
return getUserById(id, realm);
}
/**
* @deprecated Use {@link #getUserById(RealmModel, String) getUserById} instead.
*/
@Deprecated
UserModel getUserById(String id, RealmModel realm); UserModel getUserById(String id, RealmModel realm);
/**
* Returns a user with the given username belonging to the realm
*
* @param username case insensitive username (case-sensitivity is controlled by storage)
* @param realm the realm model
* @return found user model, or {@code null} if no such user exists
*/
default UserModel getUserByUsername(RealmModel realm, String username) {
return getUserByUsername(username, realm);
}
/**
* @deprecated Use {@link #getUserByUsername(RealmModel, String) getUserByUsername} instead.
*/
@Deprecated
UserModel getUserByUsername(String username, RealmModel realm); UserModel getUserByUsername(String username, RealmModel realm);
/** /**
* Returns a user with the given email belonging to the realm
*
* @param email case insensitive email address (case-sensitivity is controlled by storage)
* @param realm the realm model
* @return found user model, or {@code null} if no such user exists
* *
* @param email
* @param realm
* @throws org.keycloak.models.ModelDuplicateException when there are more users with same email * @throws org.keycloak.models.ModelDuplicateException when there are more users with same email
* @return
*/ */
UserModel getUserByEmail(String email, RealmModel realm); default UserModel getUserByEmail(RealmModel realm, String email) {
return getUserByEmail(email, realm);
}
/**
* @deprecated Use {@link #getUserByEmail(RealmModel, String) getUserByEmail} instead.
*/
@Deprecated
UserModel getUserByEmail(String email, RealmModel realm);
interface Streams extends UserLookupProvider {
@Override
UserModel getUserById(RealmModel realm, String id);
@Override
default UserModel getUserById(String id, RealmModel realm) {
return getUserById(realm, id);
}
@Override
UserModel getUserByUsername(RealmModel realm, String username);
@Override
default UserModel getUserByUsername(String username, RealmModel realm) {
return getUserByUsername(realm, username);
}
@Override
UserModel getUserByEmail(RealmModel realm, String email);
@Override
default UserModel getUserByEmail(String email, RealmModel realm) {
return getUserByEmail(realm, email);
}
}
} }

View file

@ -21,6 +21,7 @@ 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;
@ -28,9 +29,13 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
* Optional capability interface implemented by UserStorageProviders. *
* Defines complex queries that are used to locate one or more users. You must implement this interface * This is an optional capability interface that is intended to be implemented by any
* if you want to view and manager users from the administration console. * {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports complex user querying. You must
* implement this interface if you want to view and manage users from the administration console.
* <p/>
* Note that all methods in this interface should limit search only to data available within the storage that is
* represented by this provider. They should not lookup other storage providers for additional information.
* *
* @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 $
@ -43,14 +48,16 @@ public interface UserQueryProvider {
* @param realm the realm * @param realm the realm
* @return the number of users * @return the number of users
*/ */
int getUsersCount(RealmModel realm); default int getUsersCount(RealmModel realm) {
return getUsersCount(realm, false);
}
/** /**
* Returns the number of users that are in at least one of the groups * Returns the number of users that are in at least one of the groups
* given. * given.
* *
* @param realm the realm * @param realm the realm
* @param groupIds set of groups id to check for * @param groupIds set of groups IDs, the returned user needs to belong to at least one of them
* @return the number of users that are in at least one of the groups * @return the number of users that are in at least one of the groups
*/ */
default int getUsersCount(RealmModel realm, Set<String> groupIds) { default int getUsersCount(RealmModel realm, Set<String> groupIds) {
@ -61,41 +68,64 @@ public interface UserQueryProvider {
} }
/** /**
* Returns the number of users that match the given criteria. * Returns the number of users that would be returned by a call to {@link #searchForUserStream(RealmModel, String) searchForUserStream}
* *
* @param search search criteria
* @param realm the realm * @param realm the realm
* @param search case insensitive list of strings separated by whitespaces.
* @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(RealmModel realm, String search) {
return (int) searchForUserStream(search, realm).count(); return getUsersCount(search, realm);
} }
/** /**
* Returns the number of users that match the given criteria and are in * @deprecated Use {@link #getUsersCount(RealmModel, String) getUsersCount}
* at least one of the groups given. */
@Deprecated
default int getUsersCount(String search, RealmModel realm) {
return (int) searchForUserStream(realm, search).count();
}
/**
* Returns the number of users that would be returned by a call to {@link #searchForUserStream(RealmModel, String) searchForUserStream}
* and are members of at least one of the groups given by the {@code groupIds} set.
* *
* @param search search criteria
* @param realm the realm * @param realm the realm
* @param groupIds set of groups to check for * @param search case insensitive list of strings separated by whitespaces.
* @param groupIds set of groups IDs, the returned user needs to belong to at least one of them
* @return number of users that match the search and given groups * @return number of users that match the search and given groups
*/ */
default int getUsersCount(RealmModel realm, String search, Set<String> groupIds) {
return getUsersCount(search, realm, groupIds);
}
/**
* @deprecated Use {@link #getUsersCount(RealmModel, String, Set) getUsersCount} instead.
*/
@Deprecated
default int getUsersCount(String search, RealmModel realm, Set<String> groupIds) { default int getUsersCount(String search, RealmModel realm, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
return countUsersInGroups(searchForUserStream(search, realm), groupIds); return countUsersInGroups(searchForUserStream(realm, search), groupIds);
} }
/** /**
* Returns the number of users that match the given filter parameters. * Returns the number of users that match the given filter parameters.
* *
* @param params filter parameters
* @param realm the realm * @param realm the realm
* @param params filter parameters
* @return number of users that match the given filters * @return number of users that match the given filters
*/ */
default int getUsersCount(RealmModel realm, Map<String, String> params) {
return getUsersCount(params, realm);
}
/**
* @deprecated Use {@link #getUsersCount(RealmModel, Set) getUsersCount} instead.
*/
@Deprecated
default int getUsersCount(Map<String, String> params, RealmModel realm) { default int getUsersCount(Map<String, String> params, RealmModel realm) {
return (int) searchForUserStream(params, realm).count(); return (int) searchForUserStream(realm, params).count();
} }
/** /**
@ -107,13 +137,21 @@ public interface UserQueryProvider {
* @param groupIds set if groups to check for * @param groupIds set if groups to check for
* @return number of users that match the given filters and groups * @return number of users that match the given filters and groups
*/ */
default int getUsersCount(RealmModel realm, Map<String, String> params, Set<String> groupIds) {
return getUsersCount(params, realm, groupIds);
}
/**
* @deprecated Use {@link #getUsersCount(RealmModel, Map, Set) getUsersCount} instead.
*/
@Deprecated
default int getUsersCount(Map<String, String> params, RealmModel realm, Set<String> groupIds) { default int getUsersCount(Map<String, String> params, RealmModel realm, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) { if (groupIds == null || groupIds.isEmpty()) {
return 0; return 0;
} }
return countUsersInGroups(searchForUserStream(params, realm), groupIds); return countUsersInGroups(searchForUserStream(realm, params), groupIds);
} }
/** /**
* Returns the number of users from the given list of users that are in at * Returns the number of users from the given list of users that are in at
* least one of the groups given in the groups set. * least one of the groups given in the groups set.
@ -154,7 +192,7 @@ public interface UserQueryProvider {
} }
/** /**
* @deprecated Use {@link #getUsersStream(RealmModel, int, int) getUsersStream} instead. * @deprecated Use {@link #getUsersStream(RealmModel, Integer, Integer) getUsersStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults); List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults);
@ -163,184 +201,221 @@ public interface UserQueryProvider {
* Searches all users in the realm, starting from the {@code firstResult} and containing at most {@code maxResults}. * 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 realm a reference to the realm.
* @param firstResult first result to return. Ignored if negative. * @param firstResult first result to return. Ignored if negative or zero.
* @param maxResults maximum number of results to return. Ignored if negative. * @param maxResults maximum number of results to return. Ignored if negative.
* @return a non-null {@link Stream} of users. * @return a non-null {@link Stream} of users.
*/ */
default Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) { default Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
List<UserModel> value = this.getUsers(realm, firstResult, maxResults); List<UserModel> value = this.getUsers(realm, firstResult == null ? -1 : firstResult,
maxResults == null ? -1 : maxResults);
return value != null ? value.stream() : Stream.empty(); return value != null ? value.stream() : Stream.empty();
} }
/** /**
* Search for users with username, email or first + last name that is like search string. * Searches for users whose username, email, first name or last name contain any of the strings in {@code search} separated by whitespace.
* * <p/>
* If possible, implementations should treat the parameter values as partial match patterns i.e. in RDMBS terms use LIKE. * 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 * This method is used by the admin console search box
* *
* @param search * @param search case insensitive list of string separated by whitespaces.
* @param realm * @param realm realm to search within
* @return * @return list of users that satisfies the given search condition
* @deprecated Use {@link #searchForUserStream(String, RealmModel) searchForUserStream} instead. *
* @deprecated Use {@link #searchForUserStream(RealmModel, String) searchForUserStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> searchForUser(String search, RealmModel realm); List<UserModel> searchForUser(String search, RealmModel realm);
/** /**
* Searches for users with username, email or first + last name that is like search string. If possible, implementations * Searches for users whose username, email, first name or last name contain any of the strings in {@code search} separated by whitespace.
* should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE). * <p/>
* If possible, implementations should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE).
* <p/> * <p/>
* This method is used by the admin console search box * This method is used by the admin console search box
* *
* @param search case sensitive search string.
* @param realm a reference to the realm. * @param realm a reference to the realm.
* @param search case insensitive list of string separated by whitespaces.
* @return a non-null {@link Stream} of users that match the search string. * @return a non-null {@link Stream} of users that match the search string.
*/ */
default Stream<UserModel> searchForUserStream(String search, RealmModel realm) { default Stream<UserModel> searchForUserStream(RealmModel realm, String search) {
List<UserModel> value = this.searchForUser(search, realm); List<UserModel> value = this.searchForUser(search, realm);
return value != null ? value.stream() : Stream.empty(); return value != null ? value.stream() : Stream.empty();
} }
/** /**
* Search for users with username, email or first + last name that is like search string. * Searches for users whose username, email, first name or last name contain any of the strings in {@code search} separated by whitespace.
* * The resulting user list should be paginated with respect to parameters {@code firstResult} and {@code maxResults}
* <p/>
* If possible, implementations should treat the parameter values as partial match patterns i.e. in RDMBS terms use LIKE. * 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 * This method is used by the admin console search box
* *
* @param search * @param search case insensitive list of string separated by whitespaces.
* @param realm * @param realm a reference to the realm
* @param firstResult * @param firstResult first result to return. Ignored if negative or zero.
* @param maxResults * @param maxResults maximum number of results to return. Ignored if negative.
* @return * @return paginated list of users from the realm that satisfies given search
* @deprecated Use {@link #searchForUserStream(String, RealmModel, Integer, Integer) searchForUserStream} instead. *
* @deprecated Use {@link #searchForUserStream(RealmModel, String, Integer, Integer) searchForUserStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults); List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
/** /**
* Searches for users with username, email or first + last name that is like search string. If possible, implementations * Searches for users whose username, email, first name or last name contain any of the strings in {@code search} separated by whitespace.
* should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE). * <p/>
* If possible, implementations should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE).
* <p/> * <p/>
* This method is used by the admin console search box * This method is used by the admin console search box
* *
* @param search case sensitive search string.
* @param realm a reference to the realm. * @param realm a reference to the realm.
* @param firstResult first result to return. Ignored if negative. * @param search case insensitive list of string separated by whitespaces.
* @param maxResults maximum number of results to return. Ignored if negative. * @param firstResult first result to return. Ignored if negative, zero, or {@code null}.
* @param maxResults maximum number of results to return. Ignored if negative or {@code null}.
* @return a non-null {@link Stream} of users that match the search criteria. * @return a non-null {@link Stream} of users that match the search criteria.
*/ */
default Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults) { default Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
List<UserModel> value = this.searchForUser(search, realm, firstResult == null ? -1 : firstResult, maxResults == null ? -1 : maxResults); List<UserModel> value = this.searchForUser(search, realm, firstResult == null ? -1 : firstResult, maxResults == null ? -1 : maxResults);
return value != null ? value.stream() : Stream.empty(); return value != null ? value.stream() : Stream.empty();
} }
/** /**
* Search for user by parameter. Valid parameters are: * Search for user by a map of parameters.
* "first" - first name * <p/>
* "last" - last name * Valid parameters are:
* "email" - email * <ul>
* "username" - username * <li>{@link UserModel#FIRST_NAME} - first name (case insensitive string)</li>
* <li>{@link UserModel#LAST_NAME} - last name (case insensitive string)</li>
* <li>{@link UserModel#EMAIL} - email (case insensitive string)</li>
* <li>{@link UserModel#USERNAME} - username (case insensitive string)</li>
* <li>{@link UserModel#EMAIL_VERIFIED} - search only for users with verified/non-verified email (true/false)</li>
* <li>{@link UserModel#ENABLED} - search only for enabled/disabled users (true/false)</li>
* <li>{@link UserModel#IDP_ALIAS} - search only for users that have a federated identity
* from idp with the given alias configured (case sensitive string)</li>
* <li>{@link UserModel#IDP_USER_ID} - search for users with federated identity with
* the given userId (case sensitive string)</li>
* </ul>
* *
* If possible, implementations should treat the parameter values as partial match patterns i.e. in RDMBS terms use LIKE. * 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 REST API when querying users. * 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 list of users that satisfies given search conditions
* *
* @param params * @deprecated Use {@link #searchForUserStream(RealmModel, Map) searchForUserStream} instead.
* @param realm
* @return
* @deprecated Use {@link #searchForUserStream(Map, RealmModel) searchForUserStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> searchForUser(Map<String, String> params, RealmModel realm); List<UserModel> searchForUser(Map<String, String> params, RealmModel realm);
/** /**
* Searches for user by parameter. If possible, implementations should treat the parameter values as partial match patterns * Searches for user by parameter.
* (i.e. in RDMBS terms use LIKE). Valid parameters are: * If possible, implementations should treat the parameter values as partial match patterns (i.e. in RDMBS terms use LIKE).
* <p/>
* Valid parameters are:
* <ul> * <ul>
* <li><b>first</b> - first name</li> * <li>{@link UserModel#FIRST_NAME} - first name (case insensitive string)</li>
* <li><b>last</b> - last name</li> * <li>{@link UserModel#LAST_NAME} - last name (case insensitive string)</li>
* <li><b>email</b> - email</li> * <li>{@link UserModel#EMAIL} - email (case insensitive string)</li>
* <li><b>username</b> - username</li> * <li>{@link UserModel#USERNAME} - username (case insensitive string)</li>
* <li><b>enabled</b> - if user is enabled (true/false)</li> * <li>{@link UserModel#EMAIL_VERIFIED} - search only for users with verified/non-verified email (true/false)</li>
* <li>{@link UserModel#ENABLED} - search only for enabled/disabled users (true/false)</li>
* <li>{@link UserModel#IDP_ALIAS} - search only for users that have a federated identity
* from idp with the given alias configured (case sensitive string)</li>
* <li>{@link UserModel#IDP_USER_ID} - search for users with federated identity with
* the given userId (case sensitive string)</li>
* </ul> * </ul>
*
* This method is used by the REST API when querying users. * 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 realm a reference to the realm.
* @param params a map containing the search parameters.
* @return a non-null {@link Stream} of users that match the search parameters. * @return a non-null {@link Stream} of users that match the search parameters.
*/ */
default Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) { default Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params) {
List<UserModel> value = this.searchForUser(params, realm); List<UserModel> value = this.searchForUser(params, realm);
return value != null ? value.stream() : Stream.empty(); return value != null ? value.stream() : Stream.empty();
} }
/** /**
* Search for user by parameter. Valid parameters are: * Search for user by parameter.
* "first" - first name * <p/>
* "last" - last name * Valid parameters are:
* "email" - email * <ul>
* "username" - username * <li>{@link UserModel#FIRST_NAME} - first name (case insensitive string)</li>
* "enabled" - is user enabled (true/false) * <li>{@link UserModel#LAST_NAME} - last name (case insensitive string)</li>
* <li>{@link UserModel#EMAIL} - email (case insensitive string)</li>
* <li>{@link UserModel#USERNAME} - username (case insensitive string)</li>
* <li>{@link UserModel#EMAIL_VERIFIED} - search only for users with verified/non-verified email (true/false)</li>
* <li>{@link UserModel#ENABLED} - search only for enabled/disabled users (true/false)</li>
* <li>{@link UserModel#IDP_ALIAS} - search only for users that have a federated identity
* from idp with the given alias configured (case sensitive string)</li>
* <li>{@link UserModel#IDP_USER_ID} - search for users with federated identity with
* the given userId (case sensitive string)</li>
* </ul>
* *
* If possible, implementations should treat the parameter values as patterns i.e. in RDMBS terms use LIKE. * If possible, implementations should treat the parameter values as patterns i.e. in RDMBS terms use LIKE.
* <p/>
* This method is used by the REST API when querying users. * 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 {@link Stream} of users that match the search criteria.
* *
* @param params * @deprecated Use {@link #searchForUserStream(RealmModel, Map, Integer, Integer) searchForUserStream} instead.
* @param realm
* @param firstResult
* @param maxResults
* @return
* @deprecated Use {@link #searchForUserStream(Map, RealmModel, Integer, Integer) searchForUserStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults); List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults);
/** /**
* Searches for user by parameter. If possible, implementations should treat the parameter values as partial match patterns * 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: * (i.e. in RDMBS terms use LIKE).
* <p/>
* Valid parameters are:
* <ul> * <ul>
* <li><b>first</b> - first name</li> * <li>{@link UserModel#FIRST_NAME} - first name (case insensitive string)</li>
* <li><b>last</b> - last name</li> * <li>{@link UserModel#LAST_NAME} - last name (case insensitive string)</li>
* <li><b>email</b> - email</li> * <li>{@link UserModel#EMAIL} - email (case insensitive string)</li>
* <li><b>username</b> - username</li> * <li>{@link UserModel#USERNAME} - username (case insensitive string)</li>
* <li><b>enabled</b> - if user is enabled (true/false)</li> * <li>{@link UserModel#EMAIL_VERIFIED} - search only for users with verified/non-verified email (true/false)</li>
* <li>{@link UserModel#ENABLED} - search only for enabled/disabled users (true/false)</li>
* <li>{@link UserModel#IDP_ALIAS} - search only for users that have a federated identity
* from idp with the given alias configured (case sensitive string)</li>
* <li>{@link UserModel#IDP_USER_ID} - search for users with federated identity with
* the given userId (case sensitive string)</li>
* </ul> * </ul>
*
* This method is used by the REST API when querying users. * 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 realm a reference to the realm.
* @param firstResult first result to return. Ignored if negative. * @param params a map containing the search parameters.
* @param maxResults maximum number of results to return. Ignored if negative. * @param firstResult first result to return. Ignored if negative, zero, or {@code null}.
* @param maxResults maximum number of results to return. Ignored if negative or {@code null}.
* @return a non-null {@link Stream} of users that match the search criteria. * @return a non-null {@link Stream} of users that match the search criteria.
*/ */
default Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, Integer firstResult, Integer maxResults) { default Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params, Integer firstResult, Integer maxResults) {
List<UserModel> value = this.searchForUser(params, realm, firstResult == null ? -1 : firstResult, maxResults == null ? -1 : maxResults); List<UserModel> value = this.searchForUser(params, realm, firstResult == null ? -1 : firstResult, maxResults == null ? -1 : maxResults);
return value != null ? value.stream() : Stream.empty(); return value != null ? value.stream() : Stream.empty();
} }
/** /**
* Get users that belong to a specific group. Implementations do not have to search in UserFederatedStorageProvider * Get users that belong to a specific group.
* 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 list of all users that are members of the given group
* *
* @param realm
* @param group
* @return
* @deprecated Use {@link #getGroupMembersStream(RealmModel, GroupModel) getGroupMembersStream} instead. * @deprecated Use {@link #getGroupMembersStream(RealmModel, GroupModel) getGroupMembersStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group); List<UserModel> getGroupMembers(RealmModel realm, GroupModel group);
/** /**
* Obtains users that belong to a specific group. Implementations do not have to search in {@code UserFederatedStorageProvider} * Obtains users that belong to a specific group.
* as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
* *
* @param realm a reference to the realm. * @param realm a reference to the realm.
* @param group a reference to the group. * @param group a reference to the group.
@ -352,31 +427,26 @@ public interface UserQueryProvider {
} }
/** /**
* Get users that belong to a specific group. Implementations do not have to search in UserFederatedStorageProvider * Gets paginated list of users that belong to a specific group.
* 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 or zero.
* @param maxResults maximum number of results to return. Ignored if negative.
* @return paginated list of members of the given group
* *
* @param realm
* @param group
* @param firstResult
* @param maxResults
* @return
* @deprecated Use {@link #getGroupMembersStream(RealmModel, GroupModel, Integer, Integer) getGroupMembersStream} instead. * @deprecated Use {@link #getGroupMembersStream(RealmModel, GroupModel, Integer, Integer) getGroupMembersStream} instead.
*/ */
@Deprecated @Deprecated
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults); List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults);
/** /**
* Obtains users that belong to a specific group. Implementations do not have to search in {@code UserFederatedStorageProvider} * Obtains users that belong to a specific group.
* as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
* *
* @param realm a reference to the realm. * @param realm a reference to the realm.
* @param group a reference to the group. * @param group a reference to the group.
* @param firstResult first result to return. Ignored if negative. * @param firstResult first result to return. Ignored if negative, zero, or {@code null}.
* @param maxResults maximum number of results to return. Ignored if negative. * @param maxResults maximum number of results to return. Ignored if negative or {@code null}.
* @return a non-null {@link Stream} of users that belong to the group. * @return a non-null {@link Stream} of users that belong to the group.
*/ */
default Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) { default Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) {
@ -387,9 +457,10 @@ public interface UserQueryProvider {
/** /**
* Get users that belong to a specific role. * Get users that belong to a specific role.
* *
* @param realm * @param realm a reference to the realm
* @param role * @param role a reference to the role
* @return * @return a list of users that has the given role assigned
*
* @deprecated Use {@link #getRoleMembersStream(RealmModel, RoleModel) getRoleMembersStream} instead. * @deprecated Use {@link #getRoleMembersStream(RealmModel, RoleModel) getRoleMembersStream} instead.
*/ */
@Deprecated @Deprecated
@ -411,15 +482,17 @@ public interface UserQueryProvider {
/** /**
* 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 role * @param realm a reference to the realm
* @param firstResult * @param role a reference to the role
* @param maxResults * @param firstResult first result to return. Ignored if negative or zero.
* @return * @param maxResults maximum number of results to return. Ignored if negative.
* @return a paginated list of users that has the given role assigned
*
* @deprecated Use {@link #getRoleMembersStream(RealmModel, RoleModel, Integer, Integer) getRoleMembersStream} instead. * @deprecated Use {@link #getRoleMembersStream(RealmModel, RoleModel, Integer, Integer) getRoleMembersStream} instead.
*/ */
@Deprecated @Deprecated
default List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) { default List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
return this.getRoleMembersStream(realm, role, firstResult, maxResults).collect(Collectors.toList()); return Collections.emptyList();
} }
/** /**
@ -432,38 +505,33 @@ public interface UserQueryProvider {
* @return a non-null {@link Stream} of users that have the specified role. * @return a non-null {@link Stream} of users that have the specified role.
*/ */
default Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) { default Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) {
return Stream.empty(); return getRoleMembers(realm, role, firstResult == null ? -1 : firstResult, maxResults== null ? -1 : maxResults)
.stream();
} }
/** /**
* Search for users that have a specific attribute with a specific value. * Search for users that have a specific attribute with a specific value.
* Implementations do not have to search in UserFederatedStorageProvider
* as this is done automatically.
* *
* @see org.keycloak.storage.federated.UserFederatedStorageProvider * @param attrName a name of the attribute that will be searched
* @param attrValue a value of the attribute that will be searched
* @param realm a reference to the realm
* @return list of users with the given attribute name and value
* *
* @param attrName * @deprecated Use {@link #searchForUserByUserAttributeStream(RealmModel, String, String) searchForUserByUserAttributeStream}
* @param attrValue
* @param realm
* @return
* @deprecated Use {@link #searchForUserByUserAttributeStream(String, String, RealmModel) searchForUserByUserAttributeStream}
* instead. * instead.
*/ */
@Deprecated @Deprecated
List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm); List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm);
/** /**
* Searches for users that have a specific attribute with a specific value. Implementations do not have to search in * Searches for users that have a specific attribute with a specific value.
* {@code UserFederatedStorageProvider} as this is done automatically.
*
* @see org.keycloak.storage.federated.UserFederatedStorageProvider
* *
* @param realm a reference to the realm.
* @param attrName the attribute name. * @param attrName the attribute name.
* @param attrValue the attribute value. * @param attrValue the attribute value.
* @param realm a reference to the realm.
* @return a non-null {@link Stream} of users that match the search criteria. * @return a non-null {@link Stream} of users that match the search criteria.
*/ */
default Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) { default Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
List<UserModel> value = this.searchForUserByUserAttribute(attrName, attrValue, realm); List<UserModel> value = this.searchForUserByUserAttribute(attrName, attrValue, realm);
return value != null ? value.stream() : Stream.empty(); return value != null ? value.stream() : Stream.empty();
} }
@ -476,13 +544,62 @@ public interface UserQueryProvider {
* from the potential memory and performance optimizations of that approach. * from the potential memory and performance optimizations of that approach.
*/ */
interface Streams extends UserQueryProvider { interface Streams extends UserQueryProvider {
@Override
default int getUsersCount(RealmModel realm, String search) {
return (int) searchForUserStream(realm, search).count();
}
@Override
default int getUsersCount(String search, RealmModel realm) {
return getUsersCount(realm, search);
}
@Override
default int getUsersCount(RealmModel realm, String search, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) {
return 0;
}
return countUsersInGroups(searchForUserStream(realm, search), groupIds);
}
@Override
default int getUsersCount(String search, RealmModel realm, Set<String> groupIds) {
return getUsersCount(realm, search, groupIds);
}
@Override
default int getUsersCount(RealmModel realm, Map<String, String> params) {
return (int) searchForUserStream(realm, params).count();
}
@Override
default int getUsersCount( Map<String, String> params, RealmModel realm) {
return getUsersCount(realm, params);
}
@Override
default int getUsersCount(RealmModel realm, Map<String, String> params, Set<String> groupIds) {
if (groupIds == null || groupIds.isEmpty()) {
return 0;
}
return countUsersInGroups(searchForUserStream(realm, params), groupIds);
}
@Override
default int getUsersCount(Map<String, String> params, RealmModel realm, Set<String> groupIds) {
return getUsersCount(realm, params, groupIds);
}
@Override @Override
default List<UserModel> getUsers(RealmModel realm) { default List<UserModel> getUsers(RealmModel realm) {
return this.getUsersStream(realm).collect(Collectors.toList()); return this.getUsersStream(realm).collect(Collectors.toList());
} }
@Override @Override
Stream<UserModel> getUsersStream(RealmModel realm); default Stream<UserModel> getUsersStream(RealmModel realm) {
return getUsersStream(realm, null, null);
}
@Override @Override
default List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { default List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
@ -490,39 +607,43 @@ public interface UserQueryProvider {
} }
@Override @Override
Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults); Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults);
@Override @Override
default List<UserModel> searchForUser(String search, RealmModel realm) { default List<UserModel> searchForUser(String search, RealmModel realm) {
return this.searchForUserStream(search, realm).collect(Collectors.toList()); return this.searchForUserStream(realm, search).collect(Collectors.toList());
} }
@Override @Override
Stream<UserModel> searchForUserStream(String search, RealmModel realm); default Stream<UserModel> searchForUserStream(RealmModel realm, String search) {
return searchForUserStream(realm, search, null, null);
}
@Override @Override
default List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { default List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
return this.searchForUserStream(search, realm, firstResult, maxResults).collect(Collectors.toList()); return this.searchForUserStream(realm, search, firstResult, maxResults).collect(Collectors.toList());
} }
@Override @Override
Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults); Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults);
@Override @Override
default List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) { default List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
return this.searchForUserStream(params, realm).collect(Collectors.toList()); return this.searchForUserStream(realm, params).collect(Collectors.toList());
} }
@Override @Override
Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm); default Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params) {
return searchForUserStream(realm, params, null, null);
}
@Override @Override
default List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) { default List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
return this.searchForUserStream(params, realm, firstResult, maxResults).collect(Collectors.toList()); return this.searchForUserStream(realm, params, firstResult, maxResults).collect(Collectors.toList());
} }
@Override @Override
Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, Integer firstResult, Integer maxResults); Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params, Integer firstResult, Integer maxResults);
@Override @Override
default List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) { default List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
@ -530,7 +651,9 @@ public interface UserQueryProvider {
} }
@Override @Override
Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group); default Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return this.getGroupMembersStream(realm, group, null, null);
}
@Override @Override
default List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { default List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
@ -542,10 +665,10 @@ public interface UserQueryProvider {
@Override @Override
default List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) { default List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
return this.searchForUserByUserAttributeStream(attrName, attrValue, realm).collect(Collectors.toList()); return this.searchForUserByUserAttributeStream(realm, attrName, attrValue).collect(Collectors.toList());
} }
@Override @Override
Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm); Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue);
} }
} }

View file

@ -21,8 +21,9 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
/** /**
* Optional capability interface implemented by UserStorageProviders. * This is an optional capability interface that is intended to be implemented by any
* Implement this interface if your provider supports adding and removing users. * {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports addition of new users. You must
* implement this interface if you want to use this storage for registering new users.
* *
* @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 $
@ -37,9 +38,9 @@ public interface UserRegistrationProvider {
* Returning null is useful when you want optional support for adding users. For example, * Returning null is useful when you want optional support for adding users. For example,
* our LDAP provider can enable and disable the ability to add users. * our LDAP provider can enable and disable the ability to add users.
* *
* @param realm * @param realm a reference to the realm
* @param username * @param username a username the created user will be assigned
* @return * @return a model of created user
*/ */
UserModel addUser(RealmModel realm, String username); UserModel addUser(RealmModel realm, String username);
@ -54,9 +55,9 @@ public interface UserRegistrationProvider {
* this method will be called before local storage's removeUser() method is invoked. Also, * this method will be called before local storage's removeUser() method is invoked. Also,
* you DO NOT need to remove the imported user. The runtime will handle this for you. * you DO NOT need to remove the imported user. The runtime will handle this for you.
* *
* @param realm * @param realm a reference to the realm
* @param user * @param user a reference to the user that is removed
* @return * @return true if the user was removed, false otherwise
*/ */
boolean removeUser(RealmModel realm, UserModel user); boolean removeUser(RealmModel realm, UserModel user);

View file

@ -123,7 +123,7 @@ public abstract class AbstractIdpAuthenticator implements Authenticator {
ExistingUserInfo duplication = ExistingUserInfo.deserialize(existingUserId); ExistingUserInfo duplication = ExistingUserInfo.deserialize(existingUserId);
UserModel existingUser = session.users().getUserById(duplication.getExistingUserId(), realm); UserModel existingUser = session.users().getUserById(realm, duplication.getExistingUserId());
if (existingUser == null) { if (existingUser == null) {
throw new AuthenticationFlowException("User with ID '" + existingUserId + "' not found.", AuthenticationFlowError.INVALID_USER); throw new AuthenticationFlowException("User with ID '" + existingUserId + "' not found.", AuthenticationFlowError.INVALID_USER);
} }

View file

@ -120,13 +120,13 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
protected ExistingUserInfo checkExistingUser(AuthenticationFlowContext context, String username, SerializedBrokeredIdentityContext serializedCtx, BrokeredIdentityContext brokerContext) { protected ExistingUserInfo checkExistingUser(AuthenticationFlowContext context, String username, SerializedBrokeredIdentityContext serializedCtx, BrokeredIdentityContext brokerContext) {
if (brokerContext.getEmail() != null && !context.getRealm().isDuplicateEmailsAllowed()) { if (brokerContext.getEmail() != null && !context.getRealm().isDuplicateEmailsAllowed()) {
UserModel existingUser = context.getSession().users().getUserByEmail(brokerContext.getEmail(), context.getRealm()); UserModel existingUser = context.getSession().users().getUserByEmail(context.getRealm(), brokerContext.getEmail());
if (existingUser != null) { if (existingUser != null) {
return new ExistingUserInfo(existingUser.getId(), UserModel.EMAIL, existingUser.getEmail()); return new ExistingUserInfo(existingUser.getId(), UserModel.EMAIL, existingUser.getEmail());
} }
} }
UserModel existingUser = context.getSession().users().getUserByUsername(username, context.getRealm()); UserModel existingUser = context.getSession().users().getUserByUsername(context.getRealm(), username);
if (existingUser != null) { if (existingUser != null) {
return new ExistingUserInfo(existingUser.getId(), UserModel.USERNAME, existingUser.getUsername()); return new ExistingUserInfo(existingUser.getId(), UserModel.USERNAME, existingUser.getUsername());
} }

View file

@ -180,7 +180,7 @@ public class WebAuthnAuthenticator implements Authenticator, CredentialValidator
String userVerificationRequirement = getWebAuthnPolicy(context).getUserVerificationRequirement(); String userVerificationRequirement = getWebAuthnPolicy(context).getUserVerificationRequirement();
if (WebAuthnConstants.OPTION_REQUIRED.equals(userVerificationRequirement)) isUVFlagChecked = true; if (WebAuthnConstants.OPTION_REQUIRED.equals(userVerificationRequirement)) isUVFlagChecked = true;
UserModel user = session.users().getUserById(userId, context.getRealm()); UserModel user = session.users().getUserById(context.getRealm(), userId);
AuthenticationRequest authenticationRequest = new AuthenticationRequest( AuthenticationRequest authenticationRequest = new AuthenticationRequest(
credentialId, credentialId,

View file

@ -65,7 +65,7 @@ public class ResetCredentialChooseUser implements Authenticator, AuthenticatorFa
String actionTokenUserId = context.getAuthenticationSession().getAuthNote(DefaultActionTokenKey.ACTION_TOKEN_USER_ID); String actionTokenUserId = context.getAuthenticationSession().getAuthNote(DefaultActionTokenKey.ACTION_TOKEN_USER_ID);
if (actionTokenUserId != null) { if (actionTokenUserId != null) {
UserModel existingUser = context.getSession().users().getUserById(actionTokenUserId, context.getRealm()); UserModel existingUser = context.getSession().users().getUserById(context.getRealm(), actionTokenUserId);
// Action token logics handles checks for user ID validity and user being enabled // Action token logics handles checks for user ID validity and user being enabled
@ -96,9 +96,9 @@ public class ResetCredentialChooseUser implements Authenticator, AuthenticatorFa
username = username.trim(); username = username.trim();
RealmModel realm = context.getRealm(); RealmModel realm = context.getRealm();
UserModel user = context.getSession().users().getUserByUsername(username, realm); UserModel user = context.getSession().users().getUserByUsername(realm, username);
if (user == null && realm.isLoginWithEmailAllowed() && username.contains("@")) { if (user == null && realm.isLoginWithEmailAllowed() && username.contains("@")) {
user = context.getSession().users().getUserByEmail(username, realm); user = context.getSession().users().getUserByEmail(realm, username);
} }
context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username); context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);

View file

@ -63,7 +63,7 @@ public abstract class UserIdentityToModelMapper {
if (_customAttributes.isEmpty() || userIdentityValues.isEmpty() || (_customAttributes.size() != userIdentityValues.size())) { if (_customAttributes.isEmpty() || userIdentityValues.isEmpty() || (_customAttributes.size() != userIdentityValues.size())) {
return null; return null;
} }
Stream<UserModel> usersStream = session.users().searchForUserByUserAttributeStream(_customAttributes.get(0), userIdentityValues.get(0), context.getRealm()); Stream<UserModel> usersStream = session.users().searchForUserByUserAttributeStream(context.getRealm(), _customAttributes.get(0), userIdentityValues.get(0));
for (int i = 1; i <_customAttributes.size(); ++i) { for (int i = 1; i <_customAttributes.size(); ++i) {
String customAttribute = _customAttributes.get(i); String customAttribute = _customAttributes.get(i);

View file

@ -244,10 +244,10 @@ public class PolicyEvaluationService {
UserSessionModel userSession = null; UserSessionModel userSession = null;
if (subject != null) { if (subject != null) {
UserModel userModel = keycloakSession.users().getUserById(subject, realm); UserModel userModel = keycloakSession.users().getUserById(realm, subject);
if (userModel == null) { if (userModel == null) {
userModel = keycloakSession.users().getUserByUsername(subject, realm); userModel = keycloakSession.users().getUserByUsername(realm, subject);
} }
if (userModel != null) { if (userModel != null) {

View file

@ -387,7 +387,7 @@ public class ResourceSetService {
if (clientModel != null) { if (clientModel != null) {
owner = clientModel.getId(); owner = clientModel.getId();
} else { } else {
UserModel user = authorization.getKeycloakSession().users().getUserByUsername(owner, realm); UserModel user = authorization.getKeycloakSession().users().getUserByUsername(realm, owner);
if (user != null) { if (user != null) {
owner = user.getId(); owner = user.getId();

View file

@ -199,8 +199,8 @@ public class PolicyEvaluationResponseBuilder {
KeycloakSession keycloakSession = authorization.getKeycloakSession(); KeycloakSession keycloakSession = authorization.getKeycloakSession();
RealmModel realm = authorization.getRealm(); RealmModel realm = authorization.getRealm();
PermissionTicket ticket = tickets.get(0); PermissionTicket ticket = tickets.get(0);
UserModel userOwner = keycloakSession.users().getUserById(ticket.getOwner(), realm); UserModel userOwner = keycloakSession.users().getUserById(realm, ticket.getOwner());
UserModel requester = keycloakSession.users().getUserById(ticket.getRequester(), realm); UserModel requester = keycloakSession.users().getUserById(realm, ticket.getRequester());
String resourceOwner; String resourceOwner;
if (userOwner != null) { if (userOwner != null) {
resourceOwner = getUserEmailOrUserName(userOwner); resourceOwner = getUserEmailOrUserName(userOwner);

View file

@ -91,9 +91,9 @@ public class PermissionTicketService {
UserModel user = null; UserModel user = null;
if(representation.getRequester() != null) if(representation.getRequester() != null)
user = this.authorization.getKeycloakSession().userStorageManager().getUserById(representation.getRequester(), this.authorization.getRealm()); user = this.authorization.getKeycloakSession().userStorageManager().getUserById(this.authorization.getRealm(), representation.getRequester());
else else
user = this.authorization.getKeycloakSession().userStorageManager().getUserByUsername(representation.getRequesterName(), this.authorization.getRealm()); user = this.authorization.getKeycloakSession().userStorageManager().getUserByUsername(this.authorization.getRealm(), representation.getRequesterName());
if (user == null) if (user == null)
throw new ErrorResponseException("invalid_permission", "Requester does not exists in this server as user.", Response.Status.BAD_REQUEST); throw new ErrorResponseException("invalid_permission", "Requester does not exists in this server as user.", Response.Status.BAD_REQUEST);
@ -229,13 +229,13 @@ public class PermissionTicketService {
private String getUserId(String userIdOrName) { private String getUserId(String userIdOrName) {
UserProvider userProvider = authorization.getKeycloakSession().users(); UserProvider userProvider = authorization.getKeycloakSession().users();
RealmModel realm = authorization.getRealm(); RealmModel realm = authorization.getRealm();
UserModel userModel = userProvider.getUserById(userIdOrName, realm); UserModel userModel = userProvider.getUserById(realm, userIdOrName);
if (userModel != null) { if (userModel != null) {
return userModel.getId(); return userModel.getId();
} }
userModel = userProvider.getUserByUsername(userIdOrName, realm); userModel = userProvider.getUserByUsername(realm, userIdOrName);
if (userModel != null) { if (userModel != null) {
return userModel.getId(); return userModel.getId();

View file

@ -250,7 +250,7 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
} }
protected Response exchangeStoredToken(UriInfo uriInfo, EventBuilder event, ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject) { protected Response exchangeStoredToken(UriInfo uriInfo, EventBuilder event, ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject) {
FederatedIdentityModel model = session.users().getFederatedIdentity(tokenSubject, getConfig().getAlias(), authorizedClient.getRealm()); FederatedIdentityModel model = session.users().getFederatedIdentity(authorizedClient.getRealm(), tokenSubject, getConfig().getAlias());
if (model == null || model.getToken() == null) { if (model == null || model.getToken() == null) {
event.detail(Details.REASON, "requested_issuer is not linked"); event.detail(Details.REASON, "requested_issuer is not linked");
event.error(Errors.INVALID_TOKEN); event.error(Errors.INVALID_TOKEN);

View file

@ -169,7 +169,7 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
@Override @Override
protected Response exchangeStoredToken(UriInfo uriInfo, EventBuilder event, ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject) { protected Response exchangeStoredToken(UriInfo uriInfo, EventBuilder event, ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject) {
FederatedIdentityModel model = session.users().getFederatedIdentity(tokenSubject, getConfig().getAlias(), authorizedClient.getRealm()); FederatedIdentityModel model = session.users().getFederatedIdentity(authorizedClient.getRealm(), tokenSubject, getConfig().getAlias());
if (model == null || model.getToken() == null) { if (model == null || model.getToken() == null) {
event.detail(Details.REASON, "requested_issuer is not linked"); event.detail(Details.REASON, "requested_issuer is not linked");
event.error(Errors.INVALID_TOKEN); event.error(Errors.INVALID_TOKEN);

View file

@ -63,7 +63,7 @@ public class EmailEventListenerProvider implements EventListenerProvider {
private void sendEmail(Event event) { private void sendEmail(Event event) {
RealmModel realm = model.getRealm(event.getRealmId()); RealmModel realm = model.getRealm(event.getRealmId());
UserModel user = session.users().getUserById(event.getUserId(), realm); UserModel user = session.users().getUserById(realm, event.getUserId());
if (user != null && user.getEmail() != null && user.isEmailVerified()) { if (user != null && user.getEmail() != null && user.isEmailVerified()) {
try { try {
emailTemplateProvider.setRealm(realm).setUser(user).sendEvent(event); emailTemplateProvider.setRealm(realm).setUser(user).sendEvent(event);

View file

@ -458,7 +458,7 @@ public class ExportUtils {
UserRepresentation userRep = ModelToRepresentation.toRepresentation(session, realm, user); UserRepresentation userRep = ModelToRepresentation.toRepresentation(session, realm, user);
// Social links // Social links
List<FederatedIdentityRepresentation> socialLinkReps = session.users().getFederatedIdentitiesStream(user, realm) List<FederatedIdentityRepresentation> socialLinkReps = session.users().getFederatedIdentitiesStream(realm, user)
.map(ExportUtils::exportSocialLink).collect(Collectors.toList()); .map(ExportUtils::exportSocialLink).collect(Collectors.toList());
if (socialLinkReps.size() > 0) { if (socialLinkReps.size() > 0) {
userRep.setFederatedIdentities(socialLinkReps); userRep.setFederatedIdentities(socialLinkReps);

View file

@ -54,7 +54,7 @@ public class AccountFederatedIdentityBean {
.map(provider -> { .map(provider -> {
String providerId = provider.getAlias(); String providerId = provider.getAlias();
FederatedIdentityModel identity = getIdentity(session.users().getFederatedIdentitiesStream(user, realm), providerId); FederatedIdentityModel identity = getIdentity(session.users().getFederatedIdentitiesStream(realm, user), providerId);
if (identity != null) { if (identity != null) {
availableIdentities.getAndIncrement(); availableIdentities.getAndIncrement();

View file

@ -150,7 +150,7 @@ public class AuthorizationBean {
private boolean granted; private boolean granted;
public RequesterBean(PermissionTicket ticket, AuthorizationProvider authorization) { public RequesterBean(PermissionTicket ticket, AuthorizationProvider authorization) {
this.requester = authorization.getKeycloakSession().users().getUserById(ticket.getRequester(), authorization.getRealm()); this.requester = authorization.getKeycloakSession().users().getUserById(authorization.getRealm(), ticket.getRequester());
granted = ticket.isGranted(); granted = ticket.isGranted();
createdTimestamp = ticket.getCreatedTimestamp(); createdTimestamp = ticket.getCreatedTimestamp();
grantedTimestamp = ticket.getGrantedTimestamp(); grantedTimestamp = ticket.getGrantedTimestamp();
@ -236,7 +236,7 @@ public class AuthorizationBean {
RealmModel realm = authorization.getRealm(); RealmModel realm = authorization.getRealm();
resourceServer = new ResourceServerBean(realm.getClientById(resource.getResourceServer())); resourceServer = new ResourceServerBean(realm.getClientById(resource.getResourceServer()));
this.resource = resource; this.resource = resource;
userOwner = authorization.getKeycloakSession().users().getUserById(resource.getOwner(), realm); userOwner = authorization.getKeycloakSession().users().getUserById(realm, resource.getOwner());
if (userOwner == null) { if (userOwner == null) {
clientOwner = realm.getClientById(resource.getOwner()); clientOwner = realm.getClientById(resource.getOwner());
ownerName = clientOwner.getClientId(); ownerName = clientOwner.getClientId();

View file

@ -54,12 +54,12 @@ public class LoginFormsUtil {
throw new IllegalStateException("USERNAME_EDIT_DISABLED but username not known"); throw new IllegalStateException("USERNAME_EDIT_DISABLED but username not known");
} }
UserModel user = session.users().getUserByUsername(username, realm); UserModel user = session.users().getUserByUsername(realm, username);
if (user == null || !user.isEnabled()) { if (user == null || !user.isEnabled()) {
throw new IllegalStateException("User " + username + " not found or disabled"); throw new IllegalStateException("User " + username + " not found or disabled");
} }
Set<String> federatedIdentities = session.users().getFederatedIdentitiesStream(user, realm) Set<String> federatedIdentities = session.users().getFederatedIdentitiesStream(realm, user)
.map(federatedIdentityModel -> federatedIdentityModel.getIdentityProvider()) .map(federatedIdentityModel -> federatedIdentityModel.getIdentityProvider())
.collect(Collectors.toSet()); .collect(Collectors.toSet());

View file

@ -59,10 +59,10 @@ public class UsersPartialImport extends AbstractPartialImport<UserRepresentation
String userName = user.getUsername(); String userName = user.getUsername();
if (userName != null) { if (userName != null) {
return session.users().getUserByUsername(userName, realm).getId(); return session.users().getUserByUsername(realm, userName).getId();
} else if (!realm.isDuplicateEmailsAllowed()) { } else if (!realm.isDuplicateEmailsAllowed()) {
String email = user.getEmail(); String email = user.getEmail();
return session.users().getUserByEmail(email, realm).getId(); return session.users().getUserByEmail(realm, email).getId();
} }
return null; return null;
@ -74,12 +74,12 @@ public class UsersPartialImport extends AbstractPartialImport<UserRepresentation
} }
private boolean userNameExists(RealmModel realm, KeycloakSession session, UserRepresentation user) { private boolean userNameExists(RealmModel realm, KeycloakSession session, UserRepresentation user) {
return session.users().getUserByUsername(user.getUsername(), realm) != null; return session.users().getUserByUsername(realm, user.getUsername()) != null;
} }
private boolean userEmailExists(RealmModel realm, KeycloakSession session, UserRepresentation user) { private boolean userEmailExists(RealmModel realm, KeycloakSession session, UserRepresentation user) {
return (user.getEmail() != null) && !realm.isDuplicateEmailsAllowed() && return (user.getEmail() != null) && !realm.isDuplicateEmailsAllowed() &&
(session.users().getUserByEmail(user.getEmail(), realm) != null); (session.users().getUserByEmail(realm, user.getEmail()) != null);
} }
@Override @Override
@ -98,9 +98,9 @@ public class UsersPartialImport extends AbstractPartialImport<UserRepresentation
@Override @Override
public void remove(RealmModel realm, KeycloakSession session, UserRepresentation user) { public void remove(RealmModel realm, KeycloakSession session, UserRepresentation user) {
UserModel userModel = session.users().getUserByUsername(user.getUsername(), realm); UserModel userModel = session.users().getUserByUsername(realm, user.getUsername());
if (userModel == null && !realm.isDuplicateEmailsAllowed()) { if (userModel == null && !realm.isDuplicateEmailsAllowed()) {
userModel = session.users().getUserByEmail(user.getEmail(), realm); userModel = session.users().getUserByEmail(realm, user.getEmail());
} }
if (userModel != null) { if (userModel != null) {
boolean success = new UserManager(session).removeUser(realm, userModel); boolean success = new UserManager(session).removeUser(realm, userModel);

View file

@ -294,14 +294,14 @@ public class TokenManager {
*/ */
public static UserModel lookupUserFromStatelessToken(KeycloakSession session, RealmModel realm, AccessToken token) { public static UserModel lookupUserFromStatelessToken(KeycloakSession session, RealmModel realm, AccessToken token) {
// Try to lookup user based on "sub" claim. It should work for most cases with some rare exceptions (EG. OIDC "pairwise" subjects) // Try to lookup user based on "sub" claim. It should work for most cases with some rare exceptions (EG. OIDC "pairwise" subjects)
UserModel user = session.users().getUserById(token.getSubject(), realm); UserModel user = session.users().getUserById(realm, token.getSubject());
if (user != null) { if (user != null) {
return user; return user;
} }
// Fallback to lookup user based on username (preferred_username claim) // Fallback to lookup user based on username (preferred_username claim)
if (token.getPreferredUsername() != null) { if (token.getPreferredUsername() != null) {
user = session.users().getUserByUsername(token.getPreferredUsername(), realm); user = session.users().getUserByUsername(realm, token.getPreferredUsername());
if (user != null) { if (user != null) {
return user; return user;
} }

View file

@ -834,9 +834,9 @@ public class TokenEndpoint {
String requestedSubject = formParams.getFirst(OAuth2Constants.REQUESTED_SUBJECT); String requestedSubject = formParams.getFirst(OAuth2Constants.REQUESTED_SUBJECT);
if (requestedSubject != null) { if (requestedSubject != null) {
event.detail(Details.REQUESTED_SUBJECT, requestedSubject); event.detail(Details.REQUESTED_SUBJECT, requestedSubject);
UserModel requestedUser = session.users().getUserByUsername(requestedSubject, realm); UserModel requestedUser = session.users().getUserByUsername(realm, requestedSubject);
if (requestedUser == null) { if (requestedUser == null) {
requestedUser = session.users().getUserById(requestedSubject, realm); requestedUser = session.users().getUserById(realm, requestedSubject);
} }
if (requestedUser == null) { if (requestedUser == null) {
@ -1135,7 +1135,7 @@ public class TokenEndpoint {
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(), FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(),
context.getUsername(), context.getToken()); context.getUsername(), context.getToken());
UserModel user = this.session.users().getUserByFederatedIdentity(federatedIdentityModel, realm); UserModel user = this.session.users().getUserByFederatedIdentity(realm, federatedIdentityModel);
if (user == null) { if (user == null) {
@ -1154,14 +1154,14 @@ public class TokenEndpoint {
username = username.trim(); username = username.trim();
context.setModelUsername(username); context.setModelUsername(username);
if (context.getEmail() != null && !realm.isDuplicateEmailsAllowed()) { if (context.getEmail() != null && !realm.isDuplicateEmailsAllowed()) {
UserModel existingUser = session.users().getUserByEmail(context.getEmail(), realm); UserModel existingUser = session.users().getUserByEmail(realm, context.getEmail());
if (existingUser != null) { if (existingUser != null) {
event.error(Errors.FEDERATED_IDENTITY_EXISTS); event.error(Errors.FEDERATED_IDENTITY_EXISTS);
throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "User already exists", Response.Status.BAD_REQUEST); throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "User already exists", Response.Status.BAD_REQUEST);
} }
} }
UserModel existingUser = session.users().getUserByUsername(username, realm); UserModel existingUser = session.users().getUserByUsername(realm, username);
if (existingUser != null) { if (existingUser != null) {
event.error(Errors.FEDERATED_IDENTITY_EXISTS); event.error(Errors.FEDERATED_IDENTITY_EXISTS);
throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "User already exists", Response.Status.BAD_REQUEST); throw new CorsErrorResponseException(cors, Errors.INVALID_TOKEN, "User already exists", Response.Status.BAD_REQUEST);

View file

@ -34,7 +34,7 @@ public class HttpBasicAuthenticator implements Authenticator {
if (usernameAndPassword != null) { if (usernameAndPassword != null) {
final RealmModel realm = context.getRealm(); final RealmModel realm = context.getRealm();
final String username = usernameAndPassword[0]; final String username = usernameAndPassword[0];
final UserModel user = context.getSession().users().getUserByUsername(username, realm); final UserModel user = context.getSession().users().getUserByUsername(realm, username);
// to allow success/failure logging for brute force // to allow success/failure logging for brute force
context.getEvent().detail(Details.USERNAME, username); context.getEvent().detail(Details.USERNAME, username);

View file

@ -38,7 +38,7 @@ public class DynamicClientRegisterContext implements ClientUpdateContext {
this.token = token; this.token = token;
if (token != null) { if (token != null) {
if (token.getSubject() != null) { if (token.getSubject() != null) {
this.user = context.getSession().users().getUserById(token.getSubject(), realm); this.user = context.getSession().users().getUserById(realm, token.getSubject());
} }
if (token.getIssuedFor() != null) { if (token.getIssuedFor() != null) {
this.client = realm.getClientByClientId(token.getIssuedFor()); this.client = realm.getClientByClientId(token.getIssuedFor());

View file

@ -40,7 +40,7 @@ public class DynamicClientUpdateContext implements ClientUpdateContext {
this.token = token; this.token = token;
if (token != null) { if (token != null) {
if (token.getSubject() != null) { if (token.getSubject() != null) {
this.user = context.getSession().users().getUserById(token.getSubject(), realm); this.user = context.getSession().users().getUserById(realm, token.getSubject());
} }
if (token.getIssuedFor() != null) { if (token.getIssuedFor() != null) {
this.client = realm.getClientByClientId(token.getIssuedFor()); this.client = realm.getClientByClientId(token.getIssuedFor());

View file

@ -100,7 +100,7 @@ public class ClientUpdateSourceGroupsCondition implements ClientPolicyConditionP
private boolean isGroupMatched(String subjectId) { private boolean isGroupMatched(String subjectId) {
if (subjectId == null) return false; if (subjectId == null) return false;
return isGroupsMatched(session.users().getUserById(subjectId, session.getContext().getRealm())); return isGroupsMatched(session.users().getUserById(session.getContext().getRealm(), subjectId));
} }
private boolean isGroupsMatched(UserModel user) { private boolean isGroupsMatched(UserModel user) {

View file

@ -99,7 +99,7 @@ public class ClientUpdateSourceRolesCondition implements ClientPolicyConditionPr
private boolean isRoleMatched(String subjectId) { private boolean isRoleMatched(String subjectId) {
if (subjectId == null) return false; if (subjectId == null) return false;
return isRolesMatched(session.users().getUserById(subjectId, session.getContext().getRealm())); return isRolesMatched(session.users().getUserById(session.getContext().getRealm(), subjectId));
} }
private boolean isRolesMatched(UserModel user) { private boolean isRolesMatched(UserModel user) {

View file

@ -291,7 +291,7 @@ public class ClientRegistrationAuth {
private boolean hasRoleInModel(String[] roles) { private boolean hasRoleInModel(String[] roles) {
ClientModel roleNamespace; ClientModel roleNamespace;
UserModel user = session.users().getUserById(jwt.getSubject(), realm); UserModel user = session.users().getUserById(realm, jwt.getSubject());
if (user == null) { if (user == null) {
return false; return false;
} }

View file

@ -103,7 +103,7 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
logFailure(event); logFailure(event);
String userId = event.userId; String userId = event.userId;
UserModel user = session.users().getUserById(userId, realm); UserModel user = session.users().getUserById(realm, userId);
if (user == null) { if (user == null) {
return; return;
} }
@ -251,7 +251,7 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
private void success(KeycloakSession session, LoginEvent event) { private void success(KeycloakSession session, LoginEvent event) {
String userId = event.userId; String userId = event.userId;
UserModel model = session.users().getUserById(userId, getRealmModel(session, event)); UserModel model = session.users().getUserById(getRealmModel(session, event), userId);
UserLoginFailureModel user = getUserModel(session, event); UserLoginFailureModel user = getUserModel(session, event);
if(user == null) return; if(user == null) return;

View file

@ -485,7 +485,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(providerId); IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(providerId);
if (identityProviderConfig.isStoreToken()) { if (identityProviderConfig.isStoreToken()) {
FederatedIdentityModel identity = this.session.users().getFederatedIdentity(authResult.getUser(), providerId, this.realmModel); FederatedIdentityModel identity = this.session.users().getFederatedIdentity(this.realmModel, authResult.getUser(), providerId);
if (identity == null) { if (identity == null) {
return corsResponse(badRequest("User [" + authResult.getUser().getId() + "] is not associated with identity provider [" + providerId + "]."), clientModel); return corsResponse(badRequest("User [" + authResult.getUser().getId() + "] is not associated with identity provider [" + providerId + "]."), clientModel);
@ -557,12 +557,12 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
.detail(Details.IDENTITY_PROVIDER, providerId) .detail(Details.IDENTITY_PROVIDER, providerId)
.detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername()); .detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername());
UserModel federatedUser = this.session.users().getUserByFederatedIdentity(federatedIdentityModel, this.realmModel); UserModel federatedUser = this.session.users().getUserByFederatedIdentity(this.realmModel, federatedIdentityModel);
boolean shouldMigrateId = false; boolean shouldMigrateId = false;
// try to find the user using legacy ID // try to find the user using legacy ID
if (federatedUser == null && context.getLegacyId() != null) { if (federatedUser == null && context.getLegacyId() != null) {
federatedIdentityModel = new FederatedIdentityModel(federatedIdentityModel, context.getLegacyId()); federatedIdentityModel = new FederatedIdentityModel(federatedIdentityModel, context.getLegacyId());
federatedUser = this.session.users().getUserByFederatedIdentity(federatedIdentityModel, this.realmModel); federatedUser = this.session.users().getUserByFederatedIdentity(this.realmModel, federatedIdentityModel);
shouldMigrateId = true; shouldMigrateId = true;
} }
@ -962,7 +962,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
if (federatedUser != null) { if (federatedUser != null) {
if (context.getIdpConfig().isStoreToken()) { if (context.getIdpConfig().isStoreToken()) {
FederatedIdentityModel oldModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel); FederatedIdentityModel oldModel = this.session.users().getFederatedIdentity(this.realmModel, federatedUser, context.getIdpConfig().getAlias());
if (!ObjectUtil.isEqualOrBothNull(context.getToken(), oldModel.getToken())) { if (!ObjectUtil.isEqualOrBothNull(context.getToken(), oldModel.getToken())) {
this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, newModel); this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, newModel);
if (isDebugEnabled()) { if (isDebugEnabled()) {
@ -1010,7 +1010,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
private void updateFederatedIdentity(BrokeredIdentityContext context, UserModel federatedUser) { private void updateFederatedIdentity(BrokeredIdentityContext context, UserModel federatedUser) {
FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel); FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(this.realmModel, federatedUser, context.getIdpConfig().getAlias());
if (context.getIdpConfig().getSyncMode() == IdentityProviderSyncMode.FORCE) { if (context.getIdpConfig().getSyncMode() == IdentityProviderSyncMode.FORCE) {
setBasicUserAttributes(context, federatedUser); setBasicUserAttributes(context, federatedUser);
@ -1041,7 +1041,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
} }
private void migrateFederatedIdentityId(BrokeredIdentityContext context, UserModel federatedUser) { private void migrateFederatedIdentityId(BrokeredIdentityContext context, UserModel federatedUser) {
FederatedIdentityModel identityModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel); FederatedIdentityModel identityModel = this.session.users().getFederatedIdentity(this.realmModel, federatedUser, context.getIdpConfig().getAlias());
FederatedIdentityModel migratedIdentityModel = new FederatedIdentityModel(identityModel, context.getId()); FederatedIdentityModel migratedIdentityModel = new FederatedIdentityModel(identityModel, context.getId());
// since ID is a partial key we need to recreate the identity // since ID is a partial key we need to recreate the identity

View file

@ -18,7 +18,6 @@ package org.keycloak.services.resources;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.common.util.Resteasy; import org.keycloak.common.util.Resteasy;
import org.keycloak.config.ConfigProviderFactory; import org.keycloak.config.ConfigProviderFactory;
@ -371,7 +370,7 @@ public class KeycloakApplication extends Application {
UserProvider users = session.users(); UserProvider users = session.users();
if (users.getUserByUsername(userRep.getUsername(), realm) != null) { if (users.getUserByUsername(realm, userRep.getUsername()) != null) {
ServicesLogger.LOGGER.notCreatingExistingUser(userRep.getUsername()); ServicesLogger.LOGGER.notCreatingExistingUser(userRep.getUsername());
} else { } else {
UserModel user = users.addUser(realm, userRep.getUsername()); UserModel user = users.addUser(realm, userRep.getUsername());

View file

@ -137,7 +137,7 @@ public class LoginActionsServiceChecks {
* it optionally also injects the user using the given function (e.g. into session context). * it optionally also injects the user using the given function (e.g. into session context).
*/ */
public static void checkIsUserValid(KeycloakSession session, RealmModel realm, String userId, Consumer<UserModel> userSetter) throws VerificationException { public static void checkIsUserValid(KeycloakSession session, RealmModel realm, String userId, Consumer<UserModel> userSetter) throws VerificationException {
UserModel user = userId == null ? null : session.users().getUserById(userId, realm); UserModel user = userId == null ? null : session.users().getUserById(realm, userId);
if (user == null) { if (user == null) {
throw new ExplainedVerificationException(Errors.USER_NOT_FOUND, Messages.INVALID_USER); throw new ExplainedVerificationException(Errors.USER_NOT_FOUND, Messages.INVALID_USER);

View file

@ -709,11 +709,11 @@ public class AccountFormService extends AbstractSecuredLocalService {
return account.setError(Response.Status.INTERNAL_SERVER_ERROR, Messages.IDENTITY_PROVIDER_REDIRECT_ERROR).createResponse(AccountPages.FEDERATED_IDENTITY); return account.setError(Response.Status.INTERNAL_SERVER_ERROR, Messages.IDENTITY_PROVIDER_REDIRECT_ERROR).createResponse(AccountPages.FEDERATED_IDENTITY);
} }
case REMOVE: case REMOVE:
FederatedIdentityModel link = session.users().getFederatedIdentity(user, providerId, realm); FederatedIdentityModel link = session.users().getFederatedIdentity(realm, user, providerId);
if (link != null) { if (link != null) {
// Removing last social provider is not possible if you don't have other possibility to authenticate // Removing last social provider is not possible if you don't have other possibility to authenticate
if (session.users().getFederatedIdentitiesStream(user, realm).count() > 1 || user.getFederationLink() != null || isPasswordSet(session, realm, user)) { if (session.users().getFederatedIdentitiesStream(realm, user).count() > 1 || user.getFederationLink() != null || isPasswordSet(session, realm, user)) {
session.users().removeFederatedIdentity(realm, user, providerId); session.users().removeFederatedIdentity(realm, user, providerId);
logger.debugv("Social provider {0} removed successfully from user {1}", providerId, user.getUsername()); logger.debugv("Social provider {0} removed successfully from user {1}", providerId, user.getUsername());
@ -833,7 +833,7 @@ public class AccountFormService extends AbstractSecuredLocalService {
Map<String, String> filters = new HashMap<>(); Map<String, String> filters = new HashMap<>();
filters.put(PermissionTicket.RESOURCE, resource.getId()); filters.put(PermissionTicket.RESOURCE, resource.getId());
filters.put(PermissionTicket.REQUESTER, session.users().getUserByUsername(requester, realm).getId()); filters.put(PermissionTicket.REQUESTER, session.users().getUserByUsername(realm, requester).getId());
if (isRevoke) { if (isRevoke) {
filters.put(PermissionTicket.GRANTED, Boolean.TRUE.toString()); filters.put(PermissionTicket.GRANTED, Boolean.TRUE.toString());
@ -909,14 +909,14 @@ public class AccountFormService extends AbstractSecuredLocalService {
} }
for (String id : userIds) { for (String id : userIds) {
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(realm, id);
if (user == null) { if (user == null) {
user = session.users().getUserByUsername(id, realm); user = session.users().getUserByUsername(realm, id);
} }
if (user == null) { if (user == null) {
user = session.users().getUserByEmail(id, realm); user = session.users().getUserByEmail(realm, id);
} }
if (user == null) { if (user == null) {

View file

@ -119,7 +119,7 @@ public class LinkedAccountsResource {
public SortedSet<LinkedAccountRepresentation> getLinkedAccounts(KeycloakSession session, RealmModel realm, UserModel user) { public SortedSet<LinkedAccountRepresentation> getLinkedAccounts(KeycloakSession session, RealmModel realm, UserModel user) {
Set<String> socialIds = findSocialIds(); Set<String> socialIds = findSocialIds();
return realm.getIdentityProvidersStream().filter(IdentityProviderModel::isEnabled) return realm.getIdentityProvidersStream().filter(IdentityProviderModel::isEnabled)
.map(provider -> toLinkedAccountRepresentation(provider, socialIds, session.users().getFederatedIdentitiesStream(user, realm))) .map(provider -> toLinkedAccountRepresentation(provider, socialIds, session.users().getFederatedIdentitiesStream(realm, user)))
.collect(Collectors.toCollection(TreeSet::new)); .collect(Collectors.toCollection(TreeSet::new));
} }
@ -209,13 +209,13 @@ public class LinkedAccountsResource {
return ErrorResponse.error(errorMessage, Response.Status.BAD_REQUEST); return ErrorResponse.error(errorMessage, Response.Status.BAD_REQUEST);
} }
FederatedIdentityModel link = session.users().getFederatedIdentity(user, providerId, realm); FederatedIdentityModel link = session.users().getFederatedIdentity(realm, user, providerId);
if (link == null) { if (link == null) {
return ErrorResponse.error(Messages.FEDERATED_IDENTITY_NOT_ACTIVE, Response.Status.BAD_REQUEST); return ErrorResponse.error(Messages.FEDERATED_IDENTITY_NOT_ACTIVE, Response.Status.BAD_REQUEST);
} }
// Removing last social provider is not possible if you don't have other possibility to authenticate // Removing last social provider is not possible if you don't have other possibility to authenticate
if (!(session.users().getFederatedIdentitiesStream(user, realm).count() > 1 || user.getFederationLink() != null || isPasswordSet())) { if (!(session.users().getFederatedIdentitiesStream(realm, user).count() > 1 || user.getFederationLink() != null || isPasswordSet())) {
return ErrorResponse.error(Messages.FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER, Response.Status.BAD_REQUEST); return ErrorResponse.error(Messages.FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER, Response.Status.BAD_REQUEST);
} }

View file

@ -149,7 +149,7 @@ public abstract class AbstractResourceService {
} }
Permission(String userId, AuthorizationProvider provider) { Permission(String userId, AuthorizationProvider provider) {
UserModel user = provider.getKeycloakSession().users().getUserById(userId, provider.getRealm()); UserModel user = provider.getKeycloakSession().users().getUserById(provider.getRealm(), userId);
setUsername(user.getUsername()); setUsername(user.getUsername());
setFirstName(user.getFirstName()); setFirstName(user.getFirstName());

View file

@ -220,10 +220,10 @@ public class ResourceService extends AbstractResourceService {
private UserModel getUser(String requester) { private UserModel getUser(String requester) {
UserProvider users = provider.getKeycloakSession().users(); UserProvider users = provider.getKeycloakSession().users();
UserModel user = users.getUserByUsername(requester, provider.getRealm()); UserModel user = users.getUserByUsername(provider.getRealm(), requester);
if (user == null) { if (user == null) {
user = users.getUserByEmail(requester, provider.getRealm()); user = users.getUserByEmail(provider.getRealm(), requester);
} }
if (user == null) { if (user == null) {

View file

@ -79,7 +79,7 @@ public class AttackDetectionResource {
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) { public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) {
UserModel user = session.users().getUserById(userId, realm); UserModel user = session.users().getUserById(realm, userId);
if (user == null) { if (user == null) {
auth.users().requireView(); auth.users().requireView();
} else { } else {
@ -123,7 +123,7 @@ public class AttackDetectionResource {
@Path("brute-force/users/{userId}") @Path("brute-force/users/{userId}")
@DELETE @DELETE
public void clearBruteForceForUser(@PathParam("userId") String userId) { public void clearBruteForceForUser(@PathParam("userId") String userId) {
UserModel user = session.users().getUserById(userId, realm); UserModel user = session.users().getUserById(realm, userId);
if (user == null) { if (user == null) {
auth.users().requireManage(); auth.users().requireManage();
} else { } else {

View file

@ -160,7 +160,7 @@ public class ClientScopeEvaluateResource {
throw new NotFoundException("No userId provided"); throw new NotFoundException("No userId provided");
} }
UserModel user = session.users().getUserById(userId, realm); UserModel user = session.users().getUserById(realm, userId);
if (user == null) { if (user == null) {
throw new NotFoundException("No user found"); throw new NotFoundException("No user found");
} }

View file

@ -215,7 +215,7 @@ public class IdentityProviderResource {
private static void updateUsersAfterProviderAliasChange(Stream<UserModel> users, String oldProviderId, String newProviderId, RealmModel realm, KeycloakSession session) { private static void updateUsersAfterProviderAliasChange(Stream<UserModel> users, String oldProviderId, String newProviderId, RealmModel realm, KeycloakSession session) {
users.forEach(user -> { users.forEach(user -> {
FederatedIdentityModel federatedIdentity = session.users().getFederatedIdentity(user, oldProviderId, realm); FederatedIdentityModel federatedIdentity = session.users().getFederatedIdentity(realm, user, oldProviderId);
if (federatedIdentity != null) { if (federatedIdentity != null) {
// Remove old link first // Remove old link first
session.users().removeFederatedIdentity(realm, user, oldProviderId); session.users().removeFederatedIdentity(realm, user, oldProviderId);

View file

@ -380,7 +380,7 @@ public class UserResource {
private Stream<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) { private Stream<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) {
Set<String> idps = realm.getIdentityProvidersStream().map(IdentityProviderModel::getAlias).collect(Collectors.toSet()); Set<String> idps = realm.getIdentityProvidersStream().map(IdentityProviderModel::getAlias).collect(Collectors.toSet());
return session.users().getFederatedIdentitiesStream(user, realm) return session.users().getFederatedIdentitiesStream(realm, user)
.filter(identity -> idps.contains(identity.getIdentityProvider())) .filter(identity -> idps.contains(identity.getIdentityProvider()))
.map(ModelToRepresentation::toRepresentation); .map(ModelToRepresentation::toRepresentation);
} }
@ -397,7 +397,7 @@ public class UserResource {
@NoCache @NoCache
public Response addFederatedIdentity(final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) { public Response addFederatedIdentity(final @PathParam("provider") String provider, FederatedIdentityRepresentation rep) {
auth.users().requireManage(user); auth.users().requireManage(user);
if (session.users().getFederatedIdentity(user, provider, realm) != null) { if (session.users().getFederatedIdentity(realm, user, provider) != null) {
return ErrorResponse.exists("User is already linked with provider"); return ErrorResponse.exists("User is already linked with provider");
} }

View file

@ -133,12 +133,12 @@ public class UsersResource {
} }
// Double-check duplicated username and email here due to federation // Double-check duplicated username and email here due to federation
if (session.users().getUserByUsername(username, realm) != null) { if (session.users().getUserByUsername(realm, username) != null) {
return ErrorResponse.exists("User exists with same username"); return ErrorResponse.exists("User exists with same username");
} }
if (rep.getEmail() != null && !realm.isDuplicateEmailsAllowed()) { if (rep.getEmail() != null && !realm.isDuplicateEmailsAllowed()) {
try { try {
if(session.users().getUserByEmail(rep.getEmail(), realm) != null) { if(session.users().getUserByEmail(realm, rep.getEmail()) != null) {
return ErrorResponse.exists("User exists with same email"); return ErrorResponse.exists("User exists with same email");
} }
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
@ -192,7 +192,7 @@ public class UsersResource {
*/ */
@Path("{id}") @Path("{id}")
public UserResource user(final @PathParam("id") String id) { public UserResource user(final @PathParam("id") String id) {
UserModel user = session.users().getUserById(id, realm); UserModel user = session.users().getUserById(realm, id);
if (user == null) { if (user == null) {
// we do this to make sure somebody can't phish ids // we do this to make sure somebody can't phish ids
if (auth.users().canQuery()) throw new NotFoundException("User not found"); if (auth.users().canQuery()) throw new NotFoundException("User not found");
@ -251,7 +251,7 @@ public class UsersResource {
if (search != null) { if (search != null) {
if (search.startsWith(SEARCH_ID_PARAMETER)) { if (search.startsWith(SEARCH_ID_PARAMETER)) {
UserModel userModel = UserModel userModel =
session.users().getUserById(search.substring(SEARCH_ID_PARAMETER.length()).trim(), realm); session.users().getUserById(realm, search.substring(SEARCH_ID_PARAMETER.length()).trim());
if (userModel != null) { if (userModel != null) {
userModels = Stream.of(userModel); userModels = Stream.of(userModel);
} }
@ -341,12 +341,12 @@ public class UsersResource {
if (search != null) { if (search != null) {
if (search.startsWith(SEARCH_ID_PARAMETER)) { if (search.startsWith(SEARCH_ID_PARAMETER)) {
UserModel userModel = session.users().getUserById(search.substring(SEARCH_ID_PARAMETER.length()).trim(), realm); UserModel userModel = session.users().getUserById(realm, search.substring(SEARCH_ID_PARAMETER.length()).trim());
return userModel != null && userPermissionEvaluator.canView(userModel) ? 1 : 0; return userModel != null && userPermissionEvaluator.canView(userModel) ? 1 : 0;
} else if (userPermissionEvaluator.canView()) { } else if (userPermissionEvaluator.canView()) {
return session.users().getUsersCount(search.trim(), realm); return session.users().getUsersCount(realm, search.trim());
} else { } else {
return session.users().getUsersCount(search.trim(), realm, auth.groups().getGroupsWithViewPermission()); return session.users().getUsersCount(realm, search.trim(), auth.groups().getGroupsWithViewPermission());
} }
} else if (last != null || first != null || email != null || username != null || emailVerified != null) { } else if (last != null || first != null || email != null || username != null || emailVerified != null) {
Map<String, String> parameters = new HashMap<>(); Map<String, String> parameters = new HashMap<>();
@ -366,9 +366,9 @@ public class UsersResource {
parameters.put(UserModel.EMAIL_VERIFIED, emailVerified.toString()); parameters.put(UserModel.EMAIL_VERIFIED, emailVerified.toString());
} }
if (userPermissionEvaluator.canView()) { if (userPermissionEvaluator.canView()) {
return session.users().getUsersCount(parameters, realm); return session.users().getUsersCount(realm, parameters);
} else { } else {
return session.users().getUsersCount(parameters, realm, auth.groups().getGroupsWithViewPermission()); return session.users().getUsersCount(realm, parameters, auth.groups().getGroupsWithViewPermission());
} }
} else if (userPermissionEvaluator.canView()) { } else if (userPermissionEvaluator.canView()) {
return session.users().getUsersCount(realm); return session.users().getUsersCount(realm);
@ -388,7 +388,7 @@ public class UsersResource {
} }
} }
Stream<UserModel> userModels = session.users().searchForUserStream(attributes, realm, firstResult, maxResults); Stream<UserModel> userModels = session.users().searchForUserStream(realm, attributes, firstResult, maxResults);
return toRepresentation(realm, usersEvaluator, briefRepresentation, userModels); return toRepresentation(realm, usersEvaluator, briefRepresentation, userModels);
} }

View file

@ -122,7 +122,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
} }
protected Response exchangeStoredToken(UriInfo uriInfo, ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject) { protected Response exchangeStoredToken(UriInfo uriInfo, ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject) {
FederatedIdentityModel model = session.users().getFederatedIdentity(tokenSubject, getConfig().getAlias(), authorizedClient.getRealm()); FederatedIdentityModel model = session.users().getFederatedIdentity(authorizedClient.getRealm(), tokenSubject, getConfig().getAlias());
if (model == null || model.getToken() == null) { if (model == null || model.getToken() == null) {
return exchangeNotLinked(uriInfo, authorizedClient, tokenUserSession, tokenSubject); return exchangeNotLinked(uriInfo, authorizedClient, tokenUserSession, tokenSubject);
} }

View file

@ -58,6 +58,7 @@ import java.util.function.Predicate;
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;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -136,7 +137,7 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
runJobInTransaction(session.getKeycloakSessionFactory(), session -> { runJobInTransaction(session.getKeycloakSessionFactory(), 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(realmModel, userId);
if (deletedUser != null) { if (deletedUser != null) {
try { try {
new UserManager(session).removeUser(realmModel, deletedUser, session.userLocalStorage()); new UserManager(session).removeUser(realmModel, deletedUser, session.userLocalStorage());
@ -161,10 +162,8 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
Stream<UserModel> query(Object provider); Stream<UserModel> query(Object provider);
} }
protected Stream<UserModel> query(PaginatedQuery pagedQuery, RealmModel realm, int firstResult, int maxResults) { protected Stream<UserModel> query(PaginatedQuery pagedQuery, RealmModel realm, Integer firstResult, Integer maxResults) {
if (maxResults == 0) return Stream.empty(); if (maxResults != null && maxResults == 0) return Stream.empty();
if (firstResult < 0) firstResult = 0;
if (maxResults < 0) maxResults = Integer.MAX_VALUE - 1;
Stream<Object> providersStream = Stream.concat(Stream.of((Object) localStorage()), getEnabledStorageProviders(realm, UserQueryProvider.class)); Stream<Object> providersStream = Stream.concat(Stream.of((Object) localStorage()), getEnabledStorageProviders(realm, UserQueryProvider.class));
@ -173,9 +172,7 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
providersStream = Stream.concat(providersStream, Stream.of(federatedStorageProvider)); providersStream = Stream.concat(providersStream, Stream.of(federatedStorageProvider));
} }
return providersStream.flatMap(pagedQuery::query) return paginatedStream(providersStream.flatMap(pagedQuery::query), firstResult, maxResults);
.skip(firstResult)
.limit(maxResults);
} }
/** /**
@ -232,33 +229,33 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
{@link UserLookupProvider} methods implementations start here */ {@link UserLookupProvider} methods implementations start here */
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
StorageId storageId = new StorageId(id); StorageId storageId = new StorageId(id);
if (storageId.getProviderId() == null) { if (storageId.getProviderId() == null) {
UserModel user = localStorage().getUserById(id, realm); UserModel user = localStorage().getUserById(realm, id);
return importValidation(realm, user); return importValidation(realm, user);
} }
UserLookupProvider provider = getStorageProviderInstance(realm, storageId.getProviderId(), UserLookupProvider.class); UserLookupProvider provider = getStorageProviderInstance(realm, storageId.getProviderId(), UserLookupProvider.class);
if (provider == null) return null; if (provider == null) return null;
return provider.getUserById(id, realm); return provider.getUserById(realm, id);
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
UserModel user = localStorage().getUserByUsername(username, realm); UserModel user = localStorage().getUserByUsername(realm, username);
if (user != null) { if (user != null) {
return importValidation(realm, user); return importValidation(realm, user);
} }
return mapEnabledStorageProvidersWithTimeout(realm, UserLookupProvider.class, return mapEnabledStorageProvidersWithTimeout(realm, UserLookupProvider.class,
provider -> provider.getUserByUsername(username, realm)).findFirst().orElse(null); provider -> provider.getUserByUsername(realm, username)).findFirst().orElse(null);
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
UserModel user = localStorage().getUserByEmail(email, realm); UserModel user = localStorage().getUserByEmail(realm, email);
if (user != null) { if (user != null) {
user = importValidation(realm, user); user = importValidation(realm, user);
// Case when email was changed directly in the userStorage and doesn't correspond anymore to the email from local DB // Case when email was changed directly in the userStorage and doesn't correspond anymore to the email from local DB
@ -268,17 +265,12 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
return mapEnabledStorageProvidersWithTimeout(realm, UserLookupProvider.class, return mapEnabledStorageProvidersWithTimeout(realm, UserLookupProvider.class,
provider -> provider.getUserByEmail(email, realm)).findFirst().orElse(null); provider -> provider.getUserByEmail(realm, email)).findFirst().orElse(null);
} }
/** {@link UserLookupProvider} methods implementations end here /** {@link UserLookupProvider} methods implementations end here
{@link UserQueryProvider} methods implementation start here */ {@link UserQueryProvider} methods implementation start here */
@Override
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
return getGroupMembersStream(realm, group, -1, -1);
}
@Override @Override
public Stream<UserModel> getGroupMembersStream(final RealmModel realm, final GroupModel group, Integer firstResult, Integer maxResults) { public Stream<UserModel> getGroupMembersStream(final RealmModel realm, final GroupModel group, Integer firstResult, Integer maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
@ -287,7 +279,7 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} else if (provider instanceof UserFederatedStorageProvider) { } else if (provider instanceof UserFederatedStorageProvider) {
return ((UserFederatedStorageProvider)provider).getMembershipStream(realm, group, -1, -1). return ((UserFederatedStorageProvider)provider).getMembershipStream(realm, group, -1, -1).
map(id -> getUserById(id, realm)); map(id -> getUserById(realm, id));
} }
return Stream.empty(); return Stream.empty();
}, realm, firstResult, maxResults); }, realm, firstResult, maxResults);
@ -295,11 +287,6 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
return importValidation(realm, results); return importValidation(realm, results);
} }
@Override
public Stream<UserModel> getRoleMembersStream(RealmModel realm, RoleModel role) {
return getRoleMembersStream(realm, role, -1, -1);
}
@Override @Override
public Stream<UserModel> getRoleMembersStream(final RealmModel realm, final RoleModel role, Integer firstResult, Integer maxResults) { public Stream<UserModel> getRoleMembersStream(final RealmModel realm, final RoleModel role, Integer firstResult, Integer maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
@ -314,19 +301,14 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
return getUsersStream(realm, false); return getUsersStream(realm, null, null, false);
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
return getUsersStream(realm, firstResult, maxResults, false); return getUsersStream(realm, firstResult, maxResults, false);
} }
@Override
public Stream<UserModel> getUsersStream(RealmModel realm, boolean includeServiceAccounts) {
return getUsersStream(realm, 0, Integer.MAX_VALUE - 1, includeServiceAccounts);
}
@Override @Override
public Stream<UserModel> getUsersStream(final RealmModel realm, Integer firstResult, Integer maxResults, final boolean includeServiceAccounts) { public Stream<UserModel> getUsersStream(final RealmModel realm, Integer firstResult, Integer maxResults, final boolean includeServiceAccounts) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
@ -362,35 +344,30 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override // TODO: missing storageProviders count? @Override // TODO: missing storageProviders count?
public int getUsersCount(String search, RealmModel realm) { public int getUsersCount(RealmModel realm, String search) {
return localStorage().getUsersCount(search, realm); return localStorage().getUsersCount(realm, search);
} }
@Override // TODO: missing storageProviders count? @Override // TODO: missing storageProviders count?
public int getUsersCount(String search, RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, String search, Set<String> groupIds) {
return localStorage().getUsersCount(search, realm, groupIds); return localStorage().getUsersCount(realm, search, groupIds);
} }
@Override // TODO: missing storageProviders count? @Override // TODO: missing storageProviders count?
public int getUsersCount(Map<String, String> params, RealmModel realm) { public int getUsersCount(RealmModel realm, Map<String, String> params) {
return localStorage().getUsersCount(params, realm); return localStorage().getUsersCount(realm, params);
} }
@Override // TODO: missing storageProviders count? @Override // TODO: missing storageProviders count?
public int getUsersCount(Map<String, String> params, RealmModel realm, Set<String> groupIds) { public int getUsersCount(RealmModel realm, Map<String, String> params, Set<String> groupIds) {
return localStorage().getUsersCount(params, realm, groupIds); return localStorage().getUsersCount(realm, params, groupIds);
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
return searchForUserStream(search, realm, 0, Integer.MAX_VALUE - 1);
}
@Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).searchForUserStream(search, realm); return ((UserQueryProvider)provider).searchForUserStream(realm, search);
} }
return Stream.empty(); return Stream.empty();
}, realm, firstResult, maxResults); }, realm, firstResult, maxResults);
@ -398,18 +375,13 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> attributes, Integer firstResult, Integer maxResults) {
return searchForUserStream(attributes, realm, 0, Integer.MAX_VALUE - 1);
}
@Override
public Stream<UserModel> searchForUserStream(Map<String, String> attributes, RealmModel realm, Integer firstResult, Integer 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).searchForUserStream(attributes.get(UserModel.SEARCH), realm); return ((UserQueryProvider)provider).searchForUserStream(realm, attributes.get(UserModel.SEARCH));
} else { } else {
return ((UserQueryProvider)provider).searchForUserStream(attributes, realm); return ((UserQueryProvider)provider).searchForUserStream(realm, attributes);
} }
} }
return Stream.empty(); return Stream.empty();
@ -419,18 +391,18 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
Stream<UserModel> results = query((provider) -> { Stream<UserModel> results = query((provider) -> {
if (provider instanceof UserQueryProvider) { if (provider instanceof UserQueryProvider) {
return ((UserQueryProvider)provider).searchForUserByUserAttributeStream(attrName, attrValue, realm); return ((UserQueryProvider)provider).searchForUserByUserAttributeStream(realm, attrName, attrValue);
} else if (provider instanceof UserFederatedStorageProvider) { } else if (provider instanceof UserFederatedStorageProvider) {
return ((UserFederatedStorageProvider)provider).getUsersByUserAttributeStream(realm, attrName, attrValue) return ((UserFederatedStorageProvider)provider).getUsersByUserAttributeStream(realm, attrName, attrValue)
.map(id -> getUserById(id, realm)) .map(id -> getUserById(realm, id))
.filter(Objects::nonNull); .filter(Objects::nonNull);
} }
return Stream.empty(); return Stream.empty();
}, realm,0, Integer.MAX_VALUE - 1); }, realm,null, null);
// 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);
@ -594,14 +566,14 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) { public UserModel getUserByFederatedIdentity(RealmModel realm, FederatedIdentityModel socialLink) {
UserModel user = localStorage().getUserByFederatedIdentity(socialLink, realm); UserModel user = localStorage().getUserByFederatedIdentity(realm, socialLink);
if (user != null) { if (user != null) {
return importValidation(realm, user); return importValidation(realm, user);
} }
if (getFederatedStorage() == null) return null; if (getFederatedStorage() == null) return null;
String id = getFederatedStorage().getUserByFederatedIdentity(socialLink, realm); String id = getFederatedStorage().getUserByFederatedIdentity(socialLink, realm);
if (id != null) return getUserById(id, realm); if (id != null) return getUserById(realm, id);
return null; return null;
} }
@ -611,20 +583,20 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} }
@Override @Override
public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(UserModel user, RealmModel realm) { public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user) {
if (user == null) throw new IllegalStateException("Federated user no longer valid"); if (user == null) throw new IllegalStateException("Federated user no longer valid");
Stream<FederatedIdentityModel> stream = StorageId.isLocalStorage(user) ? Stream<FederatedIdentityModel> stream = StorageId.isLocalStorage(user) ?
localStorage().getFederatedIdentitiesStream(user, realm) : Stream.empty(); localStorage().getFederatedIdentitiesStream(realm, user) : Stream.empty();
if (getFederatedStorage() != null) if (getFederatedStorage() != null)
stream = Stream.concat(stream, getFederatedStorage().getFederatedIdentitiesStream(user.getId(), realm)); stream = Stream.concat(stream, getFederatedStorage().getFederatedIdentitiesStream(user.getId(), realm));
return stream.distinct(); return stream.distinct();
} }
@Override @Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) { public FederatedIdentityModel getFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
if (user == null) throw new IllegalStateException("Federated user no longer valid"); if (user == null) throw new IllegalStateException("Federated user no longer valid");
if (StorageId.isLocalStorage(user)) { if (StorageId.isLocalStorage(user)) {
FederatedIdentityModel model = localStorage().getFederatedIdentity(user, socialProvider, realm); FederatedIdentityModel model = localStorage().getFederatedIdentity(realm, user, socialProvider);
if (model != null) return model; if (model != null) return model;
} }
if (getFederatedStorage() != null) return getFederatedStorage().getFederatedIdentity(user.getId(), socialProvider, realm); if (getFederatedStorage() != null) return getFederatedStorage().getFederatedIdentity(user.getId(), socialProvider, realm);

View file

@ -95,7 +95,7 @@ public class LegacyUserProfileProvider implements UserProfileProvider {
builder.addAttributeValidator().forAttribute(UserModel.USERNAME) builder.addAttributeValidator().forAttribute(UserModel.USERNAME)
.addSingleAttributeValueValidationFunction(Messages.MISSING_USERNAME, StaticValidators.isBlank()) .addSingleAttributeValueValidationFunction(Messages.MISSING_USERNAME, StaticValidators.isBlank())
.addSingleAttributeValueValidationFunction(Messages.USERNAME_EXISTS, .addSingleAttributeValueValidationFunction(Messages.USERNAME_EXISTS,
(value, o) -> session.users().getUserByUsername(value, realm) == null) (value, o) -> session.users().getUserByUsername(realm, value) == null)
.build(); .build();
} }
} }

View file

@ -55,7 +55,7 @@ public class StaticValidators {
if (Validation.isBlank(value)) return true; if (Validation.isBlank(value)) return true;
return !(context.getCurrentProfile() != null return !(context.getCurrentProfile() != null
&& !value.equals(context.getCurrentProfile().getAttributes().getFirstAttribute(UserModel.USERNAME)) && !value.equals(context.getCurrentProfile().getAttributes().getFirstAttribute(UserModel.USERNAME))
&& session.users().getUserByUsername(value, session.getContext().getRealm()) != null); && session.users().getUserByUsername(session.getContext().getRealm(), value) != null);
}; };
} }
@ -80,7 +80,7 @@ public class StaticValidators {
if (Validation.isBlank(value)) return true; if (Validation.isBlank(value)) return true;
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
if (!realm.isDuplicateEmailsAllowed()) { if (!realm.isDuplicateEmailsAllowed()) {
UserModel userByEmail = session.users().getUserByEmail(value, realm); UserModel userByEmail = session.users().getUserByEmail(realm, value);
return !(realm.isRegistrationEmailAsUsername() && userByEmail != null && context.getCurrentProfile() != null && !userByEmail.getId().equals(context.getCurrentProfile().getId())); return !(realm.isRegistrationEmailAsUsername() && userByEmail != null && context.getCurrentProfile() != null && !userByEmail.getId().equals(context.getCurrentProfile().getId()));
} }
return true; return true;
@ -92,7 +92,7 @@ public class StaticValidators {
if (Validation.isBlank(value)) return true; if (Validation.isBlank(value)) return true;
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
if (!realm.isDuplicateEmailsAllowed()) { if (!realm.isDuplicateEmailsAllowed()) {
UserModel userByEmail = session.users().getUserByEmail(value, realm); UserModel userByEmail = session.users().getUserByEmail(realm, value);
// check for duplicated email // check for duplicated email
return !(userByEmail != null && (context.getCurrentProfile() == null || !userByEmail.getId().equals(context.getCurrentProfile().getId()))); return !(userByEmail != null && (context.getCurrentProfile() == null || !userByEmail.getId().equals(context.getCurrentProfile().getId())));
} }
@ -104,7 +104,7 @@ public class StaticValidators {
return (value, context) -> return (value, context) ->
!(value != null !(value != null
&& !session.getContext().getRealm().isDuplicateEmailsAllowed() && !session.getContext().getRealm().isDuplicateEmailsAllowed()
&& session.users().getUserByEmail(value, session.getContext().getRealm()) != null); && session.users().getUserByEmail(session.getContext().getRealm(), value) != null);
} }
public static BiFunction<List<String>, UserProfileContext, Boolean> isAttributeUnchanged(String attributeName) { public static BiFunction<List<String>, UserProfileContext, Boolean> isAttributeUnchanged(String attributeName) {

View file

@ -49,7 +49,7 @@ public class ExpectedParamAuthenticator implements Authenticator {
if (loggedUser == null) { if (loggedUser == null) {
logger.info("Successfully authenticated, but don't set any authenticated user"); logger.info("Successfully authenticated, but don't set any authenticated user");
} else { } else {
UserModel user = context.getSession().users().getUserByUsername(loggedUser, context.getRealm()); UserModel user = context.getSession().users().getUserByUsername(context.getRealm(), loggedUser);
logger.info("Successfully authenticated as user " + user.getUsername()); logger.info("Successfully authenticated as user " + user.getUsername());
context.setUser(user); context.setUser(user);
} }

View file

@ -342,7 +342,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
@Override @Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) { public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
UserModel user = getUserByUsername(search, realm); UserModel user = getUserByUsername(realm, search);
return user == null ? Collections.emptyList() : Arrays.asList(user); return user == null ? Collections.emptyList() : Arrays.asList(user);
} }

View file

@ -20,12 +20,10 @@ package org.keycloak.testsuite.federation;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.credential.CredentialInput; import org.keycloak.credential.CredentialInput;
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;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.credential.OTPCredentialModel; import org.keycloak.models.credential.OTPCredentialModel;
import org.keycloak.models.credential.PasswordCredentialModel; import org.keycloak.models.credential.PasswordCredentialModel;
@ -34,7 +32,6 @@ import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserRegistrationProvider; import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -44,7 +41,7 @@ import java.util.Set;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class DummyUserFederationProvider implements UserStorageProvider, public class DummyUserFederationProvider implements UserStorageProvider,
UserLookupProvider, UserLookupProvider.Streams,
UserRegistrationProvider, UserRegistrationProvider,
CredentialInputValidator { CredentialInputValidator {
@ -83,17 +80,17 @@ public class DummyUserFederationProvider implements UserStorageProvider,
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
return null; return null;
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
return users.get(username); return users.get(username);
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
return null; return null;
} }

View file

@ -41,7 +41,7 @@ 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 class FailableHardcodedStorageProvider implements UserStorageProvider, UserLookupProvider, UserQueryProvider.Streams, public class FailableHardcodedStorageProvider implements UserStorageProvider, UserLookupProvider.Streams, UserQueryProvider.Streams,
ImportedUserValidation, CredentialInputUpdater.Streams, CredentialInputValidator { ImportedUserValidation, CredentialInputUpdater.Streams, CredentialInputValidator {
public static String username = "billb"; public static String username = "billb";
@ -172,16 +172,16 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
checkForceFail(); checkForceFail();
throw new RuntimeException("THIS IMPORTS SHOULD NEVER BE CALLED"); throw new RuntimeException("THIS IMPORTS SHOULD NEVER BE CALLED");
} }
@Override @Override
public UserModel getUserByUsername(String uname, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String uname) {
checkForceFail(); checkForceFail();
if (!username.equals(uname)) return null; if (!username.equals(uname)) return null;
UserModel local = session.userLocalStorage().getUserByUsername(uname, realm); UserModel local = session.userLocalStorage().getUserByUsername(realm, uname);
if (local != null && !model.getId().equals(local.getFederationLink())) { if (local != null && !model.getId().equals(local.getFederationLink())) {
throw new RuntimeException("local storage has wrong federation link"); throw new RuntimeException("local storage has wrong federation link");
} }
@ -201,7 +201,7 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
checkForceFail(); checkForceFail();
return null; return null;
} }
@ -223,46 +223,46 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm) {
checkForceFail(); checkForceFail();
UserModel model = getUserByUsername(username, realm); UserModel model = getUserByUsername(realm, username);
return model != null ? Stream.of(model) : Stream.empty(); return model != null ? Stream.of(model) : Stream.empty();
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
checkForceFail(); checkForceFail();
UserModel model = getUserByUsername(username, realm); UserModel model = getUserByUsername(realm, username);
return model != null ? Stream.of(model) : Stream.empty(); return model != null ? Stream.of(model) : Stream.empty();
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search) {
checkForceFail(); checkForceFail();
if (!search.equals(username)) return Stream.empty(); if (!search.equals(username)) return Stream.empty();
UserModel model = getUserByUsername(username, realm); UserModel model = getUserByUsername(realm, username);
return model != null ? Stream.of(model) : Stream.empty(); return model != null ? Stream.of(model) : Stream.empty();
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
checkForceFail(); checkForceFail();
if (!search.equals(username)) return Stream.empty(); if (!search.equals(username)) return Stream.empty();
UserModel model = getUserByUsername(username, realm); UserModel model = getUserByUsername(realm, username);
return model != null ? Stream.of(model) : Stream.empty(); return model != null ? Stream.of(model) : Stream.empty();
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params) {
checkForceFail(); checkForceFail();
if (!username.equals(params.get("username")))return Stream.empty(); if (!username.equals(params.get("username")))return Stream.empty();
UserModel model = getUserByUsername(username, realm); UserModel model = getUserByUsername(realm, username);
return model != null ? Stream.of(model) : Stream.empty(); return model != null ? Stream.of(model) : Stream.empty();
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params, Integer firstResult, Integer maxResults) {
checkForceFail(); checkForceFail();
if (!username.equals(params.get("username")))return Stream.empty(); if (!username.equals(params.get("username")))return Stream.empty();
UserModel model = getUserByUsername(username, realm); UserModel model = getUserByUsername(realm, username);
return model != null ? Stream.of(model) : Stream.empty(); return model != null ? Stream.of(model) : Stream.empty();
} }
@ -279,7 +279,7 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
} }
@Override @Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
checkForceFail(); checkForceFail();
return Stream.empty(); return Stream.empty();
} }

View file

@ -45,7 +45,7 @@ import java.util.stream.Collectors;
*/ */
public class PassThroughFederatedUserStorageProvider implements public class PassThroughFederatedUserStorageProvider implements
UserStorageProvider, UserStorageProvider,
UserLookupProvider, UserLookupProvider.Streams,
CredentialInputValidator, CredentialInputValidator,
CredentialInputUpdater CredentialInputUpdater
{ {
@ -130,20 +130,20 @@ public class PassThroughFederatedUserStorageProvider implements
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
if (!StorageId.externalId(id).equals(PASSTHROUGH_USERNAME)) return null; if (!StorageId.externalId(id).equals(PASSTHROUGH_USERNAME)) return null;
return getUserModel(realm); return getUserModel(realm);
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
if (!PASSTHROUGH_USERNAME.equals(username)) return null; if (!PASSTHROUGH_USERNAME.equals(username)) return null;
return getUserModel(realm); return getUserModel(realm);
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
Optional<StorageId> result = session.userFederatedStorage() Optional<StorageId> result = session.userFederatedStorage()
.getUsersByUserAttributeStream(realm, AbstractUserAdapterFederatedStorage.EMAIL_ATTRIBUTE, email) .getUsersByUserAttributeStream(realm, AbstractUserAdapterFederatedStorage.EMAIL_ATTRIBUTE, email)
.map(StorageId::new) .map(StorageId::new)

View file

@ -48,12 +48,13 @@ import java.util.concurrent.atomic.AtomicInteger;
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;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
/** /**
* @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 class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater.Streams, public class UserMapStorage implements UserLookupProvider.Streams, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater.Streams,
CredentialInputValidator, UserGroupMembershipFederatedStorage.Streams, UserQueryProvider.Streams, ImportedUserValidation { CredentialInputValidator, UserGroupMembershipFederatedStorage.Streams, UserQueryProvider.Streams, ImportedUserValidation {
private static final Logger log = Logger.getLogger(UserMapStorage.class); private static final Logger log = Logger.getLogger(UserMapStorage.class);
@ -91,7 +92,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
StorageId storageId = new StorageId(id); StorageId storageId = new StorageId(id);
final String username = storageId.getExternalId(); final String username = storageId.getExternalId();
if (!userPasswords.containsKey(translateUserName(username))) { if (!userPasswords.containsKey(translateUserName(username))) {
@ -199,7 +200,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
if (!userPasswords.containsKey(translateUserName(username))) { if (!userPasswords.containsKey(translateUserName(username))) {
return null; return null;
} }
@ -208,7 +209,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
return null; return null;
} }
@ -296,17 +297,14 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
Stream<String> userStream = userPasswords.keySet().stream().sorted(); Stream<String> userStream = userPasswords.keySet().stream().sorted();
if (firstResult > 0)
userStream = userStream.skip(firstResult); return paginatedStream(userStream, firstResult, maxResults).map(userName -> createUser(realm, userName));
if (maxResults >= 0)
userStream = userStream.limit(maxResults);
return userStream.map(userName -> createUser(realm, userName));
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search) {
String tSearch = translateUserName(search); String tSearch = translateUserName(search);
return userPasswords.keySet().stream() return userPasswords.keySet().stream()
.sorted() .sorted()
@ -315,25 +313,17 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
@Override @Override
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, Integer firstResult, Integer maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
String tSearch = translateUserName(search); String tSearch = translateUserName(search);
Stream<String> userStream = userPasswords.keySet().stream() Stream<String> userStream = userPasswords.keySet().stream()
.sorted() .sorted()
.filter(userName -> translateUserName(userName).contains(search)); .filter(userName -> translateUserName(userName).contains(search));
if (firstResult != null && firstResult > 0)
userStream = userStream.skip(firstResult); return paginatedStream(userStream, firstResult, maxResults).map(userName -> createUser(realm, userName));
if (maxResults != null && maxResults >= 0)
userStream = userStream.limit(maxResults);
return userStream.map(userName -> createUser(realm, userName));
} }
@Override @Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) { public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params, Integer firstResult, Integer maxResults) {
return searchForUserStream(params, realm, 0, Integer.MAX_VALUE - 1);
}
@Override
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, Integer firstResult, Integer maxResults) {
Stream<String> userStream = userPasswords.keySet().stream() Stream<String> userStream = userPasswords.keySet().stream()
.sorted(); .sorted();
@ -356,28 +346,19 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
} }
} }
if (firstResult != null && firstResult > 0) return paginatedStream(userStream, firstResult, maxResults).map(userName -> createUser(realm, userName));
userStream = userStream.skip(firstResult);
if (maxResults != null && maxResults >= 0)
userStream = userStream.limit(maxResults);
return userStream.map(userName -> createUser(realm, userName));
} }
@Override @Override
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) { public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) {
return getMembershipStream(realm, group, firstResult, maxResults) return getMembershipStream(realm, group, firstResult == null ? -1 : firstResult, maxResults == null ? -1 : maxResults)
.map(userName -> createUser(realm, userName)); .map(userName -> createUser(realm, userName));
} }
@Override @Override
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) { public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
return getGroupMembersStream(realm, group, 0, Integer.MAX_VALUE - 1);
}
@Override
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
if (isImportEnabled()) { if (isImportEnabled()) {
return session.userLocalStorage().searchForUserByUserAttributeStream(attrName, attrValue, realm); return session.userLocalStorage().searchForUserByUserAttributeStream(realm, attrName, attrValue);
} else { } else {
return session.userFederatedStorage().getUsersByUserAttributeStream(realm, attrName, attrValue) return session.userFederatedStorage().getUsersByUserAttributeStream(realm, attrName, attrValue)
.map(userName -> createUser(realm, userName)); .map(userName -> createUser(realm, userName));
@ -409,15 +390,12 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
@Override @Override
public Stream<String> getMembershipStream(RealmModel realm, GroupModel group, int firstResult, int max) { public Stream<String> getMembershipStream(RealmModel realm, GroupModel group, int firstResult, int max) {
Stream<String> userStream = userGroups.entrySet().stream() Stream<String> userStream = paginatedStream(userGroups.entrySet().stream(), firstResult, max)
.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));
if (firstResult > 0)
userStream = userStream.skip(firstResult);
if (max >= 0)
userStream = userStream.limit(max);
return userStream; return userStream;
} }

View file

@ -40,12 +40,15 @@ 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;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
/** /**
* @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 class UserPropertyFileStorage implements UserLookupProvider, UserStorageProvider, UserQueryProvider, CredentialInputValidator { public class UserPropertyFileStorage implements UserLookupProvider.Streams, UserStorageProvider, UserQueryProvider.Streams, CredentialInputValidator {
protected Properties userPasswords; protected Properties userPasswords;
protected ComponentModel model; protected ComponentModel model;
@ -61,7 +64,7 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
@Override @Override
public UserModel getUserById(String id, RealmModel realm) { public UserModel getUserById(RealmModel realm, String id) {
StorageId storageId = new StorageId(id); StorageId storageId = new StorageId(id);
final String username = storageId.getExternalId(); final String username = storageId.getExternalId();
if (!userPasswords.containsKey(username)) return null; if (!userPasswords.containsKey(username)) return null;
@ -92,14 +95,14 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
} }
} }
public UserModel getUserByUsername(String username, RealmModel realm) { public UserModel getUserByUsername(RealmModel realm, String username) {
if (!userPasswords.containsKey(username)) return null; if (!userPasswords.containsKey(username)) return null;
return createUser(realm, username); return createUser(realm, username);
} }
@Override @Override
public UserModel getUserByEmail(String email, RealmModel realm) { public UserModel getUserByEmail(RealmModel realm, String email) {
return null; return null;
} }
@ -145,67 +148,47 @@ 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()
for (Object username : userPasswords.keySet()) { .map(username -> createUser(realm, (String) username));
users.add(createUser(realm, (String)username));
}
return users;
} }
@Override @Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) { public Stream<UserModel> getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) {
return searchForUser(attributes, realm, 0, Integer.MAX_VALUE - 1); if (maxResults != null && maxResults == 0) return Stream.empty();
return paginatedStream(userPasswords.keySet().stream(), firstResult, maxResults)
.map(username -> createUser(realm, (String) username));
} }
@Override @Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) { public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
if (maxResults == 0) return Collections.EMPTY_LIST; return searchForUser(realm, search, firstResult, maxResults, username -> username.contains(search));
List<UserModel> users = new LinkedList<>();
int count = 0;
for (Object un : userPasswords.keySet()) {
if (count++ < firstResult) continue;
String username = (String)un;
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(RealmModel realm, Map<String, String> attributes, Integer firstResult, Integer maxResults) {
return searchForUser(search, realm, firstResult, maxResults, username -> username.contains(search));
}
@Override
public List<UserModel> searchForUser(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 searchForUser(realm, search, 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, Integer firstResult, Integer 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> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1); return Stream.empty();
}
@Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
return Collections.EMPTY_LIST;
} }
@Override @Override
@ -213,20 +196,11 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
} }
private List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults, Predicate<String> matcher) { private Stream<UserModel> searchForUser(RealmModel realm, String search, Integer firstResult, Integer maxResults, Predicate<String> matcher) {
if (maxResults == 0) return Collections.EMPTY_LIST; if (maxResults != null && maxResults == 0) return Stream.empty();
List<UserModel> users = new LinkedList<>(); return paginatedStream(userPasswords.keySet().stream(), firstResult, maxResults)
int count = 0; .map(String.class::cast)
for (Object un : userPasswords.keySet()) { .filter(matcher)
String username = (String)un; .map(username -> createUser(realm, username));
if (matcher.test(username)) {
if (count++ < firstResult) {
continue;
}
users.add(createUser(realm, username));
if (users.size() + 1 > maxResults) break;
}
}
return users;
} }
} }

View file

@ -90,7 +90,7 @@ public class SyncDummyUserFederationProviderFactory extends DummyUserFederationP
// KEYCLOAK-2412 : Just remove and add some users for testing purposes // KEYCLOAK-2412 : Just remove and add some users for testing purposes
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
String username = "dummyuser-" + i; String username = "dummyuser-" + i;
UserModel user = session.userLocalStorage().getUserByUsername(username, realm); UserModel user = session.userLocalStorage().getUserByUsername(realm, username);
if (user != null) { if (user != null) {
session.userLocalStorage().removeUser(realm, user); session.userLocalStorage().removeUser(realm, user);

View file

@ -592,7 +592,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
RealmModel realm = session.realms().getRealm(realmName); RealmModel realm = session.realms().getRealm(realmName);
if (realm == null) return false; if (realm == null) return false;
UserProvider userProvider = session.getProvider(UserProvider.class); UserProvider userProvider = session.getProvider(UserProvider.class);
UserModel user = userProvider.getUserByUsername(userName, realm); UserModel user = userProvider.getUserByUsername(realm, userName);
return session.userCredentialManager().isValid(realm, user, UserCredentialModel.password(password)); return session.userCredentialManager().isValid(realm, user, UserCredentialModel.password(password));
} }
@ -604,7 +604,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
@QueryParam("userId") String userId, @QueryParam("userId") String userId,
@QueryParam("userName") String userName) { @QueryParam("userName") String userName) {
RealmModel realm = getRealmByName(realmName); RealmModel realm = getRealmByName(realmName);
UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(new FederatedIdentityModel(identityProvider, userId, userName), realm); UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(realm, new FederatedIdentityModel(identityProvider, userId, userName));
if (foundFederatedUser == null) return null; if (foundFederatedUser == null) return null;
return ModelToRepresentation.toRepresentation(session, realm, foundFederatedUser); return ModelToRepresentation.toRepresentation(session, realm, foundFederatedUser);
} }
@ -616,7 +616,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
@QueryParam("userName") String userName) { @QueryParam("userName") String userName) {
RealmModel realm = getRealmByName(realmName); RealmModel realm = getRealmByName(realmName);
DummyUserFederationProviderFactory factory = (DummyUserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, "dummy"); DummyUserFederationProviderFactory factory = (DummyUserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, "dummy");
UserModel user = factory.create(session, null).getUserByUsername(userName, realm); UserModel user = factory.create(session, null).getUserByUsername(realm, userName);
if (user == null) return null; if (user == null) return null;
return ModelToRepresentation.toRepresentation(session, realm, user); return ModelToRepresentation.toRepresentation(session, realm, user);
} }

View file

@ -55,7 +55,7 @@ public class RunHelpers {
public FetchOnServer getRunOnServer() { public FetchOnServer getRunOnServer() {
return (FetchOnServer) session -> { return (FetchOnServer) session -> {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserByUsername(username, realm); UserModel user = session.users().getUserByUsername(realm, username);
List<CredentialModel> storedCredentialsByType = session.userCredentialManager() List<CredentialModel> storedCredentialsByType = session.userCredentialManager()
.getStoredCredentialsByTypeStream(realm, user, CredentialRepresentation.PASSWORD) .getStoredCredentialsByTypeStream(realm, user, CredentialRepresentation.PASSWORD)
.collect(Collectors.toList()); .collect(Collectors.toList());

View file

@ -481,7 +481,7 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest {
final String uId = userId; // Needed for run-on-server final String uId = userId; // Needed for run-on-server
testingClient.server("test").run(session -> { testingClient.server("test").run(session -> {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserById(uId, realm); UserModel user = session.users().getUserById(realm, uId);
assertThat(user, Matchers.notNullValue()); assertThat(user, Matchers.notNullValue());
List<CredentialModel> storedCredentials = session.userCredentialManager() List<CredentialModel> storedCredentials = session.userCredentialManager()
.getStoredCredentialsStream(realm, user).collect(Collectors.toList()); .getStoredCredentialsStream(realm, user).collect(Collectors.toList());

View file

@ -65,7 +65,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -331,7 +330,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// test authorized // test authorized
{ {
UserModel user = session.users().getUserByUsername("authorized", realm); UserModel user = session.users().getUserByUsername(realm, "authorized");
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
Assert.assertTrue(permissionsForAdmin.users().canManage()); Assert.assertTrue(permissionsForAdmin.users().canManage());
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
@ -340,7 +339,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
} }
// test composite role // test composite role
{ {
UserModel user = session.users().getUserByUsername("authorizedComposite", realm); UserModel user = session.users().getUserByUsername(realm, "authorizedComposite");
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
Assert.assertTrue(permissionsForAdmin.users().canManage()); Assert.assertTrue(permissionsForAdmin.users().canManage());
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(realmRole));
@ -350,7 +349,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
// test unauthorized // test unauthorized
{ {
UserModel user = session.users().getUserByUsername("unauthorized", realm); UserModel user = session.users().getUserByUsername(realm, "unauthorized");
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
Assert.assertFalse(permissionsForAdmin.users().canManage()); Assert.assertFalse(permissionsForAdmin.users().canManage());
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
@ -359,7 +358,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
} }
// test unauthorized mapper // test unauthorized mapper
{ {
UserModel user = session.users().getUserByUsername("unauthorizedMapper", realm); UserModel user = session.users().getUserByUsername(realm, "unauthorizedMapper");
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, user);
Assert.assertTrue(permissionsForAdmin.users().canManage()); Assert.assertTrue(permissionsForAdmin.users().canManage());
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
@ -369,12 +368,12 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
} }
// test group management // test group management
{ {
UserModel admin = session.users().getUserByUsername("groupManager", realm); UserModel admin = session.users().getUserByUsername(realm, "groupManager");
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin);
UserModel user = session.users().getUserByUsername("authorized", realm); UserModel user = session.users().getUserByUsername(realm, "authorized");
Assert.assertFalse(permissionsForAdmin.users().canManage(user)); Assert.assertFalse(permissionsForAdmin.users().canManage(user));
Assert.assertFalse(permissionsForAdmin.users().canView(user)); Assert.assertFalse(permissionsForAdmin.users().canView(user));
UserModel member = session.users().getUserByUsername("groupMember", realm); UserModel member = session.users().getUserByUsername(realm, "groupMember");
Assert.assertTrue(permissionsForAdmin.users().canManage(member)); Assert.assertTrue(permissionsForAdmin.users().canManage(member));
Assert.assertTrue(permissionsForAdmin.users().canManageGroupMembership(member)); Assert.assertTrue(permissionsForAdmin.users().canManageGroupMembership(member));
Assert.assertTrue(permissionsForAdmin.users().canView(member)); Assert.assertTrue(permissionsForAdmin.users().canView(member));
@ -385,9 +384,9 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
} }
// test client.mapRoles // test client.mapRoles
{ {
UserModel admin = session.users().getUserByUsername("clientMapper", realm); UserModel admin = session.users().getUserByUsername(realm, "clientMapper");
AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin); AdminPermissionEvaluator permissionsForAdmin = AdminPermissions.evaluator(session, realm, realm, admin);
UserModel user = session.users().getUserByUsername("authorized", realm); UserModel user = session.users().getUserByUsername(realm, "authorized");
Assert.assertTrue(permissionsForAdmin.users().canManage(user)); Assert.assertTrue(permissionsForAdmin.users().canManage(user));
Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole)); Assert.assertFalse(permissionsForAdmin.roles().canMapRole(realmRole));
Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole)); Assert.assertTrue(permissionsForAdmin.roles().canMapRole(clientRole));

View file

@ -281,7 +281,7 @@ public class ImpersonationTest extends AbstractKeycloakTest {
final String userId = impersonatedUserId; final String userId = impersonatedUserId;
final UserSessionNotesHolder notesHolder = testingClient.server("test").fetch(session -> { final UserSessionNotesHolder notesHolder = testingClient.server("test").fetch(session -> {
final RealmModel realm = session.realms().getRealmByName("test"); final RealmModel realm = session.realms().getRealmByName("test");
final UserModel user = session.users().getUserById(userId, realm); final UserModel user = session.users().getUserById(realm, userId);
final UserSessionModel userSession = session.sessions().getUserSessionsStream(realm, user).findFirst().get(); final UserSessionModel userSession = session.sessions().getUserSessionsStream(realm, user).findFirst().get();
return new UserSessionNotesHolder(userSession.getNotes()); return new UserSessionNotesHolder(userSession.getNotes());
}, UserSessionNotesHolder.class); }, UserSessionNotesHolder.class);

View file

@ -563,7 +563,7 @@ public class PolicyEvaluationTest extends AbstractAuthzTest {
public static void testCheckUserAttributes(KeycloakSession session) { public static void testCheckUserAttributes(KeycloakSession session) {
RealmModel realm = session.realms().getRealmByName("authz-test"); RealmModel realm = session.realms().getRealmByName("authz-test");
UserModel jdoe = session.users().getUserByUsername("jdoe", realm); UserModel jdoe = session.users().getUserByUsername(realm, "jdoe");
jdoe.setAttribute("a1", Arrays.asList("1", "2")); jdoe.setAttribute("a1", Arrays.asList("1", "2"));
jdoe.setSingleAttribute("a2", "3"); jdoe.setSingleAttribute("a2", "3");

View file

@ -1,6 +1,5 @@
package org.keycloak.testsuite.authz; package org.keycloak.testsuite.authz;
import org.jboss.resteasy.spi.ResteasyUriInfo;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
@ -16,8 +15,6 @@ import org.keycloak.representations.idm.authorization.*;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List; import java.util.List;
@AuthServerContainerExclude(AuthServer.REMOTE) @AuthServerContainerExclude(AuthServer.REMOTE)
@ -141,7 +138,7 @@ public class UmaRepresentationTest extends AbstractResourceServerTest {
AuthorizationBean authorizationBean = new AuthorizationBean(session, null, session.getContext().getUri()); AuthorizationBean authorizationBean = new AuthorizationBean(session, null, session.getContext().getUri());
ClientModel client = session.getContext().getRealm().getClientByClientId("resource-server-test"); ClientModel client = session.getContext().getRealm().getClientByClientId("resource-server-test");
UserModel user = session.userStorageManager().getUserByUsername("marta", session.getContext().getRealm()); UserModel user = session.userStorageManager().getUserByUsername(session.getContext().getRealm(), "marta");
ResourceBean resourceBean = authorizationBean.new ResourceBean( ResourceBean resourceBean = authorizationBean.new ResourceBean(
authorization.getStoreFactory().getResourceStore().findByName( authorization.getStoreFactory().getResourceStore().findByName(
"Resource A", user.getId(), client.getId() "Resource A", user.getId(), client.getId()

View file

@ -169,9 +169,9 @@ public class AccountLinkTest extends AbstractKeycloakTest {
private static void checkEmptyFederatedIdentities(KeycloakSession session) { private static void checkEmptyFederatedIdentities(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserByUsername("child", realm); UserModel user = session.users().getUserByUsername(realm, "child");
assertEquals(0, session.users().getFederatedIdentitiesStream(user, realm).count()); assertEquals(0, session.users().getFederatedIdentitiesStream(realm, user).count());
assertNull(session.users().getFederatedIdentity(user, PARENT_IDP, realm)); assertNull(session.users().getFederatedIdentity(realm, user, PARENT_IDP));
} }
protected void testAccountLink(String childUsername, String childPassword, String childIdp) { protected void testAccountLink(String childUsername, String childPassword, String childIdp) {

View file

@ -83,7 +83,7 @@ final class BrokerRunOnServerUtil {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
ClientModel brokerClient = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID); ClientModel brokerClient = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID);
RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE); RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE);
UserModel user = session.users().getUserByUsername(username, realm); UserModel user = session.users().getUserByUsername(realm, username);
user.grantRole(readTokenRole); user.grantRole(readTokenRole);
}; };
} }
@ -93,7 +93,7 @@ final class BrokerRunOnServerUtil {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
ClientModel brokerClient = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID); ClientModel brokerClient = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID);
RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE); RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE);
UserModel user = session.users().getUserByUsername(username, realm); UserModel user = session.users().getUserByUsername(realm, username);
user.deleteRoleMapping(readTokenRole); user.deleteRoleMapping(readTokenRole);
}; };
} }
@ -134,7 +134,7 @@ final class BrokerRunOnServerUtil {
static RunOnServer assertHardCodedSessionNote() { static RunOnServer assertHardCodedSessionNote() {
return (session) -> { return (session) -> {
RealmModel realm = session.realms().getRealmByName("consumer"); RealmModel realm = session.realms().getRealmByName("consumer");
UserModel user = session.users().getUserByUsername("testuser", realm); UserModel user = session.users().getUserByUsername(realm, "testuser");
UserSessionModel sessions = session.sessions().getUserSessionsStream(realm, user).findFirst().get(); UserSessionModel sessions = session.sessions().getUserSessionsStream(realm, user).findFirst().get();
assertEquals("sessionvalue", sessions.getNote("user-session-attr")); assertEquals("sessionvalue", sessions.getNote("user-session-attr"));
}; };

View file

@ -28,7 +28,6 @@ import org.keycloak.authentication.requiredactions.TermsAndConditions;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.credential.CredentialModel;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowBindings; import org.keycloak.models.AuthenticationFlowBindings;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
@ -294,7 +293,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
public void testBrowserContinueRequiredAction() throws Exception { public void testBrowserContinueRequiredAction() throws Exception {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
user.addRequiredAction("dummy"); user.addRequiredAction("dummy");
}); });
testInstall(); testInstall();
@ -439,7 +438,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
public void testTerms() throws Exception { public void testTerms() throws Exception {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
user.addRequiredAction(TermsAndConditions.PROVIDER_ID); user.addRequiredAction(TermsAndConditions.PROVIDER_ID);
}); });
@ -466,7 +465,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
// expects that updateProfile is a passthrough // expects that updateProfile is a passthrough
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE); user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
}); });
@ -496,7 +495,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
user.removeRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE); user.removeRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
}); });
} }
@ -507,7 +506,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
public void testUpdatePassword() throws Exception { public void testUpdatePassword() throws Exception {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
}); });
@ -548,7 +547,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password")); session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password"));
}); });
} }
@ -562,7 +561,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
public void testConfigureTOTP() throws Exception { public void testConfigureTOTP() throws Exception {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP); user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
}); });
@ -631,7 +630,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
} finally { } finally {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("wburke", realm); UserModel user = session.users().getUserByUsername(realm, "wburke");
session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE) session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE)
.collect(Collectors.toList()) .collect(Collectors.toList())
.forEach(model -> session.userCredentialManager().removeStoredCredential(realm, user, model.getId())); .forEach(model -> session.userCredentialManager().removeStoredCredential(realm, user, model.getId()));
@ -648,7 +647,7 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
public void testVerifyEmail() throws Exception { public void testVerifyEmail() throws Exception {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName("test"); RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("test-user@localhost", realm); UserModel user = session.users().getUserByUsername(realm, "test-user@localhost");
user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
}); });

View file

@ -162,7 +162,7 @@ public class LDAPBinaryAttributesTest extends AbstractLDAPTest {
String joeId = joe.getId(); String joeId = joe.getId();
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel test = session.realms().getRealmByName("test"); RealmModel test = session.realms().getRealmByName("test");
UserModel userById = session.userLocalStorage().getUserById(joeId, test); UserModel userById = session.userLocalStorage().getUserById(test, joeId);
assertThat(userById.getAttributes().get(LDAPConstants.JPEG_PHOTO), is(nullValue())); assertThat(userById.getAttributes().get(LDAPConstants.JPEG_PHOTO), is(nullValue()));
}); });

View file

@ -48,7 +48,6 @@ import org.keycloak.testsuite.util.LDAPTestUtils;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -338,7 +337,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group12")); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group12"));
// Load user from LDAP to Keycloak DB // Load user from LDAP to Keycloak DB
UserModel john = session.users().getUserByUsername("johnkeycloak", realm); UserModel john = session.users().getUserByUsername(realm, "johnkeycloak");
Set<GroupModel> johnGroups = john.getGroupsStream().collect(Collectors.toSet()); Set<GroupModel> johnGroups = john.getGroupsStream().collect(Collectors.toSet());
// Assert just those groups, which john was memberOf exists because they were lazily created // Assert just those groups, which john was memberOf exists because they were lazily created

View file

@ -87,8 +87,8 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.MODE, LDAPGroupMapperMode.LDAP_ONLY.toString()); LDAPTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.MODE, LDAPGroupMapperMode.LDAP_ONLY.toString());
appRealm.updateComponent(mapperModel); appRealm.updateComponent(mapperModel);
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm); UserModel john = session.users().getUserByUsername(appRealm, "johnkeycloak");
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
// 1 - Grant some groups in LDAP // 1 - Grant some groups in LDAP
@ -127,7 +127,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel johnDb = session.userLocalStorage().getUserByUsername("johnkeycloak", appRealm); UserModel johnDb = session.userLocalStorage().getUserByUsername(appRealm, "johnkeycloak");
Assert.assertEquals(2, johnDb.getGroupsStream().count()); Assert.assertEquals(2, johnDb.getGroupsStream().count());
Assert.assertEquals(2, johnDb.getGroupsStream("Gr", 0, 10).count()); Assert.assertEquals(2, johnDb.getGroupsStream("Gr", 0, 10).count());
Assert.assertEquals(1, johnDb.getGroupsStream("Gr", 1, 10).count()); Assert.assertEquals(1, johnDb.getGroupsStream("Gr", 1, 10).count());
@ -150,8 +150,8 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12"); GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
GroupModel groupTeam20162017 = KeycloakModelUtils.findGroupByPath(appRealm, "Team 2016/2017"); GroupModel groupTeam20162017 = KeycloakModelUtils.findGroupByPath(appRealm, "Team 2016/2017");
GroupModel groupTeamChild20182019 = KeycloakModelUtils.findGroupByPath(appRealm, "defaultGroup1/Team Child 2018/2019"); GroupModel groupTeamChild20182019 = KeycloakModelUtils.findGroupByPath(appRealm, "defaultGroup1/Team Child 2018/2019");
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm); UserModel john = session.users().getUserByUsername(appRealm, "johnkeycloak");
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
Set<GroupModel> johnGroups = john.getGroupsStream().collect(Collectors.toSet()); Set<GroupModel> johnGroups = john.getGroupsStream().collect(Collectors.toSet());
Assert.assertEquals(4, johnGroups.size()); Assert.assertEquals(4, johnGroups.size());
@ -239,7 +239,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1"); GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11"); GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12"); GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
@ -267,7 +267,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12"); GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
// Add some group mapping to model. This should fail with no-import mode for LDAP provider READ_ONLY mode for the group mapper // Add some group mapping to model. This should fail with no-import mode for LDAP provider READ_ONLY mode for the group mapper
@ -284,7 +284,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1"); GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11"); GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12"); GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
@ -316,7 +316,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11"); GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12"); GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
UserModel maryDB = session.userLocalStorage().getUserByUsername("marykeycloak", appRealm); UserModel maryDB = session.userLocalStorage().getUserByUsername(appRealm, "marykeycloak");
Set<GroupModel> maryDBGroups = maryDB.getGroupsStream().collect(Collectors.toSet()); Set<GroupModel> maryDBGroups = maryDB.getGroupsStream().collect(Collectors.toSet());
Assert.assertFalse(maryDBGroups.contains(group1)); Assert.assertFalse(maryDBGroups.contains(group1));
@ -337,7 +337,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
Assert.assertEquals(1, group12Members.size()); Assert.assertEquals(1, group12Members.size());
Assert.assertEquals("marykeycloak", group12Members.get(0).getUsername()); Assert.assertEquals("marykeycloak", group12Members.get(0).getUsername());
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
mary.leaveGroup(group12); mary.leaveGroup(group12);
}); });
} else { } else {
@ -362,8 +362,8 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1"); GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11"); GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12"); GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm); UserModel john = session.users().getUserByUsername(appRealm, "johnkeycloak");
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(appRealm, ctx.getLdapModel(), "groupsMapper"); ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(appRealm, ctx.getLdapModel(), "groupsMapper");
GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ctx.getLdapProvider(), appRealm); GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ctx.getLdapProvider(), appRealm);
@ -417,7 +417,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
groupMapper.addGroupMappingInLDAP(appRealm, group12, robLdap); groupMapper.addGroupMappingInLDAP(appRealm, group12, robLdap);
// Get user and check that he has requested groups from LDAP // Get user and check that he has requested groups from LDAP
UserModel rob = session.users().getUserByUsername("robkeycloak", appRealm); UserModel rob = session.users().getUserByUsername(appRealm, "robkeycloak");
Set<GroupModel> robGroups = rob.getGroupsStream().collect(Collectors.toSet()); Set<GroupModel> robGroups = rob.getGroupsStream().collect(Collectors.toSet());
Assert.assertFalse(robGroups.contains(group1)); Assert.assertFalse(robGroups.contains(group1));
@ -563,7 +563,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
// Get user in Keycloak. Ensure that he is member of requested group // Get user in Keycloak. Ensure that he is member of requested group
UserModel carlos = session.users().getUserByUsername("carloskeycloak", appRealm); UserModel carlos = session.users().getUserByUsername(appRealm, "carloskeycloak");
Set<GroupModel> carlosGroups = carlos.getGroupsStream().collect(Collectors.toSet()); Set<GroupModel> carlosGroups = carlos.getGroupsStream().collect(Collectors.toSet());
GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1"); GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
@ -608,7 +608,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm); UserModel john = session.users().getUserByUsername(appRealm, "johnkeycloak");
GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4"); GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
john.joinGroup(group4); john.joinGroup(group4);
@ -628,7 +628,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm); UserModel john = session.users().getUserByUsername(appRealm, "johnkeycloak");
GroupModel group14 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group14"); GroupModel group14 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group14");
GroupModel group3 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3"); GroupModel group3 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3");
@ -747,7 +747,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
GroupModel kcBigGroup = KeycloakModelUtils.findGroupByPath(appRealm, "/biggroup"); GroupModel kcBigGroup = KeycloakModelUtils.findGroupByPath(appRealm, "/biggroup");
// check all the users have the group assigned // check all the users have the group assigned
for (int i = 0; i < membersToTest; i++) { for (int i = 0; i < membersToTest; i++) {
UserModel kcUser = session.users().getUserByUsername(String.format("user%02d", i), appRealm); UserModel kcUser = session.users().getUserByUsername(appRealm, String.format("user%02d", i));
Assert.assertTrue("User contains biggroup " + i, kcUser.getGroupsStream().collect(Collectors.toSet()).contains(kcBigGroup)); Assert.assertTrue("User contains biggroup " + i, kcUser.getGroupsStream().collect(Collectors.toSet()).contains(kcBigGroup));
} }
// check the group contains all the users as member // check the group contains all the users as member
@ -794,7 +794,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest {
// check everything is OK // check everything is OK
GroupModel kcDeleteGroup = KeycloakModelUtils.findGroupByPath(appRealm, "/deletegroup"); GroupModel kcDeleteGroup = KeycloakModelUtils.findGroupByPath(appRealm, "/deletegroup");
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm); UserModel mary = session.users().getUserByUsername(appRealm, "marykeycloak");
List<UserModel> groupMembers = session.users().getGroupMembersStream(appRealm, kcDeleteGroup, 0, 5) List<UserModel> groupMembers = session.users().getGroupMembersStream(appRealm, kcDeleteGroup, 0, 5)
.collect(Collectors.toList()); .collect(Collectors.toList());
Assert.assertEquals(1, groupMembers.size()); Assert.assertEquals(1, groupMembers.size());

View file

@ -84,7 +84,7 @@ public class LDAPHardcodedAttributeTest extends AbstractLDAPTest {
LDAPTestContext ctx = LDAPTestContext.init(session); LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
UserModel user = session.users().getUserByUsername("johnkeycloak", appRealm); UserModel user = session.users().getUserByUsername(appRealm, "johnkeycloak");
Assert.assertNotNull(user); Assert.assertNotNull(user);
Assert.assertTrue(user.isEmailVerified()); Assert.assertTrue(user.isEmailVerified());
Assert.assertEquals("en", user.getFirstAttribute("locale")); Assert.assertEquals("en", user.getFirstAttribute("locale"));

Some files were not shown because too many files have changed in this diff Show more