KEYCLOAK-15450 Complement methods for accessing realms with Stream variants

This commit is contained in:
Martin Kanis 2020-09-16 10:04:49 +02:00 committed by Hynek Mlnařík
parent 0621e4ceb9
commit 086f7b4696
148 changed files with 1844 additions and 2294 deletions

View file

@ -25,10 +25,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore;
import org.keycloak.storage.ldap.mappers.LDAPConfigDecorator; import org.keycloak.storage.ldap.mappers.LDAPConfigDecorator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -68,12 +66,9 @@ public class LDAPIdentityStoreRegistry {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
RealmModel realm = session.realms().getRealm(ldapModel.getParentId()); RealmModel realm = session.realms().getRealm(ldapModel.getParentId());
List<ComponentModel> mappers = realm.getComponents(ldapModel.getId()); realm.getComponentsStream(ldapModel.getId()).forEach(c ->
mappers.stream().forEach((ComponentModel c) -> { logger.debugf("Mapper for provider: %s, Mapper name: %s, Provider: %s, Mapper configuration: %s",
ldapModel.getName(), c.getName(), c.getProviderId(), c.getConfig().toString()));
logger.debugf("Mapper for provider: %s, Mapper name: %s, Provider: %s, Mapper configuration: %s", ldapModel.getName(), c.getName(), c.getProviderId(), c.getConfig().toString());
});
} }
} }

View file

@ -25,6 +25,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import javax.naming.AuthenticationException; import javax.naming.AuthenticationException;
@ -37,7 +39,18 @@ import org.keycloak.credential.CredentialInputUpdater;
import org.keycloak.credential.CredentialInputValidator; import org.keycloak.credential.CredentialInputValidator;
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator; import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator; import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
import org.keycloak.models.*; import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserManager;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CachedUserModel; import org.keycloak.models.cache.CachedUserModel;
import org.keycloak.models.credential.PasswordCredentialModel; import org.keycloak.models.credential.PasswordCredentialModel;
import org.keycloak.models.utils.DefaultRoles; import org.keycloak.models.utils.DefaultRoles;
@ -58,10 +71,11 @@ import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder; import org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore;
import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig; import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig;
import org.keycloak.storage.ldap.mappers.LDAPMappersComparator;
import org.keycloak.storage.ldap.mappers.LDAPOperationDecorator;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapperManager; import org.keycloak.storage.ldap.mappers.LDAPStorageMapperManager;
import org.keycloak.storage.ldap.mappers.PasswordUpdateCallback; import org.keycloak.storage.ldap.mappers.PasswordUpdateCallback;
import org.keycloak.storage.ldap.mappers.LDAPOperationDecorator;
import org.keycloak.storage.user.ImportedUserValidation; import org.keycloak.storage.user.ImportedUserValidation;
import org.keycloak.storage.user.UserLookupProvider; import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider; import org.keycloak.storage.user.UserQueryProvider;
@ -91,6 +105,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
protected PasswordUpdateCallback updater; protected PasswordUpdateCallback updater;
protected LDAPStorageMapperManager mapperManager; protected LDAPStorageMapperManager mapperManager;
protected LDAPStorageUserManager userManager; protected LDAPStorageUserManager userManager;
private LDAPMappersComparator ldapMappersComparator;
// these exist to make sure that we only hit ldap once per transaction // these exist to make sure that we only hit ldap once per transaction
//protected Map<String, UserModel> noImportSessionCache = new HashMap<>(); //protected Map<String, UserModel> noImportSessionCache = new HashMap<>();
@ -112,6 +127,8 @@ public class LDAPStorageProvider implements UserStorageProvider,
if (kerberosConfig.isAllowKerberosAuthentication()) { if (kerberosConfig.isAllowKerberosAuthentication()) {
supportedCredentialTypes.add(UserCredentialModel.KERBEROS); supportedCredentialTypes.add(UserCredentialModel.KERBEROS);
} }
ldapMappersComparator = new LDAPMappersComparator(getLdapIdentityStore().getConfig());
} }
public void setUpdater(PasswordUpdateCallback updater) { public void setUpdater(PasswordUpdateCallback updater) {
@ -192,12 +209,14 @@ public class LDAPStorageProvider implements UserStorageProvider,
break; break;
} }
List<ComponentModel> mappers = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName()); AtomicReference<UserModel> proxy = new AtomicReference<>(proxied);
List<ComponentModel> sortedMappers = mapperManager.sortMappersAsc(mappers); realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
for (ComponentModel mapperModel : sortedMappers) { .sorted(ldapMappersComparator.sortAsc())
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); .forEachOrdered(mapperModel -> {
proxied = ldapMapper.proxy(ldapObject, proxied, realm); LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
} proxy.set(ldapMapper.proxy(ldapObject, proxy.get(), realm));
});
proxied = proxy.get();
if (!model.isImportEnabled()) { if (!model.isImportEnabled()) {
proxied = new UpdateOnlyChangeUserModelDelegate(proxied); proxied = new UpdateOnlyChangeUserModelDelegate(proxied);
@ -241,7 +260,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
return Collections.emptyList(); return Collections.emptyList();
} }
List<UserModel> searchResults = new LinkedList<UserModel>(); List<UserModel> searchResults = new LinkedList<>();
for (LDAPObject ldapUser : ldapObjects) { for (LDAPObject ldapUser : ldapObjects) {
String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig()); String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig());
@ -286,11 +305,11 @@ public class LDAPStorageProvider implements UserStorageProvider,
realm.getDefaultGroupsStream().forEach(proxy::joinGroup); realm.getDefaultGroupsStream().forEach(proxy::joinGroup);
for (RequiredActionProviderModel r : realm.getRequiredActionProviders()) { realm.getRequiredActionProvidersStream()
if (r.isEnabled() && r.isDefaultAction()) { .filter(RequiredActionProviderModel::isEnabled)
proxy.addRequiredAction(r.getAlias()); .filter(RequiredActionProviderModel::isDefaultAction)
} .map(RequiredActionProviderModel::getAlias)
} .forEachOrdered(proxy::addRequiredAction);
return proxy; return proxy;
} }
@ -397,8 +416,10 @@ public class LDAPStorageProvider implements UserStorageProvider,
@Override @Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) { public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
List<ComponentModel> mappers = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName()); List<ComponentModel> sortedMappers = realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
List<ComponentModel> sortedMappers = mapperManager.sortMappersAsc(mappers); .sorted(ldapMappersComparator.sortAsc())
.collect(Collectors.toList());
for (ComponentModel mapperModel : sortedMappers) { for (ComponentModel mapperModel : sortedMappers) {
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
List<UserModel> users = ldapMapper.getGroupMembers(realm, group, firstResult, maxResults); List<UserModel> users = ldapMapper.getGroupMembers(realm, group, firstResult, maxResults);
@ -418,8 +439,9 @@ public class LDAPStorageProvider implements UserStorageProvider,
@Override @Override
public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) { public List<UserModel> getRoleMembers(RealmModel realm, RoleModel role, int firstResult, int maxResults) {
List<ComponentModel> mappers = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName()); List<ComponentModel> sortedMappers = realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
List<ComponentModel> sortedMappers = mapperManager.sortMappersAsc(mappers); .sorted(ldapMappersComparator.sortAsc())
.collect(Collectors.toList());
for (ComponentModel mapperModel : sortedMappers) { for (ComponentModel mapperModel : sortedMappers) {
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
List<UserModel> users = ldapMapper.getRoleMembers(realm, role, firstResult, maxResults); List<UserModel> users = ldapMapper.getRoleMembers(realm, role, firstResult, maxResults);
@ -544,15 +566,16 @@ public class LDAPStorageProvider implements UserStorageProvider,
} }
imported.setEnabled(true); imported.setEnabled(true);
List<ComponentModel> mappers = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName()); UserModel finalImported = imported;
List<ComponentModel> sortedMappers = mapperManager.sortMappersDesc(mappers); realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
for (ComponentModel mapperModel : sortedMappers) { .sorted(ldapMappersComparator.sortDesc())
if (logger.isTraceEnabled()) { .forEachOrdered(mapperModel -> {
logger.tracef("Using mapper %s during import user from LDAP", mapperModel); if (logger.isTraceEnabled()) {
} logger.tracef("Using mapper %s during import user from LDAP", mapperModel);
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); }
ldapMapper.onImportUserFromLDAP(ldapUser, imported, realm, true); LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
} ldapMapper.onImportUserFromLDAP(ldapUser, finalImported, realm, true);
});
String userDN = ldapUser.getDn().toString(); String userDN = ldapUser.getDn().toString();
if (model.isImportEnabled()) imported.setFederationLink(model.getId()); if (model.isImportEnabled()) imported.setFederationLink(model.getId());
@ -631,17 +654,17 @@ public class LDAPStorageProvider implements UserStorageProvider,
ldapIdentityStore.validatePassword(ldapUser, password); ldapIdentityStore.validatePassword(ldapUser, password);
return true; return true;
} catch (AuthenticationException ae) { } catch (AuthenticationException ae) {
boolean processed = false; AtomicReference<Boolean> processed = new AtomicReference<>(false);
List<ComponentModel> mappers = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName()); realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
List<ComponentModel> sortedMappers = mapperManager.sortMappersDesc(mappers); .sorted(ldapMappersComparator.sortDesc())
for (ComponentModel mapperModel : sortedMappers) { .forEachOrdered(mapperModel -> {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.tracef("Using mapper %s during import user from LDAP", mapperModel); logger.tracef("Using mapper %s during import user from LDAP", mapperModel);
} }
LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel); LDAPStorageMapper ldapMapper = mapperManager.getMapper(mapperModel);
processed = processed || ldapMapper.onAuthenticationFailure(ldapUser, user, ae, realm); processed.set(processed.get() || ldapMapper.onAuthenticationFailure(ldapUser, user, ae, realm));
} });
return processed; return processed.get();
} }
} }
} }

View file

@ -52,8 +52,8 @@ import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory;
import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapper; import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapper;
import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory; import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory;
import org.keycloak.storage.ldap.mappers.LDAPConfigDecorator; import org.keycloak.storage.ldap.mappers.LDAPConfigDecorator;
import org.keycloak.storage.ldap.mappers.LDAPMappersComparator;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory;
import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper; import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapperFactory; import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapperFactory;
import org.keycloak.storage.ldap.mappers.msad.MSADUserAccountControlStorageMapperFactory; import org.keycloak.storage.ldap.mappers.msad.MSADUserAccountControlStorageMapperFactory;
@ -62,9 +62,10 @@ import org.keycloak.storage.user.SynchronizationResult;
import org.keycloak.utils.CredentialHelper; import org.keycloak.utils.CredentialHelper;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -241,17 +242,12 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
// Check if it's some performance overhead to create this map in every request. But probably not... // Check if it's some performance overhead to create this map in every request. But probably not...
protected Map<ComponentModel, LDAPConfigDecorator> getLDAPConfigDecorators(KeycloakSession session, ComponentModel ldapModel) { protected Map<ComponentModel, LDAPConfigDecorator> getLDAPConfigDecorators(KeycloakSession session, ComponentModel ldapModel) {
RealmModel realm = session.realms().getRealm(ldapModel.getParentId()); RealmModel realm = session.realms().getRealm(ldapModel.getParentId());
List<ComponentModel> mapperComponents = realm.getComponents(ldapModel.getId(), LDAPStorageMapper.class.getName()); return realm.getComponentsStream(ldapModel.getId(), LDAPStorageMapper.class.getName())
.filter(mapperModel -> session.getKeycloakSessionFactory()
Map<ComponentModel, LDAPConfigDecorator> result = new HashMap<>(); .getProviderFactory(LDAPStorageMapper.class, mapperModel.getProviderId()) instanceof LDAPConfigDecorator)
for (ComponentModel mapperModel : mapperComponents) { .collect(Collectors.toMap(Function.identity(), mapperModel ->
LDAPStorageMapperFactory mapperFactory = (LDAPStorageMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(LDAPStorageMapper.class, mapperModel.getProviderId()); (LDAPConfigDecorator) session.getKeycloakSessionFactory()
if (mapperFactory instanceof LDAPConfigDecorator) { .getProviderFactory(LDAPStorageMapper.class, mapperModel.getProviderId())));
result.put(mapperModel, (LDAPConfigDecorator) mapperFactory);
}
}
return result;
} }
@ -504,14 +500,15 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
RealmModel realm = session.realms().getRealm(realmId); RealmModel realm = session.realms().getRealm(realmId);
session.getContext().setRealm(realm); session.getContext().setRealm(realm);
session.getProvider(UserStorageProvider.class, model); session.getProvider(UserStorageProvider.class, model);
List<ComponentModel> mappers = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName()); realm.getComponentsStream(model.getId(), LDAPStorageMapper.class.getName())
for (ComponentModel mapperModel : mappers) { .forEach(mapperModel -> {
LDAPStorageMapper ldapMapper = session.getProvider(LDAPStorageMapper.class, mapperModel); SynchronizationResult syncResult = session.getProvider(LDAPStorageMapper.class, mapperModel)
SynchronizationResult syncResult = ldapMapper.syncDataFromFederationProviderToKeycloak(realm); .syncDataFromFederationProviderToKeycloak(realm);
if (syncResult.getAdded() > 0 || syncResult.getUpdated() > 0 || syncResult.getRemoved() > 0 || syncResult.getFailed() > 0) { if (syncResult.getAdded() > 0 || syncResult.getUpdated() > 0 || syncResult.getRemoved() > 0
logger.infof("Sync of federation mapper '%s' finished. Status: %s", mapperModel.getName(), syncResult.toString()); || syncResult.getFailed() > 0) {
} logger.infof("Sync of federation mapper '%s' finished. Status: %s", mapperModel.getName(), syncResult.toString());
} }
});
} }
}); });
@ -609,12 +606,14 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory<LD
if ((fedModel.getId().equals(currentUser.getFederationLink())) && (ldapUser.getUuid().equals(currentUser.getFirstAttribute(LDAPConstants.LDAP_ID)))) { if ((fedModel.getId().equals(currentUser.getFederationLink())) && (ldapUser.getUuid().equals(currentUser.getFirstAttribute(LDAPConstants.LDAP_ID)))) {
// Update keycloak user // Update keycloak user
List<ComponentModel> federationMappers = currentRealm.getComponents(fedModel.getId(), LDAPStorageMapper.class.getName()); LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapFedProvider.getLdapIdentityStore().getConfig());
List<ComponentModel> sortedMappers = ldapFedProvider.getMapperManager().sortMappersDesc(federationMappers); currentRealm.getComponentsStream(fedModel.getId(), LDAPStorageMapper.class.getName())
for (ComponentModel mapperModel : sortedMappers) { .sorted(ldapMappersComparator.sortDesc())
LDAPStorageMapper ldapMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel); .forEachOrdered(mapperModel -> {
ldapMapper.onImportUserFromLDAP(ldapUser, currentUser, currentRealm, false); LDAPStorageMapper ldapMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel);
} ldapMapper.onImportUserFromLDAP(ldapUser, currentUser, currentRealm, false);
});
UserCache userCache = session.userCache(); UserCache userCache = session.userCache();
if (userCache != null) { if (userCache != null) {
userCache.evict(currentRealm, currentUser); userCache.evict(currentRealm, currentUser);

View file

@ -25,6 +25,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.naming.directory.SearchControls; import javax.naming.directory.SearchControls;
@ -43,6 +44,7 @@ import org.keycloak.storage.ldap.idm.query.Condition;
import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery; import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder; import org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore;
import org.keycloak.storage.ldap.mappers.LDAPMappersComparator;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.membership.MembershipType; import org.keycloak.storage.ldap.mappers.membership.MembershipType;
@ -67,12 +69,13 @@ public class LDAPUtils {
ldapUser.setRdnAttributeName(ldapConfig.getRdnLdapAttribute()); ldapUser.setRdnAttributeName(ldapConfig.getRdnLdapAttribute());
ldapUser.setObjectClasses(ldapConfig.getUserObjectClasses()); ldapUser.setObjectClasses(ldapConfig.getUserObjectClasses());
List<ComponentModel> federationMappers = realm.getComponents(ldapProvider.getModel().getId(), LDAPStorageMapper.class.getName()); LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapConfig);
List<ComponentModel> sortedMappers = ldapProvider.getMapperManager().sortMappersAsc(federationMappers); realm.getComponentsStream(ldapProvider.getModel().getId(), LDAPStorageMapper.class.getName())
for (ComponentModel mapperModel : sortedMappers) { .sorted(ldapMappersComparator.sortAsc())
LDAPStorageMapper ldapMapper = ldapProvider.getMapperManager().getMapper(mapperModel); .forEachOrdered(mapperModel -> {
ldapMapper.onRegisterUserToLDAP(ldapUser, user, realm); LDAPStorageMapper ldapMapper = ldapProvider.getMapperManager().getMapper(mapperModel);
} ldapMapper.onRegisterUserToLDAP(ldapUser, user, realm);
});
LDAPUtils.computeAndSetDn(ldapConfig, ldapUser); LDAPUtils.computeAndSetDn(ldapConfig, ldapUser);
ldapStore.add(ldapUser); ldapStore.add(ldapUser);
@ -92,7 +95,9 @@ public class LDAPUtils {
ldapQuery.addWhereCondition(customFilterCondition); ldapQuery.addWhereCondition(customFilterCondition);
} }
List<ComponentModel> mapperModels = realm.getComponents(ldapProvider.getModel().getId(), LDAPStorageMapper.class.getName()); List<ComponentModel> mapperModels = realm
.getComponentsStream(ldapProvider.getModel().getId(), LDAPStorageMapper.class.getName())
.collect(Collectors.toList());
ldapQuery.addMappers(mapperModels); ldapQuery.addMappers(mapperModels);
return ldapQuery; return ldapQuery;

View file

@ -26,18 +26,14 @@ import org.keycloak.storage.ldap.idm.model.LDAPObject;
import org.keycloak.storage.ldap.idm.query.Condition; import org.keycloak.storage.ldap.idm.query.Condition;
import org.keycloak.storage.ldap.idm.query.Sort; import org.keycloak.storage.ldap.idm.query.Sort;
import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager; import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager;
import org.keycloak.storage.ldap.mappers.LDAPMappersComparator;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.naming.directory.SearchControls; import javax.naming.directory.SearchControls;
import javax.naming.ldap.LdapContext; import javax.naming.ldap.LdapContext;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static java.util.Collections.unmodifiableSet; import static java.util.Collections.unmodifiableSet;
@ -162,8 +158,10 @@ public class LDAPQuery implements AutoCloseable {
public List<LDAPObject> getResultList() { public List<LDAPObject> getResultList() {
// Apply mappers now // Apply mappers now
List<ComponentModel> sortedMappers = ldapFedProvider.getMapperManager().sortMappersAsc(mappers); LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapFedProvider.getLdapIdentityStore().getConfig());
for (ComponentModel mapperModel : sortedMappers) { Collections.sort(mappers, ldapMappersComparator.sortAsc());
for (ComponentModel mapperModel : mappers) {
LDAPStorageMapper fedMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel); LDAPStorageMapper fedMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel);
fedMapper.beforeLDAPQuery(this); fedMapper.beforeLDAPQuery(this);
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.storage.ldap.mappers; package org.keycloak.storage.ldap.mappers;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.storage.ldap.LDAPConfig; import org.keycloak.storage.ldap.LDAPConfig;
@ -34,20 +35,18 @@ import java.util.List;
*/ */
public class LDAPMappersComparator { public class LDAPMappersComparator {
public static List<ComponentModel> sortAsc(LDAPConfig ldapConfig, Collection<ComponentModel> mappers) { private LDAPConfig ldapConfig;
Comparator<ComponentModel> comparator = new ImportantFirstComparator(ldapConfig);
List<ComponentModel> result = new ArrayList<>(mappers); public LDAPMappersComparator(LDAPConfig ldapConfig) {
Collections.sort(result, comparator); this.ldapConfig = ldapConfig;
return result;
} }
public static List<ComponentModel> sortDesc(LDAPConfig ldapConfig, Collection<ComponentModel> mappers) { public Comparator<ComponentModel> sortAsc() {
Comparator<ComponentModel> comparator = new ImportantFirstComparator(ldapConfig).reversed(); return new ImportantFirstComparator(ldapConfig);
}
List<ComponentModel> result = new ArrayList<>(mappers); public Comparator<ComponentModel> sortDesc() {
Collections.sort(result, comparator); return new ImportantFirstComparator(ldapConfig).reversed();
return result;
} }

View file

@ -17,9 +17,6 @@
package org.keycloak.storage.ldap.mappers; package org.keycloak.storage.ldap.mappers;
import java.util.Collection;
import java.util.List;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
import org.keycloak.storage.ldap.LDAPStorageProvider; import org.keycloak.storage.ldap.LDAPStorageProvider;
@ -45,15 +42,4 @@ public class LDAPStorageMapperManager {
return ldapMapper; return ldapMapper;
} }
public List<ComponentModel> sortMappersAsc(Collection<ComponentModel> mappers) {
return LDAPMappersComparator.sortAsc(ldapProvider.getLdapIdentityStore().getConfig(), mappers);
}
public List<ComponentModel> sortMappersDesc(Collection<ComponentModel> mappers) {
return LDAPMappersComparator.sortDesc(ldapProvider.getLdapIdentityStore().getConfig(), mappers);
}
} }

View file

@ -32,6 +32,7 @@ import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper; import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapperFactory; import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapperFactory;
import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -46,26 +47,30 @@ public class LDAPMappersComparatorTest {
public void testCompareWithCNUsername() { public void testCompareWithCNUsername() {
MultivaluedHashMap<String, String> cfg = new MultivaluedHashMap<>(); MultivaluedHashMap<String, String> cfg = new MultivaluedHashMap<>();
cfg.add(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, LDAPConstants.CN); cfg.add(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, LDAPConstants.CN);
LDAPConfig config = new LDAPConfig(cfg); LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(new LDAPConfig(cfg));
List<ComponentModel> sorted = LDAPMappersComparator.sortAsc(config, getMappers()); List<ComponentModel> mappers = getMappers();
assertOrder(sorted, "username-cn", "sAMAccountName", "first name", "full name");
sorted = LDAPMappersComparator.sortDesc(config, getMappers()); Collections.sort(mappers, ldapMappersComparator.sortAsc());
assertOrder(sorted, "full name", "first name", "sAMAccountName", "username-cn"); assertOrder(mappers, "username-cn", "sAMAccountName", "first name", "full name");
Collections.sort(mappers, ldapMappersComparator.sortDesc());
assertOrder(mappers, "full name", "first name", "sAMAccountName", "username-cn");
} }
@Test @Test
public void testCompareWithSAMAccountNameUsername() { public void testCompareWithSAMAccountNameUsername() {
MultivaluedHashMap<String, String> cfg = new MultivaluedHashMap<>(); MultivaluedHashMap<String, String> cfg = new MultivaluedHashMap<>();
cfg.add(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, LDAPConstants.SAM_ACCOUNT_NAME); cfg.add(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, LDAPConstants.SAM_ACCOUNT_NAME);
LDAPConfig config = new LDAPConfig(cfg); LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(new LDAPConfig(cfg));
List<ComponentModel> sorted = LDAPMappersComparator.sortAsc(config, getMappers()); List<ComponentModel> mappers = getMappers();
assertOrder(sorted, "sAMAccountName", "username-cn", "first name", "full name");
sorted = LDAPMappersComparator.sortDesc(config, getMappers()); Collections.sort(mappers, ldapMappersComparator.sortAsc());
assertOrder(sorted, "full name", "first name", "username-cn", "sAMAccountName"); assertOrder(mappers, "sAMAccountName", "username-cn", "first name", "full name");
Collections.sort(mappers, ldapMappersComparator.sortDesc());
assertOrder(mappers, "full name", "first name", "username-cn", "sAMAccountName");
} }
private void assertOrder(List<ComponentModel> result, String... names) { private void assertOrder(List<ComponentModel> result, String... names) {

View file

@ -638,9 +638,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<RequiredCredentialModel> getRequiredCredentials() { public Stream<RequiredCredentialModel> getRequiredCredentialsStream() {
if (isUpdated()) return updated.getRequiredCredentials(); if (isUpdated()) return updated.getRequiredCredentialsStream();
return cached.getRequiredCredentials(); return cached.getRequiredCredentials().stream();
} }
@Override @Override
@ -833,21 +833,18 @@ public class RealmAdapter implements CachedRealmModel {
@Override @Override
public List<IdentityProviderModel> getIdentityProviders() { public Stream<IdentityProviderModel> getIdentityProvidersStream() {
if (isUpdated()) return updated.getIdentityProviders(); if (isUpdated()) return updated.getIdentityProvidersStream();
return cached.getIdentityProviders(); return cached.getIdentityProviders().stream();
} }
@Override @Override
public IdentityProviderModel getIdentityProviderByAlias(String alias) { public IdentityProviderModel getIdentityProviderByAlias(String alias) {
if (isUpdated()) return updated.getIdentityProviderByAlias(alias); if (isUpdated()) return updated.getIdentityProviderByAlias(alias);
for (IdentityProviderModel identityProviderModel : getIdentityProviders()) { return getIdentityProvidersStream()
if (identityProviderModel.getAlias().equals(alias)) { .filter(model -> Objects.equals(model.getAlias(), alias))
return identityProviderModel; .findFirst()
} .orElse(null);
}
return null;
} }
@Override @Override
@ -953,9 +950,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public Set<String> getEventsListeners() { public Stream<String> getEventsListenersStream() {
if (isUpdated()) return updated.getEventsListeners(); if (isUpdated()) return updated.getEventsListenersStream();
return cached.getEventsListeners(); return cached.getEventsListeners().stream();
} }
@Override @Override
@ -965,9 +962,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public Set<String> getEnabledEventTypes() { public Stream<String> getEnabledEventTypesStream() {
if (isUpdated()) return updated.getEnabledEventTypes(); if (isUpdated()) return updated.getEnabledEventTypesStream();
return cached.getEnabledEventTypes(); return cached.getEnabledEventTypes().stream();
} }
@Override @Override
@ -1081,9 +1078,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public Set<String> getSupportedLocales() { public Stream<String> getSupportedLocalesStream() {
if (isUpdated()) return updated.getSupportedLocales(); if (isUpdated()) return updated.getSupportedLocalesStream();
return cached.getSupportedLocales(); return cached.getSupportedLocales().stream();
} }
@Override @Override
@ -1104,20 +1101,16 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public Set<IdentityProviderMapperModel> getIdentityProviderMappers() { public Stream<IdentityProviderMapperModel> getIdentityProviderMappersStream() {
if (isUpdated()) return updated.getIdentityProviderMappers(); if (isUpdated()) return updated.getIdentityProviderMappersStream();
return cached.getIdentityProviderMapperSet(); return cached.getIdentityProviderMapperSet().stream();
} }
@Override @Override
public Set<IdentityProviderMapperModel> getIdentityProviderMappersByAlias(String brokerAlias) { public Stream<IdentityProviderMapperModel> getIdentityProviderMappersByAliasStream(String brokerAlias) {
if (isUpdated()) return updated.getIdentityProviderMappersByAlias(brokerAlias); if (isUpdated()) return updated.getIdentityProviderMappersByAliasStream(brokerAlias);
Set<IdentityProviderMapperModel> mappings = new HashSet<>(); Set<IdentityProviderMapperModel> mappings = new HashSet<>(cached.getIdentityProviderMappers().getList(brokerAlias));
List<IdentityProviderMapperModel> list = cached.getIdentityProviderMappers().getList(brokerAlias); return mappings.stream();
for (IdentityProviderMapperModel entity : list) {
mappings.add(entity);
}
return Collections.unmodifiableSet(mappings);
} }
@Override @Override
@ -1236,29 +1229,25 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<AuthenticationFlowModel> getAuthenticationFlows() { public Stream<AuthenticationFlowModel> getAuthenticationFlowsStream() {
if (isUpdated()) return updated.getAuthenticationFlows(); if (isUpdated()) return updated.getAuthenticationFlowsStream();
return cached.getAuthenticationFlowList(); return cached.getAuthenticationFlowList().stream();
} }
@Override @Override
public AuthenticationFlowModel getFlowByAlias(String alias) { public AuthenticationFlowModel getFlowByAlias(String alias) {
for (AuthenticationFlowModel flow : getAuthenticationFlows()) { return getAuthenticationFlowsStream()
if (flow.getAlias().equals(alias)) { .filter(flow -> Objects.equals(flow.getAlias(), alias))
return flow; .findFirst()
} .orElse(null);
}
return null;
} }
@Override @Override
public AuthenticatorConfigModel getAuthenticatorConfigByAlias(String alias) { public AuthenticatorConfigModel getAuthenticatorConfigByAlias(String alias) {
for (AuthenticatorConfigModel config : getAuthenticatorConfigs()) { return getAuthenticatorConfigsStream()
if (config.getAlias().equals(alias)) { .filter(config -> Objects.equals(config.getAlias(), alias))
return config; .findFirst()
} .orElse(null);
}
return null;
} }
@ -1289,9 +1278,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) { public Stream<AuthenticationExecutionModel> getAuthenticationExecutionsStream(String flowId) {
if (isUpdated()) return updated.getAuthenticationExecutions(flowId); if (isUpdated()) return updated.getAuthenticationExecutionsStream(flowId);
return cached.getAuthenticationExecutions().get(flowId); return cached.getAuthenticationExecutions().get(flowId).stream();
} }
@Override @Override
@ -1327,11 +1316,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<AuthenticatorConfigModel> getAuthenticatorConfigs() { public Stream<AuthenticatorConfigModel> getAuthenticatorConfigsStream() {
if (isUpdated()) return updated.getAuthenticatorConfigs(); if (isUpdated()) return updated.getAuthenticatorConfigsStream();
List<AuthenticatorConfigModel> models = new ArrayList<>(); return cached.getAuthenticatorConfigs().values().stream();
models.addAll(cached.getAuthenticatorConfigs().values());
return Collections.unmodifiableList(models);
} }
@Override @Override
@ -1361,9 +1348,9 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<RequiredActionProviderModel> getRequiredActionProviders() { public Stream<RequiredActionProviderModel> getRequiredActionProvidersStream() {
if (isUpdated()) return updated.getRequiredActionProviders(); if (isUpdated()) return updated.getRequiredActionProvidersStream();
return cached.getRequiredActionProviderList(); return cached.getRequiredActionProviderList().stream();
} }
@Override @Override
@ -1449,20 +1436,15 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<ClientScopeModel> getClientScopes() { public Stream<ClientScopeModel> getClientScopesStream() {
if (isUpdated()) return updated.getClientScopes(); if (isUpdated()) return updated.getClientScopesStream();
List<String> clientScopes = cached.getClientScopes(); return cached.getClientScopes().stream().map(scope -> {
if (clientScopes.isEmpty()) return Collections.EMPTY_LIST; ClientScopeModel model = cacheSession.getClientScopeById(scope, this);
List<ClientScopeModel> apps = new LinkedList<>();
for (String id : clientScopes) {
ClientScopeModel model = cacheSession.getClientScopeById(id, this);
if (model == null) { if (model == null) {
throw new IllegalStateException("Cached clientScope not found: " + id); throw new IllegalStateException("Cached clientScope not found: " + scope);
} }
apps.add(model); return model;
} });
return Collections.unmodifiableList(apps);
} }
@Override @Override
@ -1507,19 +1489,12 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<ClientScopeModel> getDefaultClientScopes(boolean defaultScope) { public Stream<ClientScopeModel> getDefaultClientScopesStream(boolean defaultScope) {
if (isUpdated()) return updated.getDefaultClientScopes(defaultScope); if (isUpdated()) return updated.getDefaultClientScopesStream(defaultScope);
List<String> clientScopeIds = defaultScope ? cached.getDefaultDefaultClientScopes() : cached.getOptionalDefaultClientScopes(); List<String> clientScopeIds = defaultScope ? cached.getDefaultDefaultClientScopes() : cached.getOptionalDefaultClientScopes();
return clientScopeIds.stream()
List<ClientScopeModel> clientScopes = new LinkedList<>(); .map(scope -> cacheSession.getClientScopeById(scope, this))
for (String scopeId : clientScopeIds) { .filter(Objects::nonNull);
ClientScopeModel clientScope = cacheSession.getClientScopeById(scopeId, this);
if (clientScope != null) {
clientScopes.add(clientScope);
}
}
return clientScopes;
} }
@Override @Override
@ -1588,27 +1563,21 @@ public class RealmAdapter implements CachedRealmModel {
} }
@Override @Override
public List<ComponentModel> getComponents(String parentId, String providerType) { public Stream<ComponentModel> getComponentsStream(String parentId, String providerType) {
if (isUpdated()) return updated.getComponents(parentId, providerType); if (isUpdated()) return updated.getComponentsStream(parentId, providerType);
List<ComponentModel> components = cached.getComponentsByParentAndType().getList(parentId + providerType); return cached.getComponentsByParentAndType().getList(parentId + providerType).stream();
if (components == null) return Collections.EMPTY_LIST;
return Collections.unmodifiableList(components);
} }
@Override @Override
public List<ComponentModel> getComponents(String parentId) { public Stream<ComponentModel> getComponentsStream(String parentId) {
if (isUpdated()) return updated.getComponents(parentId); if (isUpdated()) return updated.getComponentsStream(parentId);
List<ComponentModel> components = cached.getComponentsByParent().getList(parentId); return cached.getComponentsByParent().getList(parentId).stream();
if (components == null) return Collections.EMPTY_LIST;
return Collections.unmodifiableList(components);
} }
@Override @Override
public List<ComponentModel> getComponents() { public Stream<ComponentModel> getComponentsStream() {
if (isUpdated()) return updated.getComponents(); if (isUpdated()) return updated.getComponentsStream();
List<ComponentModel> results = new LinkedList<>(); return cached.getComponents().values().stream();
results.addAll(cached.getComponents().values());
return Collections.unmodifiableList(results);
} }
@Override @Override

View file

@ -468,27 +468,20 @@ public class RealmCacheSession implements CacheRealmProvider {
} }
@Override @Override
public List<RealmModel> getRealmsWithProviderType(Class<?> type) { public Stream<RealmModel> getRealmsWithProviderTypeStream(Class<?> type) {
// Retrieve realms from backend // Retrieve realms from backend
List<RealmModel> backendRealms = getRealmDelegate().getRealmsWithProviderType(type); return getRealms(getRealmDelegate().getRealmsWithProviderTypeStream(type));
return getRealms(backendRealms);
} }
@Override @Override
public List<RealmModel> getRealms() { public Stream<RealmModel> getRealmsStream() {
// Retrieve realms from backend // Retrieve realms from backend
List<RealmModel> backendRealms = getRealmDelegate().getRealms(); return getRealms(getRealmDelegate().getRealmsStream());
return getRealms(backendRealms);
} }
private List<RealmModel> getRealms(List<RealmModel> backendRealms) { private Stream<RealmModel> getRealms(Stream<RealmModel> backendRealms) {
// Return cache delegates to ensure cache invalidated during write operations // Return cache delegates to ensure cache invalidated during write operations
List<RealmModel> cachedRealms = new LinkedList<>(); return backendRealms.map(RealmModel::getId).map(this::getRealm);
for (RealmModel realm : backendRealms) {
RealmModel cached = getRealm(realm.getId());
cachedRealms.add(cached);
}
return cachedRealms;
} }
@Override @Override
@ -1240,8 +1233,8 @@ public class RealmCacheSession implements CacheRealmProvider {
} }
@Override @Override
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) { public Stream<ClientInitialAccessModel> listClientInitialAccessStream(RealmModel realm) {
return getRealmDelegate().listClientInitialAccess(realm); return getRealmDelegate().listClientInitialAccessStream(realm);
} }
@Override @Override

View file

@ -35,7 +35,6 @@ import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.WebAuthnPolicy; import org.keycloak.models.WebAuthnPolicy;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -43,6 +42,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -113,14 +113,14 @@ public class CachedRealm extends AbstractExtendableRevisioned {
protected List<RequiredCredentialModel> requiredCredentials; protected List<RequiredCredentialModel> requiredCredentials;
protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>(); protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>(); protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>();
protected Map<String, ComponentModel> components = new HashMap<>(); protected Map<String, ComponentModel> components;
protected List<IdentityProviderModel> identityProviders; protected List<IdentityProviderModel> identityProviders;
protected Map<String, String> browserSecurityHeaders; protected Map<String, String> browserSecurityHeaders;
protected Map<String, String> smtpConfig; protected Map<String, String> smtpConfig;
protected Map<String, AuthenticationFlowModel> authenticationFlows = new HashMap<>(); protected Map<String, AuthenticationFlowModel> authenticationFlows = new HashMap<>();
protected List<AuthenticationFlowModel> authenticationFlowList; protected List<AuthenticationFlowModel> authenticationFlowList;
protected Map<String, AuthenticatorConfigModel> authenticatorConfigs = new HashMap<>(); protected Map<String, AuthenticatorConfigModel> authenticatorConfigs;
protected Map<String, RequiredActionProviderModel> requiredActionProviders = new HashMap<>(); protected Map<String, RequiredActionProviderModel> requiredActionProviders = new HashMap<>();
protected List<RequiredActionProviderModel> requiredActionProviderList; protected List<RequiredActionProviderModel> requiredActionProviderList;
protected Map<String, RequiredActionProviderModel> requiredActionProvidersByAlias = new HashMap<>(); protected Map<String, RequiredActionProviderModel> requiredActionProvidersByAlias = new HashMap<>();
@ -224,17 +224,14 @@ public class CachedRealm extends AbstractExtendableRevisioned {
adminTheme = model.getAdminTheme(); adminTheme = model.getAdminTheme();
emailTheme = model.getEmailTheme(); emailTheme = model.getEmailTheme();
requiredCredentials = model.getRequiredCredentials(); requiredCredentials = model.getRequiredCredentialsStream().collect(Collectors.toList());
userActionTokenLifespans = Collections.unmodifiableMap(new HashMap<>(model.getUserActionTokenLifespans())); userActionTokenLifespans = Collections.unmodifiableMap(new HashMap<>(model.getUserActionTokenLifespans()));
this.identityProviders = new ArrayList<>(); this.identityProviders = model.getIdentityProvidersStream().map(IdentityProviderModel::new)
.collect(Collectors.toList());
for (IdentityProviderModel identityProviderModel : model.getIdentityProviders()) {
this.identityProviders.add(new IdentityProviderModel(identityProviderModel));
}
this.identityProviders = Collections.unmodifiableList(this.identityProviders); this.identityProviders = Collections.unmodifiableList(this.identityProviders);
this.identityProviderMapperSet = model.getIdentityProviderMappers(); this.identityProviderMapperSet = model.getIdentityProviderMappersStream().collect(Collectors.toSet());
for (IdentityProviderMapperModel mapper : identityProviderMapperSet) { for (IdentityProviderMapperModel mapper : identityProviderMapperSet) {
identityProviderMappers.add(mapper.getIdentityProviderAlias(), mapper); identityProviderMappers.add(mapper.getIdentityProviderAlias(), mapper);
} }
@ -246,8 +243,8 @@ public class CachedRealm extends AbstractExtendableRevisioned {
eventsEnabled = model.isEventsEnabled(); eventsEnabled = model.isEventsEnabled();
eventsExpiration = model.getEventsExpiration(); eventsExpiration = model.getEventsExpiration();
eventsListeners = model.getEventsListeners(); eventsListeners = model.getEventsListenersStream().collect(Collectors.toSet());
enabledEventTypes = model.getEnabledEventTypes(); enabledEventTypes = model.getEnabledEventTypesStream().collect(Collectors.toSet());
adminEventsEnabled = model.isAdminEventsEnabled(); adminEventsEnabled = model.isAdminEventsEnabled();
adminEventsDetailsEnabled = model.isAdminEventsDetailsEnabled(); adminEventsDetailsEnabled = model.isAdminEventsDetailsEnabled();
@ -259,25 +256,24 @@ public class CachedRealm extends AbstractExtendableRevisioned {
cacheClientScopes(model); cacheClientScopes(model);
internationalizationEnabled = model.isInternationalizationEnabled(); internationalizationEnabled = model.isInternationalizationEnabled();
supportedLocales = model.getSupportedLocales(); supportedLocales = model.getSupportedLocalesStream().collect(Collectors.toSet());
defaultLocale = model.getDefaultLocale(); defaultLocale = model.getDefaultLocale();
authenticationFlowList = model.getAuthenticationFlows(); authenticationFlowList = model.getAuthenticationFlowsStream().collect(Collectors.toList());
for (AuthenticationFlowModel flow : authenticationFlowList) { for (AuthenticationFlowModel flow : authenticationFlowList) {
this.authenticationFlows.put(flow.getId(), flow); this.authenticationFlows.put(flow.getId(), flow);
authenticationExecutions.put(flow.getId(), new LinkedList<>()); authenticationExecutions.put(flow.getId(), new LinkedList<>());
for (AuthenticationExecutionModel execution : model.getAuthenticationExecutions(flow.getId())) { model.getAuthenticationExecutionsStream(flow.getId()).forEachOrdered(execution -> {
authenticationExecutions.add(flow.getId(), execution); authenticationExecutions.add(flow.getId(), execution);
executionsById.put(execution.getId(), execution); executionsById.put(execution.getId(), execution);
if (execution.getFlowId() != null) { if (execution.getFlowId() != null) {
executionsByFlowId.put(execution.getFlowId(), execution); executionsByFlowId.put(execution.getFlowId(), execution);
} }
} });
} }
for (AuthenticatorConfigModel authenticator : model.getAuthenticatorConfigs()) { authenticatorConfigs = model.getAuthenticatorConfigsStream()
authenticatorConfigs.put(authenticator.getId(), authenticator); .collect(Collectors.toMap(AuthenticatorConfigModel::getId, Function.identity()));
} requiredActionProviderList = model.getRequiredActionProvidersStream().collect(Collectors.toList());
requiredActionProviderList = model.getRequiredActionProviders();
for (RequiredActionProviderModel action : requiredActionProviderList) { for (RequiredActionProviderModel action : requiredActionProviderList) {
this.requiredActionProviders.put(action.getId(), action); this.requiredActionProviders.put(action.getId(), action);
requiredActionProvidersByAlias.put(action.getAlias(), action); requiredActionProvidersByAlias.put(action.getAlias(), action);
@ -292,15 +288,13 @@ public class CachedRealm extends AbstractExtendableRevisioned {
clientAuthenticationFlow = model.getClientAuthenticationFlow(); clientAuthenticationFlow = model.getClientAuthenticationFlow();
dockerAuthenticationFlow = model.getDockerAuthenticationFlow(); dockerAuthenticationFlow = model.getDockerAuthenticationFlow();
for (ComponentModel component : model.getComponents()) { model.getComponentsStream().forEach(component ->
componentsByParentAndType.add(component.getParentId() + component.getProviderType(), component); componentsByParentAndType.add(component.getParentId() + component.getProviderType(), component)
} );
for (ComponentModel component : model.getComponents()) { model.getComponentsStream().forEach(component ->
componentsByParent.add(component.getParentId(), component); componentsByParent.add(component.getParentId(), component)
} );
for (ComponentModel component : model.getComponents()) { components = model.getComponentsStream().collect(Collectors.toMap(component -> component.getId(), Function.identity()));
components.put(component.getId(), component);
}
try { try {
attributes = model.getAttributes(); attributes = model.getAttributes();
@ -310,15 +304,11 @@ public class CachedRealm extends AbstractExtendableRevisioned {
} }
protected void cacheClientScopes(RealmModel model) { protected void cacheClientScopes(RealmModel model) {
for (ClientScopeModel clientScope : model.getClientScopes()) { clientScopes = model.getClientScopesStream().map(ClientScopeModel::getId).collect(Collectors.toList());
clientScopes.add(clientScope.getId()); defaultDefaultClientScopes = model.getDefaultClientScopesStream(true).map(ClientScopeModel::getId)
} .collect(Collectors.toList());
for (ClientScopeModel clientScope : model.getDefaultClientScopes(true)) { optionalDefaultClientScopes = model.getDefaultClientScopesStream(false).map(ClientScopeModel::getId)
defaultDefaultClientScopes.add(clientScope.getId()); .collect(Collectors.toList());
}
for (ClientScopeModel clientScope : model.getDefaultClientScopes(false)) {
optionalDefaultClientScopes.add(clientScope.getId());
}
} }
public String getMasterAdminClient() { public String getMasterAdminClient() {

View file

@ -33,6 +33,9 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static org.keycloak.utils.StreamsUtil.closing;
/** /**
* @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a> * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
@ -140,7 +143,7 @@ public class JpaAdminEventQuery implements AdminEventQuery {
} }
@Override @Override
public List<AdminEvent> getResultList() { public Stream<AdminEvent> getResultStream() {
if (!predicates.isEmpty()) { if (!predicates.isEmpty()) {
cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()]))); cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
} }
@ -157,12 +160,7 @@ public class JpaAdminEventQuery implements AdminEventQuery {
query.setMaxResults(maxResults); query.setMaxResults(maxResults);
} }
List<AdminEvent> events = new LinkedList<AdminEvent>(); return closing(query.getResultStream().map(JpaEventStoreProvider::convertAdminEvent));
for (AdminEventEntity e : query.getResultList()) {
events.add(JpaEventStoreProvider.convertAdminEvent(e));
}
return events;
} }
} }

View file

@ -31,6 +31,9 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static org.keycloak.utils.StreamsUtil.closing;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -113,7 +116,7 @@ public class JpaEventQuery implements EventQuery {
} }
@Override @Override
public List<Event> getResultList() { public Stream<Event> getResultStream() {
if (!predicates.isEmpty()) { if (!predicates.isEmpty()) {
cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()]))); cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
} }
@ -130,12 +133,8 @@ public class JpaEventQuery implements EventQuery {
query.setMaxResults(maxResults); query.setMaxResults(maxResults);
} }
List<Event> events = new LinkedList<Event>();
for (EventEntity e : query.getResultList()) {
events.add(JpaEventStoreProvider.convertEvent(e));
}
return events; return closing(query.getResultStream().map(JpaEventStoreProvider::convertEvent));
} }
} }

View file

@ -110,26 +110,20 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
} }
@Override @Override
public List<RealmModel> getRealmsWithProviderType(Class<?> providerType) { public Stream<RealmModel> getRealmsWithProviderTypeStream(Class<?> providerType) {
TypedQuery<String> query = em.createNamedQuery("getRealmIdsWithProviderType", String.class); TypedQuery<String> query = em.createNamedQuery("getRealmIdsWithProviderType", String.class);
query.setParameter("providerType", providerType.getName()); query.setParameter("providerType", providerType.getName());
return getRealms(query); return getRealms(query);
} }
@Override @Override
public List<RealmModel> getRealms() { public Stream<RealmModel> getRealmsStream() {
TypedQuery<String> query = em.createNamedQuery("getAllRealmIds", String.class); TypedQuery<String> query = em.createNamedQuery("getAllRealmIds", String.class);
return getRealms(query); return getRealms(query);
} }
private List<RealmModel> getRealms(TypedQuery<String> query) { private Stream<RealmModel> getRealms(TypedQuery<String> query) {
List<String> entities = query.getResultList(); return closing(query.getResultStream().map(session.realms()::getRealm).filter(Objects::nonNull));
List<RealmModel> realms = new ArrayList<RealmModel>();
for (String id : entities) {
RealmModel realm = session.realms().getRealm(id);
if (realm != null) realms.add(realm);
}
return realms;
} }
@Override @Override
@ -843,16 +837,12 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, GroupPro
} }
@Override @Override
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) { public Stream<ClientInitialAccessModel> listClientInitialAccessStream(RealmModel realm) {
RealmEntity realmEntity = em.find(RealmEntity.class, realm.getId()); RealmEntity realmEntity = em.find(RealmEntity.class, realm.getId());
TypedQuery<ClientInitialAccessEntity> query = em.createNamedQuery("findClientInitialAccessByRealm", ClientInitialAccessEntity.class); TypedQuery<ClientInitialAccessEntity> query = em.createNamedQuery("findClientInitialAccessByRealm", ClientInitialAccessEntity.class);
query.setParameter("realm", realmEntity); query.setParameter("realm", realmEntity);
List<ClientInitialAccessEntity> entities = query.getResultList(); return closing(query.getResultStream().map(this::entityToModel));
return entities.stream()
.map(this::entityToModel)
.collect(Collectors.toList());
} }
@Override @Override

View file

@ -57,15 +57,7 @@ import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery; import javax.persistence.criteria.Subquery;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.persistence.LockModeType; import javax.persistence.LockModeType;
@ -114,12 +106,14 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
realm.getDefaultGroupsStream().forEach(userModel::joinGroupImpl); realm.getDefaultGroupsStream().forEach(userModel::joinGroupImpl);
} }
if (addDefaultRequiredActions){ if (addDefaultRequiredActions) {
for (RequiredActionProviderModel r : realm.getRequiredActionProviders()) { Optional<String> requiredAction = realm.getRequiredActionProvidersStream()
if (r.isEnabled() && r.isDefaultAction()) { .filter(RequiredActionProviderModel::isEnabled)
userModel.addRequiredAction(r.getAlias()); .filter(RequiredActionProviderModel::isDefaultAction)
} .map(RequiredActionProviderModel::getAlias)
} .findFirst();
if (requiredAction.isPresent())
userModel.addRequiredAction(requiredAction.get());
} }
return userModel; return userModel;

View file

@ -33,10 +33,10 @@ import javax.persistence.LockModeType;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import java.util.*; import java.util.*;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import static org.keycloak.utils.StreamsUtil.closing;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -701,19 +701,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override @Override
public List<RequiredCredentialModel> getRequiredCredentials() { public Stream<RequiredCredentialModel> getRequiredCredentialsStream() {
Collection<RequiredCredentialEntity> entities = realm.getRequiredCredentials(); return realm.getRequiredCredentials().stream().map(this::toRequiredCredentialModel);
if (entities == null) return Collections.EMPTY_LIST;
List<RequiredCredentialModel> requiredCredentialModels = new LinkedList<>();
for (RequiredCredentialEntity entity : entities) {
RequiredCredentialModel model = new RequiredCredentialModel();
model.setFormLabel(entity.getFormLabel());
model.setType(entity.getType());
model.setSecret(entity.isSecret());
model.setInput(entity.isInput());
requiredCredentialModels.add(model);
}
return Collections.unmodifiableList(requiredCredentialModels);
} }
@ -1179,12 +1168,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public Set<String> getEventsListeners() { public Stream<String> getEventsListenersStream() {
Set<String> eventsListeners = realm.getEventsListeners(); return realm.getEventsListeners().stream();
if (eventsListeners.isEmpty()) return Collections.EMPTY_SET;
Set<String> copy = new HashSet<>();
copy.addAll(eventsListeners);
return Collections.unmodifiableSet(copy);
} }
@Override @Override
@ -1194,12 +1179,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public Set<String> getEnabledEventTypes() { public Stream<String> getEnabledEventTypesStream() {
Set<String> enabledEventTypes = realm.getEnabledEventTypes(); return realm.getEnabledEventTypes().stream();
if (enabledEventTypes.isEmpty()) return Collections.EMPTY_SET;
Set<String> copy = new HashSet<>();
copy.addAll(enabledEventTypes);
return Collections.unmodifiableSet(copy);
} }
@Override @Override
@ -1250,18 +1231,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<IdentityProviderModel> getIdentityProviders() { public Stream<IdentityProviderModel> getIdentityProvidersStream() {
List<IdentityProviderEntity> entities = realm.getIdentityProviders(); return realm.getIdentityProviders().stream().map(this::entityToModel);
if (entities.isEmpty()) return Collections.EMPTY_LIST;
List<IdentityProviderModel> identityProviders = new ArrayList<IdentityProviderModel>();
for (IdentityProviderEntity entity: entities) {
IdentityProviderModel identityProviderModel = entityToModel(entity);
identityProviders.add(identityProviderModel);
}
return Collections.unmodifiableList(identityProviders);
} }
private IdentityProviderModel entityToModel(IdentityProviderEntity entity) { private IdentityProviderModel entityToModel(IdentityProviderEntity entity) {
@ -1288,13 +1259,10 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override @Override
public IdentityProviderModel getIdentityProviderByAlias(String alias) { public IdentityProviderModel getIdentityProviderByAlias(String alias) {
for (IdentityProviderModel identityProviderModel : getIdentityProviders()) { return getIdentityProvidersStream()
if (identityProviderModel.getAlias().equals(alias)) { .filter(model -> Objects.equals(model.getAlias(), alias))
return identityProviderModel; .findFirst()
} .orElse(null);
}
return null;
} }
@Override @Override
@ -1414,12 +1382,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public Set<String> getSupportedLocales() { public Stream<String> getSupportedLocalesStream() {
Set<String> supportedLocales = realm.getSupportedLocales(); return realm.getSupportedLocales().stream();
if (supportedLocales == null || supportedLocales.isEmpty()) return Collections.EMPTY_SET;
Set<String> copy = new HashSet<>();
copy.addAll(supportedLocales);
return Collections.unmodifiableSet(copy);
} }
@Override @Override
@ -1440,28 +1404,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public Set<IdentityProviderMapperModel> getIdentityProviderMappers() { public Stream<IdentityProviderMapperModel> getIdentityProviderMappersStream() {
Collection<IdentityProviderMapperEntity> entities = this.realm.getIdentityProviderMappers(); return realm.getIdentityProviderMappers().stream().map(this::entityToModel);
if (entities.isEmpty()) return Collections.EMPTY_SET;
Set<IdentityProviderMapperModel> mappings = new HashSet<IdentityProviderMapperModel>();
for (IdentityProviderMapperEntity entity : entities) {
IdentityProviderMapperModel mapping = entityToModel(entity);
mappings.add(mapping);
}
return Collections.unmodifiableSet(mappings);
} }
@Override @Override
public Set<IdentityProviderMapperModel> getIdentityProviderMappersByAlias(String brokerAlias) { public Stream<IdentityProviderMapperModel> getIdentityProviderMappersByAliasStream(String brokerAlias) {
Set<IdentityProviderMapperModel> mappings = new HashSet<IdentityProviderMapperModel>(); return realm.getIdentityProviderMappers().stream()
for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { .filter(e -> Objects.equals(e.getIdentityProviderAlias(), brokerAlias))
if (!entity.getIdentityProviderAlias().equals(brokerAlias)) { .map(this::entityToModel);
continue;
}
IdentityProviderMapperModel mapping = entityToModel(entity);
mappings.add(mapping);
}
return mappings;
} }
@Override @Override
@ -1630,31 +1581,24 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<AuthenticationFlowModel> getAuthenticationFlows() { public Stream<AuthenticationFlowModel> getAuthenticationFlowsStream() {
return realm.getAuthenticationFlows().stream() return realm.getAuthenticationFlows().stream().map(this::entityToModel);
.map(this::entityToModel)
.collect(Collectors.collectingAndThen(
Collectors.toList(), Collections::unmodifiableList));
} }
@Override @Override
public AuthenticationFlowModel getFlowByAlias(String alias) { public AuthenticationFlowModel getFlowByAlias(String alias) {
for (AuthenticationFlowModel flow : getAuthenticationFlows()) { return getAuthenticationFlowsStream()
if (flow.getAlias().equals(alias)) { .filter(flow -> Objects.equals(flow.getAlias(), alias))
return flow; .findFirst()
} .orElse(null);
}
return null;
} }
@Override @Override
public AuthenticatorConfigModel getAuthenticatorConfigByAlias(String alias) { public AuthenticatorConfigModel getAuthenticatorConfigByAlias(String alias) {
for (AuthenticatorConfigModel config : getAuthenticatorConfigs()) { return getAuthenticatorConfigsStream()
if (config.getAlias().equals(alias)) { .filter(config -> Objects.equals(config.getAlias(), alias))
return config; .findFirst()
} .orElse(null);
}
return null;
} }
protected AuthenticationFlowModel entityToModel(AuthenticationFlowEntity entity) { protected AuthenticationFlowModel entityToModel(AuthenticationFlowEntity entity) {
@ -1725,15 +1669,13 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) { public Stream<AuthenticationExecutionModel> getAuthenticationExecutionsStream(String flowId) {
AuthenticationFlowEntity flow = em.getReference(AuthenticationFlowEntity.class, flowId); AuthenticationFlowEntity flow = em.getReference(AuthenticationFlowEntity.class, flowId);
return flow.getExecutions().stream() return flow.getExecutions().stream()
.filter(e -> getId().equals(e.getRealm().getId())) .filter(e -> getId().equals(e.getRealm().getId()))
.map(this::entityToModel) .map(this::entityToModel)
.sorted(AuthenticationExecutionModel.ExecutionComparator.SINGLETON) .sorted(AuthenticationExecutionModel.ExecutionComparator.SINGLETON);
.collect(Collectors.collectingAndThen(
Collectors.toList(), Collections::unmodifiableList));
} }
public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) { public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) {
@ -1889,14 +1831,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<AuthenticatorConfigModel> getAuthenticatorConfigs() { public Stream<AuthenticatorConfigModel> getAuthenticatorConfigsStream() {
Collection<AuthenticatorConfigEntity> entities = realm.getAuthenticatorConfigs(); return realm.getAuthenticatorConfigs().stream().map(this::entityToModel);
if (entities.isEmpty()) return Collections.EMPTY_LIST;
List<AuthenticatorConfigModel> authenticators = new LinkedList<>();
for (AuthenticatorConfigEntity entity : entities) {
authenticators.add(entityToModel(entity));
}
return Collections.unmodifiableList(authenticators);
} }
@Override @Override
@ -1973,15 +1909,10 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<RequiredActionProviderModel> getRequiredActionProviders() { public Stream<RequiredActionProviderModel> getRequiredActionProvidersStream() {
Collection<RequiredActionProviderEntity> entities = realm.getRequiredActionProviders(); return realm.getRequiredActionProviders().stream()
if (entities.isEmpty()) return Collections.EMPTY_LIST; .map(this::entityToModel)
List<RequiredActionProviderModel> actions = new LinkedList<>(); .sorted(RequiredActionProviderModel.RequiredActionComparator.SINGLETON);
for (RequiredActionProviderEntity entity : entities) {
actions.add(entityToModel(entity));
}
Collections.sort(actions, RequiredActionProviderModel.RequiredActionComparator.SINGLETON);
return Collections.unmodifiableList(actions);
} }
private RequiredActionProviderEntity getRequiredProviderEntity(String id, boolean readForRemove) { private RequiredActionProviderEntity getRequiredProviderEntity(String id, boolean readForRemove) {
@ -1995,10 +1926,10 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override @Override
public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) { public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) {
for (RequiredActionProviderModel action : getRequiredActionProviders()) { return getRequiredActionProvidersStream()
if (action.getAlias().equals(alias)) return action; .filter(action -> Objects.equals(action.getAlias(), alias))
} .findFirst()
return null; .orElse(null);
} }
@Override @Override
@ -2052,14 +1983,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<ClientScopeModel> getClientScopes() { public Stream<ClientScopeModel> getClientScopesStream() {
Collection<ClientScopeEntity> entities = realm.getClientScopes(); return realm.getClientScopes().stream().map(ClientScopeEntity::getId).map(this::getClientScopeById);
if (entities == null || entities.isEmpty()) return Collections.EMPTY_LIST;
List<ClientScopeModel> list = new LinkedList<>();
for (ClientScopeEntity entity : entities) {
list.add(session.realms().getClientScopeById(entity.getId(), this));
}
return Collections.unmodifiableList(list);
} }
@Override @Override
@ -2142,19 +2067,11 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<ClientScopeModel> getDefaultClientScopes(boolean defaultScope) { public Stream<ClientScopeModel> getDefaultClientScopesStream(boolean defaultScope) {
TypedQuery<String> query = em.createNamedQuery("defaultClientScopeRealmMappingIdsByRealm", String.class); TypedQuery<String> query = em.createNamedQuery("defaultClientScopeRealmMappingIdsByRealm", String.class);
query.setParameter("realm", getEntity()); query.setParameter("realm", getEntity());
query.setParameter("defaultScope", defaultScope); query.setParameter("defaultScope", defaultScope);
List<String> ids = query.getResultList(); return closing(query.getResultStream().map(this::getClientScopeById).filter(Objects::nonNull));
List<ClientScopeModel> clientScopes = new LinkedList<>();
for (String clientScopeId : ids) {
ClientScopeModel clientScope = getClientScopeById(clientScopeId);
if (clientScope == null) continue;
clientScopes.add(clientScope);
}
return clientScopes;
} }
@Override @Override
@ -2273,23 +2190,22 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
} }
@Override @Override
public List<ComponentModel> getComponents(String parentId, final String providerType) { public Stream<ComponentModel> getComponentsStream(String parentId, final String providerType) {
if (parentId == null) parentId = getId(); if (parentId == null) parentId = getId();
final String parent = parentId; final String parent = parentId;
return realm.getComponents().stream() Stream<ComponentEntity> componentStream = realm.getComponents().stream()
.filter(c -> parent.equals(c.getParentId()) .filter(c -> Objects.equals(parent, c.getParentId()));
&& providerType.equals(c.getProviderType()))
.map(this::entityToModel) if (providerType != null) {
.collect(Collectors.toList()); componentStream = componentStream.filter(c -> Objects.equals(providerType, c.getProviderType()));
}
return componentStream.map(this::entityToModel);
} }
@Override @Override
public List<ComponentModel> getComponents(final String parentId) { public Stream<ComponentModel> getComponentsStream(final String parentId) {
return realm.getComponents().stream() return getComponentsStream(parentId, null);
.filter(c -> parentId.equals(c.getParentId()))
.map(this::entityToModel)
.collect(Collectors.toList());
} }
protected ComponentModel entityToModel(ComponentEntity c) { protected ComponentModel entityToModel(ComponentEntity c) {
@ -2308,9 +2224,18 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
return model; return model;
} }
private RequiredCredentialModel toRequiredCredentialModel(RequiredCredentialEntity entity) {
RequiredCredentialModel model = new RequiredCredentialModel();
model.setFormLabel(entity.getFormLabel());
model.setType(entity.getType());
model.setSecret(entity.isSecret());
model.setInput(entity.isInput());
return model;
}
@Override @Override
public List<ComponentModel> getComponents() { public Stream<ComponentModel> getComponentsStream() {
return realm.getComponents().stream().map(this::entityToModel).collect(Collectors.toList()); return realm.getComponents().stream().map(this::entityToModel);
} }
@Override @Override

View file

@ -27,9 +27,10 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -57,17 +58,19 @@ public class EventBuilder {
} }
} }
if (realm.getEventsListeners() != null && !realm.getEventsListeners().isEmpty()) {
this.listeners = new LinkedList<>(); this.listeners = realm.getEventsListenersStream()
for (String id : realm.getEventsListeners()) { .map(id -> {
EventListenerProvider listener = session.getProvider(EventListenerProvider.class, id); EventListenerProvider listener = session.getProvider(EventListenerProvider.class, id);
if (listener != null) { if (listener != null) {
listeners.add(listener); return listener;
} else { } else {
log.error("Event listener '" + id + "' registered, but provider not found"); log.error("Event listener '" + id + "' registered, but provider not found");
} return null;
} }
} })
.filter(Objects::nonNull)
.collect(Collectors.toList());
realm(realm); realm(realm);
ipAddress(clientConnection.getRemoteAddr()); ipAddress(clientConnection.getRemoteAddr());
@ -177,7 +180,8 @@ public class EventBuilder {
event.setTime(Time.currentTimeMillis()); event.setTime(Time.currentTimeMillis());
if (store != null) { if (store != null) {
if (realm.getEnabledEventTypes() != null && !realm.getEnabledEventTypes().isEmpty() ? realm.getEnabledEventTypes().contains(event.getType().name()) : event.getType().isSaveByDefault()) { Set<String> eventTypes = realm.getEnabledEventTypesStream().collect(Collectors.toSet());
if (!eventTypes.isEmpty() ? eventTypes.contains(event.getType().name()) : event.getType().isSaveByDefault()) {
try { try {
store.onEvent(event); store.onEvent(event);
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -19,6 +19,8 @@ package org.keycloak.events;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -43,6 +45,17 @@ public interface EventQuery {
EventQuery maxResults(int results); EventQuery maxResults(int results);
List<Event> getResultList(); /**
* @deprecated Use {@link #getResultStream() getResultStream} instead.
*/
@Deprecated
default List<Event> getResultList() {
return getResultStream().collect(Collectors.toList());
}
/**
* Returns requested results that match given criteria as a stream.
* @return Stream of events
*/
Stream<Event> getResultStream();
} }

View file

@ -19,6 +19,8 @@ package org.keycloak.events.admin;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -127,8 +129,16 @@ public interface AdminEventQuery {
/** /**
* Executes the query and returns the results * Executes the query and returns the results
* * @deprecated Use {@link #getResultStream() getResultStream} instead.
* @return
*/ */
List<AdminEvent> getResultList(); @Deprecated
default List<AdminEvent> getResultList() {
return getResultStream().collect(Collectors.toList());
}
/**
* Executes the query and returns the results as a stream.
* @return Stream of admin events
*/
Stream<AdminEvent> getResultStream();
} }

View file

@ -26,8 +26,6 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List;
/** /**
* @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 $
@ -68,12 +66,10 @@ public class MigrateTo1_2_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(realm -> {
for (RealmModel realm : realms) {
setupBrokerService(realm); setupBrokerService(realm);
setupClientNames(realm); setupClientNames(realm);
} });
} }
@Override @Override

View file

@ -19,7 +19,6 @@ package org.keycloak.migration.migrators;
import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentFactory; import org.keycloak.component.ComponentFactory;
import org.keycloak.component.ComponentModel;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
@ -44,11 +43,7 @@ public class MigrateTo1_3_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(realm -> migrateLDAPProviders(session, realm));
for (RealmModel realm : realms) {
migrateLDAPProviders(session, realm);
}
} }
@Override @Override
@ -57,9 +52,7 @@ public class MigrateTo1_3_0 implements Migration {
} }
private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) { private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) {
List<UserStorageProviderModel> federationProviders = realm.getUserStorageProviders(); realm.getUserStorageProvidersStream().forEachOrdered(fedProvider -> {
for (UserStorageProviderModel fedProvider : federationProviders) {
if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) { if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) {
fedProvider = new UserStorageProviderModel(fedProvider); // copy don't want to muck with cache fedProvider = new UserStorageProviderModel(fedProvider); // copy don't want to muck with cache
MultivaluedHashMap<String, String> config = fedProvider.getConfig(); MultivaluedHashMap<String, String> config = fedProvider.getConfig();
@ -91,14 +84,13 @@ public class MigrateTo1_3_0 implements Migration {
realm.updateComponent(fedProvider); realm.updateComponent(fedProvider);
// Create default mappers for LDAP // Create default mappers for LDAP
List<ComponentModel> mappers = realm.getComponents(fedProvider.getId()); if (realm.getComponentsStream(fedProvider.getId()).count() == 0) {
if (mappers.isEmpty()) {
ProviderFactory ldapFactory = session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, LDAPConstants.LDAP_PROVIDER); ProviderFactory ldapFactory = session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, LDAPConstants.LDAP_PROVIDER);
if (ldapFactory != null) { if (ldapFactory != null) {
((ComponentFactory) ldapFactory).onCreate(session, realm, fedProvider); ((ComponentFactory) ldapFactory).onCreate(session, realm, fedProvider);
} }
} }
} }
} });
} }
} }

View file

@ -29,10 +29,10 @@ import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.models.utils.DefaultRequiredActions; import org.keycloak.models.utils.DefaultRequiredActions;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.storage.UserStorageProviderModel;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -45,15 +45,11 @@ public class MigrateTo1_4_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm));
for (RealmModel realm : realms) {
migrateRealm(session, realm);
}
} }
protected void migrateRealm(KeycloakSession session, RealmModel realm) { protected void migrateRealm(KeycloakSession session, RealmModel realm) {
if (realm.getAuthenticationFlows().size() == 0) { if (realm.getAuthenticationFlowsStream().count() == 0) {
DefaultAuthenticationFlows.migrateFlows(realm); DefaultAuthenticationFlows.migrateFlows(realm);
DefaultRequiredActions.addActions(realm); DefaultRequiredActions.addActions(realm);
} }
@ -71,19 +67,15 @@ public class MigrateTo1_4_0 implements Migration {
private void migrateLDAPMappers(KeycloakSession session, RealmModel realm) { private void migrateLDAPMappers(KeycloakSession session, RealmModel realm) {
List<String> mandatoryInLdap = Arrays.asList("username", "username-cn", "first name", "last name"); List<String> mandatoryInLdap = Arrays.asList("username", "username-cn", "first name", "last name");
for (UserStorageProviderModel providerModel : realm.getUserStorageProviders()) { realm.getUserStorageProvidersStream()
if (providerModel.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) { .filter(providerModel -> Objects.equals(providerModel.getProviderId(), LDAPConstants.LDAP_PROVIDER))
List<ComponentModel> mappers = realm.getComponents(providerModel.getId()); .forEachOrdered(providerModel -> realm.getComponentsStream(providerModel.getId())
for (ComponentModel mapper : mappers) { .filter(mapper -> mandatoryInLdap.contains(mapper.getName()))
if (mandatoryInLdap.contains(mapper.getName())) { .forEach(mapper -> {
mapper = new ComponentModel(mapper); // don't want to modify cache mapper = new ComponentModel(mapper); // don't want to modify cache
mapper.getConfig().putSingle("is.mandatory.in.ldap", "true"); mapper.getConfig().putSingle("is.mandatory.in.ldap", "true");
realm.updateComponent(mapper); realm.updateComponent(mapper);
} }));
}
}
}
} }
private void migrateUsers(KeycloakSession session, RealmModel realm) { private void migrateUsers(KeycloakSession session, RealmModel realm) {

View file

@ -25,8 +25,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List;
/** /**
* @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 $
@ -39,11 +37,7 @@ public class MigrateTo1_5_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm));
for (RealmModel realm : realms) {
migrateRealm(session, realm);
}
} }
@Override @Override

View file

@ -29,8 +29,6 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -51,10 +49,7 @@ public class MigrateTo1_6_0 implements Migration {
throw new RuntimeException("Can't find default locale mapper"); throw new RuntimeException("Can't find default locale mapper");
} }
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, localeMapper, realm));
for (RealmModel realm : realms) {
migrateRealm(session, localeMapper, realm);
}
} }
@Override @Override

View file

@ -21,14 +21,11 @@ import org.keycloak.migration.MigrationProvider;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -41,11 +38,7 @@ public class MigrateTo1_7_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm));
for (RealmModel realm : realms) {
migrateRealm(session, realm);
}
} }
@Override @Override
@ -65,12 +58,11 @@ public class MigrateTo1_7_0 implements Migration {
DefaultAuthenticationFlows.migrateFlows(realm); DefaultAuthenticationFlows.migrateFlows(realm);
AuthenticationFlowModel firstBrokerLoginFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW); AuthenticationFlowModel firstBrokerLoginFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW);
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders(); realm.getIdentityProvidersStream()
for (IdentityProviderModel identityProvider : identityProviders) { .filter(provider -> provider.getFirstBrokerLoginFlowId() == null)
if (identityProvider.getFirstBrokerLoginFlowId() == null) { .forEach(provider -> {
identityProvider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId()); provider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId());
realm.updateIdentityProvider(identityProvider); realm.updateIdentityProvider(provider);
} });
}
} }
} }

View file

@ -26,7 +26,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.UserStorageProviderModel;
import java.util.List; import java.util.Objects;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -41,12 +41,7 @@ public class MigrateTo1_8_0 implements Migration {
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); session.realms().getRealmsStream().forEach(this::migrateRealm);
for (RealmModel realm : realms) {
migrateRealm(realm);
}
} }
@Override @Override
@ -55,30 +50,22 @@ public class MigrateTo1_8_0 implements Migration {
} }
protected void migrateRealm(RealmModel realm) { protected void migrateRealm(RealmModel realm) {
List<UserStorageProviderModel> federationProviders = realm.getUserStorageProviders(); realm.getUserStorageProvidersStream()
for (UserStorageProviderModel fedProvider : federationProviders) { .filter(fedProvider -> Objects.equals(fedProvider.getProviderId(), LDAPConstants.LDAP_PROVIDER))
.filter(this::isActiveDirectory)
if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) { .filter(fedProvider -> Objects.isNull(getMapperByName(realm, fedProvider, "MSAD account controls")))
// Create mapper for MSAD account controls
if (isActiveDirectory(fedProvider)) { .map(fedProvider -> KeycloakModelUtils.createComponentModel("MSAD account controls",
// Create mapper for MSAD account controls fedProvider.getId(), LDAPConstants.MSAD_USER_ACCOUNT_CONTROL_MAPPER,
if (getMapperByName(realm, fedProvider, "MSAD account controls") == null) { "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"))
ComponentModel mapperModel = KeycloakModelUtils.createComponentModel("MSAD account controls", fedProvider.getId(), LDAPConstants.MSAD_USER_ACCOUNT_CONTROL_MAPPER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"); .forEachOrdered(realm::addComponentModel);
realm.addComponentModel(mapperModel);
}
}
}
}
} }
public static ComponentModel getMapperByName(RealmModel realm, ComponentModel providerModel, String name) { public static ComponentModel getMapperByName(RealmModel realm, ComponentModel providerModel, String name) {
List<ComponentModel> components = realm.getComponents(providerModel.getId(), "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"); return realm.getComponentsStream(providerModel.getId(), "org.keycloak.storage.ldap.mappers.LDAPStorageMapper")
for (ComponentModel component : components) { .filter(component -> Objects.equals(component.getName(), name))
if (component.getName().equals(name)) { .findFirst()
return component; .orElse(null);
}
}
return null;
} }

View file

@ -35,9 +35,7 @@ public class MigrateTo1_9_2 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(this::migrateRealm);
migrateRealm(realm);
}
} }
@Override @Override

View file

@ -33,9 +33,7 @@ public class MigrateTo2_0_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(this::migrateAuthorizationServices);
migrateAuthorizationServices(realm);
}
} }
@Override @Override

View file

@ -47,10 +47,10 @@ public class MigrateTo2_1_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(realm -> {
migrateDefaultRequiredAction(realm); migrateDefaultRequiredAction(realm);
migrateRolePolicies(realm, session); migrateRolePolicies(realm, session);
} });
} }
@Override @Override

View file

@ -35,9 +35,7 @@ public class MigrateTo2_2_0 implements Migration {
} }
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(this::addIdentityProviderAuthenticator);
addIdentityProviderAuthenticator(realm);
}
} }
@Override @Override
@ -47,13 +45,12 @@ public class MigrateTo2_2_0 implements Migration {
} }
private void addIdentityProviderAuthenticator(RealmModel realm) { private void addIdentityProviderAuthenticator(RealmModel realm) {
String defaultProvider = null; String defaultProvider = realm.getIdentityProvidersStream()
for (IdentityProviderModel provider : realm.getIdentityProviders()) { .filter(IdentityProviderModel::isEnabled)
if (provider.isEnabled() && provider.isAuthenticateByDefault()) { .filter(IdentityProviderModel::isAuthenticateByDefault)
defaultProvider = provider.getAlias(); .map(IdentityProviderModel::getAlias)
break; .findFirst()
} .orElse(null);
}
DefaultAuthenticationFlows.addIdentityProviderAuthenticator(realm, defaultProvider); DefaultAuthenticationFlows.addIdentityProviderAuthenticator(realm, defaultProvider);
} }

View file

@ -19,7 +19,6 @@ package org.keycloak.migration.migrators;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -33,17 +32,13 @@ public class MigrateTo2_3_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(this::migrateRealm);
migrateRealm(realm);
}
} }
protected void migrateRealm(RealmModel realm) { protected void migrateRealm(RealmModel realm) {
realm.getClientsStream().forEach(MigrationUtils::updateProtocolMappers); realm.getClientsStream().forEach(MigrationUtils::updateProtocolMappers);
for (ClientScopeModel clientScope : realm.getClientScopes()) { realm.getClientScopesStream().forEach(MigrationUtils::updateProtocolMappers);
MigrationUtils.updateProtocolMappers(clientScope);
}
} }
@Override @Override

View file

@ -33,9 +33,7 @@ public class MigrateTo2_5_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach( session.realms().getRealmsStream().forEach(DefaultKeyProviders::createSecretProvider);
r -> DefaultKeyProviders.createSecretProvider(r)
);
} }
@Override @Override

View file

@ -41,12 +41,7 @@ public class MigrateTo3_0_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(this::migrateRealm);
migrateRealm(realm);
}
} }
@Override @Override

View file

@ -36,9 +36,7 @@ public class MigrateTo3_1_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(this::migrateRealm);
migrateRealm(realm);
}
} }
protected void migrateRealm(RealmModel realm) { protected void migrateRealm(RealmModel realm) {

View file

@ -33,10 +33,7 @@ public class MigrateTo3_2_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm));
migrateRealm(session, realm);
}
} }
@Override @Override

View file

@ -17,7 +17,6 @@
package org.keycloak.migration.migrators; package org.keycloak.migration.migrators;
import org.keycloak.keys.KeyProvider;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -37,11 +36,7 @@ public class MigrateTo3_4_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach( session.realms().getRealmsStream().forEach(this::migrateRealm);
r -> {
migrateRealm(r);
}
);
} }
@Override @Override

View file

@ -37,11 +37,7 @@ public class MigrateTo3_4_1 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach( session.realms().getRealmsStream().forEach(this::migrateRealm);
r -> {
migrateRealm(r);
}
);
} }
@Override @Override

View file

@ -36,11 +36,7 @@ public class MigrateTo3_4_2 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach( session.realms().getRealmsStream().forEach(this::migrateRealm);
r -> {
migrateRealm(r);
}
);
} }
@Override @Override

View file

@ -18,10 +18,10 @@
package org.keycloak.migration.migrators; package org.keycloak.migration.migrators;
import java.util.List; import java.util.List;
import java.util.Objects;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.component.ComponentModel;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
@ -48,11 +48,7 @@ public class MigrateTo4_0_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach( session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm, false));
r -> {
migrateRealm(session, r, false);
}
);
} }
@Override @Override
@ -63,13 +59,14 @@ public class MigrateTo4_0_0 implements Migration {
protected void migrateRealm(KeycloakSession session, RealmModel realm, boolean json) { protected void migrateRealm(KeycloakSession session, RealmModel realm, boolean json) {
// Upgrade names of clientScopes to not contain space // Upgrade names of clientScopes to not contain space
for (ClientScopeModel clientScope : realm.getClientScopes()) { realm.getClientScopesStream()
if (clientScope.getName().contains(" ")) { .filter(clientScope -> clientScope.getName().contains(" "))
LOG.debugf("Replacing spaces with underscores in the name of client scope '%s' of realm '%s'", clientScope.getName(), realm.getName()); .forEach(clientScope -> {
String replacedName = clientScope.getName().replaceAll(" ", "_"); LOG.debugf("Replacing spaces with underscores in the name of client scope '%s' of realm '%s'",
clientScope.setName(replacedName); clientScope.getName(), realm.getName());
} String replacedName = clientScope.getName().replaceAll(" ", "_");
} clientScope.setName(replacedName);
});
if (!json) { if (!json) {
// Add default client scopes. But don't add them to existing clients. For JSON, they were already added // Add default client scopes. But don't add them to existing clients. For JSON, they were already added
@ -78,17 +75,17 @@ public class MigrateTo4_0_0 implements Migration {
} }
// Upgrade configuration of "allowed-client-templates" client registration policy // Upgrade configuration of "allowed-client-templates" client registration policy
for (ComponentModel component : realm.getComponents(realm.getId(), "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy")) { realm.getComponentsStream(realm.getId(), "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy")
if ("allowed-client-templates".equals(component.getProviderId())) { .filter(component -> Objects.equals(component.getProviderId(), "allowed-client-templates"))
List<String> configVal = component.getConfig().remove("allowed-client-templates"); .forEach(component -> {
if (configVal != null) { List<String> configVal = component.getConfig().remove("allowed-client-templates");
component.getConfig().put("allowed-client-scopes", configVal); if (configVal != null) {
} component.getConfig().put("allowed-client-scopes", configVal);
component.put("allow-default-scopes", true); }
component.put("allow-default-scopes", true);
realm.updateComponent(component); realm.updateComponent(component);
} });
}
// If client has scope for offline_access role (either directly or through fullScopeAllowed), then add offline_access client // If client has scope for offline_access role (either directly or through fullScopeAllowed), then add offline_access client

View file

@ -19,8 +19,7 @@ package org.keycloak.migration.migrators;
import static java.util.Comparator.comparing; import static java.util.Comparator.comparing;
import java.util.List; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
@ -45,29 +44,27 @@ public class MigrateTo4_2_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach(r -> { session.realms().getRealmsStream().forEach(this::migrateRealm);
migrateRealm(session, r, false);
});
} }
@Override @Override
public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
migrateRealm(session, realm, true); migrateRealm(realm);
} }
protected void migrateRealm(KeycloakSession session, RealmModel realm, boolean json) { protected void migrateRealm(RealmModel realm) {
// Set default priority of required actions in alphabetical order // Set default priority of required actions in alphabetical order
List<RequiredActionProviderModel> actions = realm.getRequiredActionProviders().stream() AtomicInteger priority = new AtomicInteger(10);
.sorted(comparing(RequiredActionProviderModel::getName)).collect(Collectors.toList()); realm.getRequiredActionProvidersStream()
int priority = 10; .sorted(comparing(RequiredActionProviderModel::getName))
for (RequiredActionProviderModel model : actions) { .forEachOrdered(model -> {
LOG.debugf("Setting priority '%d' for required action '%s' in realm '%s'", priority, model.getAlias(), LOG.debugf("Setting priority '%d' for required action '%s' in realm '%s'", priority.get(), model.getAlias(),
realm.getName()); realm.getName());
model.setPriority(priority); model.setPriority(priority.get());
priority += 10; priority.addAndGet(10);
// Save // Save
realm.updateRequiredActionProvider(model); realm.updateRequiredActionProvider(model);
} });
} }
} }

View file

@ -42,9 +42,7 @@ public class MigrateTo4_6_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach(r -> { session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm, false));
migrateRealm(session, r, false);
});
} }
@Override @Override

View file

@ -43,9 +43,7 @@ public class MigrateTo6_0_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach(r -> { session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm, false));
migrateRealm(session, r, false);
});
} }
@Override @Override

View file

@ -46,11 +46,9 @@ public class MigrateTo8_0_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
// Perform basic realm migration first (non multi-factor authentication) // Perform basic realm migration first (non multi-factor authentication)
session.realms().getRealms().stream().forEach(realm -> migrateRealmCommon(realm)); session.realms().getRealmsStream().forEach(this::migrateRealmCommon);
// Moreover, for multi-factor authentication migrate optional execution of realm flows to subflows // Moreover, for multi-factor authentication migrate optional execution of realm flows to subflows
session.realms().getRealms().stream().forEach(r -> { session.realms().getRealmsStream().forEach(realm -> migrateRealmMFA(realm));
migrateRealmMFA(session, r, false);
});
} }
@Override @Override
@ -79,15 +77,12 @@ public class MigrateTo8_0_0 implements Migration {
} }
} }
protected void migrateRealmMFA(KeycloakSession session, RealmModel realm, boolean jsn) { protected void migrateRealmMFA(RealmModel realm) {
for (AuthenticationFlowModel authFlow : realm.getAuthenticationFlows()) { realm.getAuthenticationFlowsStream()
for (AuthenticationExecutionModel authExecution : realm.getAuthenticationExecutions(authFlow.getId())) { .forEach(authFlow ->
// Those were OPTIONAL executions in previous version realm.getAuthenticationExecutionsStream(authFlow.getId())
if (authExecution.getRequirement() == AuthenticationExecutionModel.Requirement.CONDITIONAL) { .filter(exe -> exe.getRequirement() == AuthenticationExecutionModel.Requirement.CONDITIONAL)
migrateOptionalAuthenticationExecution(realm, authFlow, authExecution, true); .forEachOrdered(exe -> migrateOptionalAuthenticationExecution(realm, authFlow, exe, true)));
}
}
}
} }
public static void migrateOptionalAuthenticationExecution(RealmModel realm, AuthenticationFlowModel parentFlow, AuthenticationExecutionModel optionalExecution, boolean updateOptionalExecution) { public static void migrateOptionalAuthenticationExecution(RealmModel realm, AuthenticationFlowModel parentFlow, AuthenticationExecutionModel optionalExecution, boolean updateOptionalExecution) {

View file

@ -19,6 +19,10 @@
package org.keycloak.migration.migrators; package org.keycloak.migration.migrators;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
@ -28,6 +32,8 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import static org.keycloak.models.AuthenticationExecutionModel.Requirement.*;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -44,7 +50,7 @@ public class MigrateTo8_0_2 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().forEach(this::migrateAuthenticationFlowsWithAlternativeRequirements); session.realms().getRealmsStream().forEach(this::migrateAuthenticationFlowsWithAlternativeRequirements);
} }
@Override @Override
@ -54,47 +60,39 @@ public class MigrateTo8_0_2 implements Migration {
protected void migrateAuthenticationFlowsWithAlternativeRequirements(RealmModel realm) { protected void migrateAuthenticationFlowsWithAlternativeRequirements(RealmModel realm) {
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) { for (AuthenticationFlowModel flow : realm.getAuthenticationFlowsStream().collect(Collectors.toList())) {
List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutionsStream(flow.getId())
.collect(Collectors.toList());
boolean alternativeFound = false; Set<AuthenticationExecutionModel.Requirement> requirements = executions.stream()
boolean requiredFound = false; .map(AuthenticationExecutionModel::getRequirement)
for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(flow.getId())) { .collect(Collectors.toSet());
switch (execution.getRequirement()) {
case REQUIRED:
case CONDITIONAL:
requiredFound = true;
break;
case ALTERNATIVE:
alternativeFound = true;
break;
}
}
// This flow contains some REQUIRED and ALTERNATIVE at the same level. We will migrate ALTERNATIVES to separate subflows // This flow contains some REQUIRED and ALTERNATIVE at the same level. We will migrate ALTERNATIVES to separate subflows
// to try to preserve same behaviour as in previous versions // to try to preserve same behaviour as in previous versions
if (requiredFound && alternativeFound) { if (requirements.contains(REQUIRED) || requirements.contains(CONDITIONAL) && requirements.contains(ALTERNATIVE)) {
// Suffix used just to avoid name conflicts // Suffix used just to avoid name conflicts
int suffix = 0; AtomicInteger suffix = new AtomicInteger(0);
LinkedList<AuthenticationExecutionModel> alternativesToMigrate = new LinkedList<>(); LinkedList<AuthenticationExecutionModel> alternativesToMigrate = new LinkedList<>();
for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(flow.getId())) { for (AuthenticationExecutionModel execution: executions) {
if (AuthenticationExecutionModel.Requirement.ALTERNATIVE.equals(execution.getRequirement())) { if (AuthenticationExecutionModel.Requirement.ALTERNATIVE.equals(execution.getRequirement())) {
alternativesToMigrate.add(execution); alternativesToMigrate.add(execution);
} }
// If we have some REQUIRED then ALTERNATIVE and then REQUIRED/CONDITIONAL, we migrate the alternatives to the new subflow. // If we have some REQUIRED then ALTERNATIVE and then REQUIRED/CONDITIONAL, we migrate the alternatives to the new subflow.
if (AuthenticationExecutionModel.Requirement.REQUIRED.equals(execution.getRequirement()) || if (REQUIRED.equals(execution.getRequirement()) ||
AuthenticationExecutionModel.Requirement.CONDITIONAL.equals(execution.getRequirement())) { CONDITIONAL.equals(execution.getRequirement())) {
if (!alternativesToMigrate.isEmpty()) { if (!alternativesToMigrate.isEmpty()) {
migrateAlternatives(realm, flow, alternativesToMigrate, suffix); migrateAlternatives(realm, flow, alternativesToMigrate, suffix.get());
suffix += 1; suffix.addAndGet(1);
alternativesToMigrate.clear(); alternativesToMigrate.clear();
} }
} }
} }
if (!alternativesToMigrate.isEmpty()) { if (!alternativesToMigrate.isEmpty()) {
migrateAlternatives(realm, flow, alternativesToMigrate, suffix); migrateAlternatives(realm, flow, alternativesToMigrate, suffix.get());
} }
} }
} }
@ -116,7 +114,7 @@ public class MigrateTo8_0_2 implements Migration {
AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
execution.setParentFlow(parentFlow.getId()); execution.setParentFlow(parentFlow.getId());
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setRequirement(REQUIRED);
execution.setFlowId(newFlow.getId()); execution.setFlowId(newFlow.getId());
// Use same priority as the first ALTERNATIVE as new execution will defacto replace it in the parent flow // Use same priority as the first ALTERNATIVE as new execution will defacto replace it in the parent flow
execution.setPriority(alternativesToMigrate.getFirst().getPriority()); execution.setPriority(alternativesToMigrate.getFirst().getPriority());

View file

@ -47,7 +47,7 @@ public class MigrateTo9_0_0 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach(realm -> migrateRealmCommon(realm)); session.realms().getRealmsStream().forEach(this::migrateRealmCommon);
} }
@Override @Override

View file

@ -38,7 +38,7 @@ public class MigrateTo9_0_4 implements Migration {
@Override @Override
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
session.realms().getRealms().stream().forEach(this::checkAuthConfigNullAlias); session.realms().getRealmsStream().forEach(this::checkAuthConfigNullAlias);
} }
@Override @Override
@ -46,7 +46,7 @@ public class MigrateTo9_0_4 implements Migration {
} }
protected void checkAuthConfigNullAlias(RealmModel realm) { protected void checkAuthConfigNullAlias(RealmModel realm) {
realm.getAuthenticatorConfigs().stream() realm.getAuthenticatorConfigsStream()
.filter(this::hasNullAlias) .filter(this::hasNullAlias)
.forEach((config) -> this.setRandomAlias(realm, config)); .forEach((config) -> this.setRandomAlias(realm, config));
} }

View file

@ -24,10 +24,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation;
import java.util.HashMap; import java.util.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -150,13 +147,7 @@ public class DefaultAuthenticationFlows {
} }
private static boolean hasCredentialType(RealmModel realm, String type) { private static boolean hasCredentialType(RealmModel realm, String type) {
for (RequiredCredentialModel requiredCredentialModel : realm.getRequiredCredentials()) { return realm.getRequiredCredentialsStream().anyMatch(r -> Objects.equals(r.getType(), type));
if (type.equals(requiredCredentialModel.getType())) {
return true;
}
}
return false;
} }
public static void resetCredentialsFlow(RealmModel realm) { public static void resetCredentialsFlow(RealmModel realm) {
@ -388,20 +379,16 @@ public class DefaultAuthenticationFlows {
} }
public static void addIdentityProviderAuthenticator(RealmModel realm, String defaultProvider) { public static void addIdentityProviderAuthenticator(RealmModel realm, String defaultProvider) {
String browserFlowId = null; String browserFlowId = realm.getAuthenticationFlowsStream()
for (AuthenticationFlowModel f : realm.getAuthenticationFlows()) { .filter(f -> Objects.equals(f.getAlias(), DefaultAuthenticationFlows.BROWSER_FLOW))
if (f.getAlias().equals(DefaultAuthenticationFlows.BROWSER_FLOW)) { .map(AuthenticationFlowModel::getId)
browserFlowId = f.getId(); .findFirst()
break; .orElse(null);
}
}
if (browserFlowId != null) { if (browserFlowId != null) {
for (AuthenticationExecutionModel e : realm.getAuthenticationExecutions(browserFlowId)) { if (realm.getAuthenticationExecutionsStream(browserFlowId)
if ("identity-provider-redirector".equals(e.getAuthenticator())) { .anyMatch(e -> Objects.equals(e.getAuthenticator(), "identity-provider-redirector")))
return; return;
}
}
AuthenticationExecutionModel execution; AuthenticationExecutionModel execution;
execution = new AuthenticationExecutionModel(); execution = new AuthenticationExecutionModel();
@ -618,7 +605,8 @@ public class DefaultAuthenticationFlows {
KeycloakModelUtils.deepFindAuthenticationExecutions(realm, browserFlow, browserExecutions); KeycloakModelUtils.deepFindAuthenticationExecutions(realm, browserFlow, browserExecutions);
for (AuthenticationExecutionModel browserExecution : browserExecutions) { for (AuthenticationExecutionModel browserExecution : browserExecutions) {
if (browserExecution.isAuthenticatorFlow()){ if (browserExecution.isAuthenticatorFlow()){
if (realm.getAuthenticationExecutions(browserExecution.getFlowId()).stream().anyMatch(e -> e.getAuthenticator().equals("auth-otp-form"))){ if (realm.getAuthenticationExecutionsStream(browserExecution.getFlowId())
.anyMatch(e -> e.getAuthenticator().equals("auth-otp-form"))){
execution.setRequirement(browserExecution.getRequirement()); execution.setRequirement(browserExecution.getRequirement());
} }
} }

View file

@ -23,7 +23,7 @@ import org.keycloak.crypto.Algorithm;
import org.keycloak.keys.KeyProvider; import org.keycloak.keys.KeyProvider;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import java.util.List; import java.util.Objects;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -81,13 +81,8 @@ public class DefaultKeyProviders {
} }
protected static boolean hasProvider(RealmModel realm, String providerId) { protected static boolean hasProvider(RealmModel realm, String providerId) {
List<ComponentModel> currentComponents = realm.getComponents(realm.getId(), KeyProvider.class.getName()); return realm.getComponentsStream(realm.getId(), KeyProvider.class.getName())
for (ComponentModel current : currentComponents) { .anyMatch(component -> Objects.equals(component.getProviderId(), providerId));
if (current.getProviderId().equals(providerId)) {
return true;
}
}
return false;
} }
public static void createProviders(RealmModel realm, String privateKeyPem, String certificatePem) { public static void createProviders(RealmModel realm, String privateKeyPem, String certificatePem) {

View file

@ -35,7 +35,6 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask; import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.KeycloakTransaction; import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.ScopeContainerModel; import org.keycloak.models.ScopeContainerModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
@ -296,21 +295,17 @@ public final class KeycloakModelUtils {
return null; return null;
} }
for (UserStorageProviderModel fedProvider : realm.getUserStorageProviders()) { return realm.getUserStorageProvidersStream()
if (displayName.equals(fedProvider.getName())) { .filter(fedProvider -> Objects.equals(fedProvider.getName(), displayName))
return fedProvider; .findFirst()
} .orElse(null);
}
return null;
} }
public static UserStorageProviderModel findUserStorageProviderById(String fedProviderId, RealmModel realm) { public static UserStorageProviderModel findUserStorageProviderById(String fedProviderId, RealmModel realm) {
for (UserStorageProviderModel fedProvider : realm.getUserStorageProviders()) { return realm.getUserStorageProvidersStream()
if (fedProviderId.equals(fedProvider.getId())) { .filter(fedProvider -> Objects.equals(fedProvider.getId(), fedProviderId))
return fedProvider; .findFirst()
} .orElse(null);
}
return null;
} }
public static ComponentModel createComponentModel(String name, String parentId, String providerId, String providerType, String... config) { public static ComponentModel createComponentModel(String name, String parentId, String providerId, String providerType, String... config) {
@ -364,15 +359,14 @@ public final class KeycloakModelUtils {
* @param result input should be empty list. At the end will be all executions added to this list * @param result input should be empty list. At the end will be all executions added to this list
*/ */
public static void deepFindAuthenticationExecutions(RealmModel realm, AuthenticationFlowModel flow, List<AuthenticationExecutionModel> result) { public static void deepFindAuthenticationExecutions(RealmModel realm, AuthenticationFlowModel flow, List<AuthenticationExecutionModel> result) {
List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutions(flow.getId()); realm.getAuthenticationExecutionsStream(flow.getId()).forEachOrdered(execution -> {
for (AuthenticationExecutionModel execution : executions) {
if (execution.isAuthenticatorFlow()) { if (execution.isAuthenticatorFlow()) {
AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId()); AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId());
deepFindAuthenticationExecutions(realm, subFlow, result); deepFindAuthenticationExecutions(realm, subFlow, result);
} else { } else {
result.add(execution); result.add(execution);
} }
} });
} }
public static String resolveFirstAttribute(GroupModel group, String name) { public static String resolveFirstAttribute(GroupModel group, String name) {
@ -575,13 +569,9 @@ public final class KeycloakModelUtils {
if ((realmFlow = realm.getResetCredentialsFlow()) != null && realmFlow.getId().equals(model.getId())) return true; if ((realmFlow = realm.getResetCredentialsFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
if ((realmFlow = realm.getDockerAuthenticationFlow()) != null && realmFlow.getId().equals(model.getId())) return true; if ((realmFlow = realm.getDockerAuthenticationFlow()) != null && realmFlow.getId().equals(model.getId())) return true;
for (IdentityProviderModel idp : realm.getIdentityProviders()) { return realm.getIdentityProvidersStream().anyMatch(idp ->
if (model.getId().equals(idp.getFirstBrokerLoginFlowId())) return true; Objects.equals(idp.getFirstBrokerLoginFlowId(), model.getId()) ||
if (model.getId().equals(idp.getPostBrokerLoginFlowId())) return true; Objects.equals(idp.getPostBrokerLoginFlowId(), model.getId()));
}
return false;
} }
public static boolean isClientScopeUsed(RealmModel realm, ClientScopeModel clientScope) { public static boolean isClientScopeUsed(RealmModel realm, ClientScopeModel clientScope) {
@ -592,13 +582,14 @@ public final class KeycloakModelUtils {
} }
public static ClientScopeModel getClientScopeByName(RealmModel realm, String clientScopeName) { public static ClientScopeModel getClientScopeByName(RealmModel realm, String clientScopeName) {
for (ClientScopeModel clientScope : realm.getClientScopes()) { return realm.getClientScopesStream()
if (clientScopeName.equals(clientScope.getName())) { .filter(clientScope -> Objects.equals(clientScopeName, clientScope.getName()))
return clientScope; .findFirst()
} // check if we are referencing a client instead of a scope
} .orElse(realm.getClientsStream()
// check if we are referencing a client instead of a scope .filter(c -> Objects.equals(clientScopeName, c.getClientId()))
return realm.getClientsStream().filter(c -> clientScopeName.equals(c.getClientId())).findFirst().orElse(null); .findFirst()
.orElse(null));
} }
/** /**

View file

@ -39,8 +39,6 @@ import org.keycloak.representations.idm.authorization.*;
import org.keycloak.storage.StorageId; import org.keycloak.storage.StorageId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
@ -323,12 +321,10 @@ public class ModelToRepresentation {
if (realm.getEventsExpiration() != 0) { if (realm.getEventsExpiration() != 0) {
rep.setEventsExpiration(realm.getEventsExpiration()); rep.setEventsExpiration(realm.getEventsExpiration());
} }
if (realm.getEventsListeners() != null) {
rep.setEventsListeners(new LinkedList<>(realm.getEventsListeners())); rep.setEventsListeners(realm.getEventsListenersStream().collect(Collectors.toList()));
}
if (realm.getEnabledEventTypes() != null) { rep.setEnabledEventTypes(realm.getEnabledEventTypesStream().collect(Collectors.toList()));
rep.setEnabledEventTypes(new LinkedList<>(realm.getEnabledEventTypes()));
}
rep.setAdminEventsEnabled(realm.isAdminEventsEnabled()); rep.setAdminEventsEnabled(realm.isAdminEventsEnabled());
rep.setAdminEventsDetailsEnabled(realm.isAdminEventsDetailsEnabled()); rep.setAdminEventsDetailsEnabled(realm.isAdminEventsDetailsEnabled());
@ -419,27 +415,23 @@ public class ModelToRepresentation {
rep.setDefaultGroups(defaultGroups); rep.setDefaultGroups(defaultGroups);
} }
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials(); Set<String> reqCredentials = realm.getRequiredCredentialsStream()
if (!requiredCredentialModels.isEmpty()) { .map(RequiredCredentialModel::getType)
rep.setRequiredCredentials(new HashSet<>()); .collect(Collectors.toSet());
for (RequiredCredentialModel cred : requiredCredentialModels) { if (!reqCredentials.isEmpty()) {
rep.getRequiredCredentials().add(cred.getType()); rep.setRequiredCredentials(reqCredentials);
}
} }
for (IdentityProviderModel provider : realm.getIdentityProviders()) { List<IdentityProviderRepresentation> identityProviders = realm.getIdentityProvidersStream()
rep.addIdentityProvider(toRepresentation(realm, provider)); .map(provider -> toRepresentation(realm, provider)).collect(Collectors.toList());
} rep.setIdentityProviders(identityProviders);
for (IdentityProviderMapperModel mapper : realm.getIdentityProviderMappers()) { List<IdentityProviderMapperRepresentation> identityProviderMappers = realm.getIdentityProviderMappersStream()
rep.addIdentityProviderMapper(toRepresentation(mapper)); .map(ModelToRepresentation::toRepresentation).collect(Collectors.toList());
} rep.setIdentityProviderMappers(identityProviderMappers);
rep.setInternationalizationEnabled(realm.isInternationalizationEnabled()); rep.setInternationalizationEnabled(realm.isInternationalizationEnabled());
if (realm.getSupportedLocales() != null) { rep.setSupportedLocales(realm.getSupportedLocalesStream().collect(Collectors.toSet()));
rep.setSupportedLocales(new HashSet<>());
rep.getSupportedLocales().addAll(realm.getSupportedLocales());
}
rep.setDefaultLocale(realm.getDefaultLocale()); rep.setDefaultLocale(realm.getDefaultLocale());
if (internal) { if (internal) {
exportAuthenticationFlows(realm, rep); exportAuthenticationFlows(realm, rep);
@ -479,47 +471,22 @@ public class ModelToRepresentation {
} }
public static void exportAuthenticationFlows(RealmModel realm, RealmRepresentation rep) { public static void exportAuthenticationFlows(RealmModel realm, RealmRepresentation rep) {
rep.setAuthenticationFlows(new LinkedList<>()); List<AuthenticationFlowRepresentation> authenticationFlows = realm.getAuthenticationFlowsStream()
rep.setAuthenticatorConfig(new LinkedList<>()); .sorted(AuthenticationFlowModel.AuthenticationFlowComparator.SINGLETON)
.map(flow -> toRepresentation(realm, flow))
List<AuthenticationFlowModel> authenticationFlows = new ArrayList<>(realm.getAuthenticationFlows()); .collect(Collectors.toList());
//ensure consistent ordering of authenticationFlows. rep.setAuthenticationFlows(authenticationFlows);
Collections.sort(authenticationFlows, new Comparator<AuthenticationFlowModel>() {
@Override
public int compare(AuthenticationFlowModel left, AuthenticationFlowModel right) {
String l = left.getAlias() != null ? left.getAlias() : "\0";
String r = right.getAlias() != null ? right.getAlias() : "\0";
return l.compareTo(r);
}
});
for (AuthenticationFlowModel model : authenticationFlows) {
AuthenticationFlowRepresentation flowRep = toRepresentation(realm, model);
rep.getAuthenticationFlows().add(flowRep);
}
List<AuthenticatorConfigModel> authenticatorConfigs = new ArrayList<>(realm.getAuthenticatorConfigs());
//ensure consistent ordering of authenticatorConfigs.
Collections.sort(authenticatorConfigs, new Comparator<AuthenticatorConfigModel>() {
@Override
public int compare(AuthenticatorConfigModel left, AuthenticatorConfigModel right) {
String l = left.getAlias() != null ? left.getAlias() : "\0";
String r = right.getAlias() != null ? right.getAlias() : "\0";
return l.compareTo(r);
}
});
for (AuthenticatorConfigModel model : authenticatorConfigs) {
rep.getAuthenticatorConfig().add(toRepresentation(model));
}
List<AuthenticatorConfigRepresentation> authenticationConfigs = realm.getAuthenticatorConfigsStream()
.sorted(AuthenticatorConfigModel.AuthenticationConfigComparator.SINGLETON)
.map(ModelToRepresentation::toRepresentation)
.collect(Collectors.toList());
rep.setAuthenticatorConfig(authenticationConfigs);
} }
public static void exportRequiredActions(RealmModel realm, RealmRepresentation rep) { public static void exportRequiredActions(RealmModel realm, RealmRepresentation rep) {
rep.setRequiredActions(realm.getRequiredActionProvidersStream()
rep.setRequiredActions(new LinkedList<>()); .map(ModelToRepresentation::toRepresentation).collect(Collectors.toList()));
realm.getRequiredActionProviders().forEach(action -> rep.getRequiredActions().add(toRepresentation(action)));
} }
public static RealmEventsConfigRepresentation toEventsConfigReprensetation(RealmModel realm) { public static RealmEventsConfigRepresentation toEventsConfigReprensetation(RealmModel realm) {
@ -530,13 +497,9 @@ public class ModelToRepresentation {
rep.setEventsExpiration(realm.getEventsExpiration()); rep.setEventsExpiration(realm.getEventsExpiration());
} }
if (realm.getEventsListeners() != null) { rep.setEventsListeners(realm.getEventsListenersStream().collect(Collectors.toList()));
rep.setEventsListeners(new LinkedList<>(realm.getEventsListeners()));
}
if (realm.getEnabledEventTypes() != null) { rep.setEnabledEventTypes(realm.getEnabledEventTypesStream().collect(Collectors.toList()));
rep.setEnabledEventTypes(new LinkedList<>(realm.getEnabledEventTypes()));
}
rep.setAdminEventsEnabled(realm.isAdminEventsEnabled()); rep.setAdminEventsEnabled(realm.isAdminEventsEnabled());
@ -763,12 +726,9 @@ public class ModelToRepresentation {
rep.setProviderId(model.getProviderId()); rep.setProviderId(model.getProviderId());
rep.setAlias(model.getAlias()); rep.setAlias(model.getAlias());
rep.setDescription(model.getDescription()); rep.setDescription(model.getDescription());
rep.setAuthenticationExecutions(new LinkedList<>()); rep.setAuthenticationExecutions(realm.getAuthenticationExecutionsStream(model.getId())
for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(model.getId())) { .map(e -> toRepresentation(realm, e)).collect(Collectors.toList()));
rep.getAuthenticationExecutions().add(toRepresentation(realm, execution));
}
return rep; return rep;
} }
public static AuthenticationExecutionExportRepresentation toRepresentation(RealmModel realm, AuthenticationExecutionModel model) { public static AuthenticationExecutionExportRepresentation toRepresentation(RealmModel realm, AuthenticationExecutionModel model) {

View file

@ -446,7 +446,7 @@ public class RepresentationToModel {
} }
} }
if (newRealm.getComponents(newRealm.getId(), KeyProvider.class.getName()).isEmpty()) { if (newRealm.getComponentsStream(newRealm.getId(), KeyProvider.class.getName()).count() == 0) {
if (rep.getPrivateKey() != null) { if (rep.getPrivateKey() != null) {
DefaultKeyProviders.createProviders(newRealm, rep.getPrivateKey(), rep.getCertificate()); DefaultKeyProviders.createProviders(newRealm, rep.getPrivateKey(), rep.getCertificate());
} else { } else {

View file

@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener; import org.keycloak.provider.ProviderEventListener;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -76,12 +77,12 @@ public abstract class AbstractLoginProtocolFactory implements LoginProtocolFacto
} }
protected void addDefaultClientScopes(RealmModel realm, Stream<ClientModel> newClients) { protected void addDefaultClientScopes(RealmModel realm, Stream<ClientModel> newClients) {
Set<ClientScopeModel> defaultClientScopes = realm.getDefaultClientScopes(true).stream() Set<ClientScopeModel> defaultClientScopes = realm.getDefaultClientScopesStream(true)
.filter(clientScope -> getId().equals(clientScope.getProtocol())) .filter(clientScope -> Objects.equals(getId(), clientScope.getProtocol()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Set<ClientScopeModel> nonDefaultClientScopes = realm.getDefaultClientScopes(false).stream() Set<ClientScopeModel> nonDefaultClientScopes = realm.getDefaultClientScopesStream(false)
.filter(clientScope -> getId().equals(clientScope.getProtocol())) .filter(clientScope -> Objects.equals(getId(), clientScope.getProtocol()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Consumer<ClientModel> addDefault = c -> c.addClientScopes(defaultClientScopes, true); Consumer<ClientModel> addDefault = c -> c.addClientScopes(defaultClientScopes, true);

View file

@ -17,8 +17,6 @@
package org.keycloak.utils; package org.keycloak.utils;
import javax.ws.rs.core.Response;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.authentication.AuthenticatorFactory;
@ -29,17 +27,16 @@ import org.keycloak.authentication.FormAction;
import org.keycloak.authentication.FormActionFactory; import org.keycloak.authentication.FormActionFactory;
import org.keycloak.credential.CredentialModel; import org.keycloak.credential.CredentialModel;
import org.keycloak.credential.CredentialProvider; import org.keycloak.credential.CredentialProvider;
import org.keycloak.forms.account.AccountPages;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel; 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.utils.CredentialValidation;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import java.util.Objects;
/** /**
* used to set an execution a state based on type. * used to set an execution a state based on type.
* *
@ -61,22 +58,25 @@ public class CredentialHelper {
} }
public static void setOrReplaceAuthenticationRequirement(KeycloakSession session, RealmModel realm, String type, AuthenticationExecutionModel.Requirement requirement, AuthenticationExecutionModel.Requirement currentRequirement) { public static void setOrReplaceAuthenticationRequirement(KeycloakSession session, RealmModel realm, String type, AuthenticationExecutionModel.Requirement requirement, AuthenticationExecutionModel.Requirement currentRequirement) {
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) { realm.getAuthenticationFlowsStream().forEach(flow -> realm.getAuthenticationExecutionsStream(flow.getId())
for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(flow.getId())) { .filter(exe -> {
String providerId = execution.getAuthenticator(); ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(session, exe.getAuthenticator());
ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(session, providerId); return Objects.nonNull(factory) && Objects.equals(type, factory.getReferenceCategory());
if (factory == null) continue; })
if (type.equals(factory.getReferenceCategory())) { .filter(exe -> {
if (currentRequirement == null || currentRequirement.equals(execution.getRequirement())) { if (Objects.isNull(currentRequirement) || Objects.equals(exe.getRequirement(), currentRequirement))
execution.setRequirement(requirement); return true;
realm.updateAuthenticatorExecution(execution); else {
logger.debugf("Authenticator execution '%s' switched to '%s'", execution.getAuthenticator(), requirement.toString()); logger.debugf("Skip switch authenticator execution '%s' to '%s' as it's in state %s",
} else { exe.getAuthenticator(), requirement.toString(), exe.getRequirement());
logger.debugf("Skip switch authenticator execution '%s' to '%s' as it's in state %s", execution.getAuthenticator(), requirement.toString(), execution.getRequirement()); return false;
} }
} })
} .forEachOrdered(exe -> {
} exe.setRequirement(requirement);
realm.updateAuthenticatorExecution(exe);
logger.debugf("Authenticator execution '%s' switched to '%s'", exe.getAuthenticator(), requirement.toString());
}));
} }
public static ConfigurableAuthenticatorFactory getConfigurableAuthenticatorFactory(KeycloakSession session, String providerId) { public static ConfigurableAuthenticatorFactory getConfigurableAuthenticatorFactory(KeycloakSession session, String providerId) {

View file

@ -17,11 +17,29 @@
package org.keycloak.utils; package org.keycloak.utils;
import java.util.Iterator;
import java.util.Spliterators;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class StreamsUtil { public class StreamsUtil {
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());
} }
/**
* Returns the original stream if the stream is not empty. Otherwise throws the provided exception.
* @param stream Stream to be examined.
* @param ex Exception to be thrown if the stream is empty.
* @return Stream
*/
public static <T> Stream<T> throwIfEmpty(Stream<T> stream, RuntimeException ex) {
Iterator<T> iterator = stream.iterator();
if (iterator.hasNext()) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
} else {
throw ex;
}
}
} }

View file

@ -266,13 +266,10 @@ public class CredentialTypeMetadata implements Comparable<CredentialTypeMetadata
return false; return false;
} }
for (RequiredActionProviderModel requiredActionProvider : realm.getRequiredActionProviders()) { return realm.getRequiredActionProvidersStream()
if (requiredActionProviderId.equals(requiredActionProvider.getProviderId()) && requiredActionProvider.isEnabled()) { .filter(RequiredActionProviderModel::isEnabled)
return true; .map(RequiredActionProviderModel::getProviderId)
} .anyMatch(requiredActionProviderId::equals);
}
return false;
} }
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.models; package org.keycloak.models;
import java.io.Serializable; import java.io.Serializable;
import java.util.Comparator;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -79,4 +80,17 @@ public class AuthenticationFlowModel implements Serializable {
public void setBuiltIn(boolean builtIn) { public void setBuiltIn(boolean builtIn) {
this.builtIn = builtIn; this.builtIn = builtIn;
} }
public static class AuthenticationFlowComparator implements Comparator<AuthenticationFlowModel> {
public static final AuthenticationFlowModel.AuthenticationFlowComparator SINGLETON =
new AuthenticationFlowModel.AuthenticationFlowComparator();
@Override
public int compare(AuthenticationFlowModel left, AuthenticationFlowModel right) {
//ensure consistent ordering of authenticationFlows.
String l = left.getAlias() != null ? left.getAlias() : "\0";
String r = right.getAlias() != null ? right.getAlias() : "\0";
return l.compareTo(r);
}
}
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.models; package org.keycloak.models;
import java.io.Serializable; import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -57,4 +58,17 @@ public class AuthenticatorConfigModel implements Serializable {
public void setConfig(Map<String, String> config) { public void setConfig(Map<String, String> config) {
this.config = config; this.config = config;
} }
public static class AuthenticationConfigComparator implements Comparator<AuthenticatorConfigModel> {
public static final AuthenticatorConfigModel.AuthenticationConfigComparator SINGLETON =
new AuthenticatorConfigModel.AuthenticationConfigComparator();
@Override
public int compare(AuthenticatorConfigModel left, AuthenticatorConfigModel right) {
//ensure consistent ordering of authenticationFlows.
String l = left.getAlias() != null ? left.getAlias() : "\0";
String r = right.getAlias() != null ? right.getAlias() : "\0";
return l.compareTo(r);
}
}
} }

View file

@ -49,7 +49,7 @@ public interface GroupProvider extends Provider, GroupLookupProvider {
* *
* @param realm Realm. * @param realm Realm.
* @return List of groups in the Realm. * @return List of groups in the Realm.
* @deprecated Use {@link #getGroupsStream(RealmModel)} getGroupsStream} instead. * @deprecated Use {@link #getGroupsStream(RealmModel) getGroupsStream} instead.
*/ */
@Deprecated @Deprecated
default List<GroupModel> getGroups(RealmModel realm) { default List<GroupModel> getGroups(RealmModel realm) {
@ -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, Integer, Integer)} getGroupsByRoleStream} instead. * @deprecated Use {@link #getGroupsByRoleStream(RealmModel, RoleModel, int, int) 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) {
@ -163,7 +163,7 @@ public interface GroupProvider extends Provider, GroupLookupProvider {
* *
* @param realm Realm. * @param realm Realm.
* @return List of all top level groups in the realm. * @return List of all top level groups in the realm.
* @deprecated Use {@link #getTopLevelGroupsStream(RealmModel)} getTopLevelGroupsStream} instead. * @deprecated Use {@link #getTopLevelGroupsStream(RealmModel) getTopLevelGroupsStream} instead.
*/ */
@Deprecated @Deprecated
default List<GroupModel> getTopLevelGroups(RealmModel realm) { default List<GroupModel> getTopLevelGroups(RealmModel realm) {
@ -185,7 +185,7 @@ public interface GroupProvider extends Provider, GroupLookupProvider {
* @param firstResult First result to return. Ignored if negative or {@code null}. * @param firstResult First result to return. Ignored if negative or {@code null}.
* @param maxResults Maximum number of results to return. Ignored if negative or {@code null}. * @param maxResults Maximum number of results to return. Ignored if negative or {@code null}.
* @return List of top level groups in the realm. * @return List of top level groups in the realm.
* @deprecated Use {@link #getTopLevelGroupsStream(RealmModel, Integer, Integer)} getTopLevelGroupsStream} instead. * @deprecated Use {@link #getTopLevelGroupsStream(RealmModel, Integer, Integer) getTopLevelGroupsStream} instead.
*/ */
@Deprecated @Deprecated
default List<GroupModel> getTopLevelGroups(RealmModel realm, Integer firstResult, Integer maxResults) { default List<GroupModel> getTopLevelGroups(RealmModel realm, Integer firstResult, Integer maxResults) {

View file

@ -246,7 +246,15 @@ public interface RealmModel extends RoleContainerModel {
int getActionTokenGeneratedByUserLifespan(String actionTokenType); int getActionTokenGeneratedByUserLifespan(String actionTokenType);
void setActionTokenGeneratedByUserLifespan(String actionTokenType, Integer seconds); void setActionTokenGeneratedByUserLifespan(String actionTokenType, Integer seconds);
List<RequiredCredentialModel> getRequiredCredentials(); /**
* @deprecated Use {@link #getRequiredCredentialsStream() getRequiredCredentialsStream} instead.
*/
@Deprecated
default List<RequiredCredentialModel> getRequiredCredentials() {
return getRequiredCredentialsStream().collect(Collectors.toList());
}
Stream<RequiredCredentialModel> getRequiredCredentialsStream();
void addRequiredCredential(String cred); void addRequiredCredential(String cred);
@ -360,42 +368,115 @@ public interface RealmModel extends RoleContainerModel {
AuthenticationFlowModel getDockerAuthenticationFlow(); AuthenticationFlowModel getDockerAuthenticationFlow();
void setDockerAuthenticationFlow(AuthenticationFlowModel flow); void setDockerAuthenticationFlow(AuthenticationFlowModel flow);
List<AuthenticationFlowModel> getAuthenticationFlows(); /**
* @deprecated Use {@link #getAuthenticationFlowsStream() getAuthenticationFlowsStream} instead.
*/
@Deprecated
default List<AuthenticationFlowModel> getAuthenticationFlows() {
return getAuthenticationFlowsStream().collect(Collectors.toList());
}
Stream<AuthenticationFlowModel> getAuthenticationFlowsStream();
AuthenticationFlowModel getFlowByAlias(String alias); AuthenticationFlowModel getFlowByAlias(String alias);
AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model); AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model);
AuthenticationFlowModel getAuthenticationFlowById(String id); AuthenticationFlowModel getAuthenticationFlowById(String id);
void removeAuthenticationFlow(AuthenticationFlowModel model); void removeAuthenticationFlow(AuthenticationFlowModel model);
void updateAuthenticationFlow(AuthenticationFlowModel model); void updateAuthenticationFlow(AuthenticationFlowModel model);
List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId); /**
* @deprecated Use {@link #getAuthenticationExecutionsStream(String) getAuthenticationExecutionsStream} instead.
*/
@Deprecated
default List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) {
return getAuthenticationExecutionsStream(flowId).collect(Collectors.toList());
}
/**
* Returns sorted {@link AuthenticationExecutionModel AuthenticationExecutionModel} as a stream.
* It should be used with forEachOrdered if the ordering is required.
* @return Sorted stream
*/
Stream<AuthenticationExecutionModel> getAuthenticationExecutionsStream(String flowId);
AuthenticationExecutionModel getAuthenticationExecutionById(String id); AuthenticationExecutionModel getAuthenticationExecutionById(String id);
AuthenticationExecutionModel getAuthenticationExecutionByFlowId(String flowId); AuthenticationExecutionModel getAuthenticationExecutionByFlowId(String flowId);
AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model); AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model);
void updateAuthenticatorExecution(AuthenticationExecutionModel model); void updateAuthenticatorExecution(AuthenticationExecutionModel model);
void removeAuthenticatorExecution(AuthenticationExecutionModel model); void removeAuthenticatorExecution(AuthenticationExecutionModel model);
/**
* @deprecated Use {@link #getAuthenticatorConfigsStream() getAuthenticatorConfigsStream} instead.
*/
@Deprecated
default List<AuthenticatorConfigModel> getAuthenticatorConfigs() {
return getAuthenticatorConfigsStream().collect(Collectors.toList());
}
Stream<AuthenticatorConfigModel> getAuthenticatorConfigsStream();
List<AuthenticatorConfigModel> getAuthenticatorConfigs();
AuthenticatorConfigModel addAuthenticatorConfig(AuthenticatorConfigModel model); AuthenticatorConfigModel addAuthenticatorConfig(AuthenticatorConfigModel model);
void updateAuthenticatorConfig(AuthenticatorConfigModel model); void updateAuthenticatorConfig(AuthenticatorConfigModel model);
void removeAuthenticatorConfig(AuthenticatorConfigModel model); void removeAuthenticatorConfig(AuthenticatorConfigModel model);
AuthenticatorConfigModel getAuthenticatorConfigById(String id); AuthenticatorConfigModel getAuthenticatorConfigById(String id);
AuthenticatorConfigModel getAuthenticatorConfigByAlias(String alias); AuthenticatorConfigModel getAuthenticatorConfigByAlias(String alias);
List<RequiredActionProviderModel> getRequiredActionProviders(); /**
* @deprecated Use {@link #getRequiredActionProvidersStream() getRequiredActionProvidersStream} instead.
*/
@Deprecated
default List<RequiredActionProviderModel> getRequiredActionProviders() {
return getRequiredActionProvidersStream().collect(Collectors.toList());
}
/**
* Returns sorted {@link RequiredActionProviderModel RequiredActionProviderModel} as a stream.
* It should be used with forEachOrdered if the ordering is required.
* @return Sorted stream
*/
Stream<RequiredActionProviderModel> getRequiredActionProvidersStream();
RequiredActionProviderModel addRequiredActionProvider(RequiredActionProviderModel model); RequiredActionProviderModel addRequiredActionProvider(RequiredActionProviderModel model);
void updateRequiredActionProvider(RequiredActionProviderModel model); void updateRequiredActionProvider(RequiredActionProviderModel model);
void removeRequiredActionProvider(RequiredActionProviderModel model); void removeRequiredActionProvider(RequiredActionProviderModel model);
RequiredActionProviderModel getRequiredActionProviderById(String id); RequiredActionProviderModel getRequiredActionProviderById(String id);
RequiredActionProviderModel getRequiredActionProviderByAlias(String alias); RequiredActionProviderModel getRequiredActionProviderByAlias(String alias);
List<IdentityProviderModel> getIdentityProviders(); /**
* @deprecated Use {@link #getIdentityProvidersStream() getIdentityProvidersStream} instead.
*/
@Deprecated
default List<IdentityProviderModel> getIdentityProviders() {
return getIdentityProvidersStream().collect(Collectors.toList());
}
Stream<IdentityProviderModel> getIdentityProvidersStream();
IdentityProviderModel getIdentityProviderByAlias(String alias); IdentityProviderModel getIdentityProviderByAlias(String alias);
void addIdentityProvider(IdentityProviderModel identityProvider); void addIdentityProvider(IdentityProviderModel identityProvider);
void removeIdentityProviderByAlias(String alias); void removeIdentityProviderByAlias(String alias);
void updateIdentityProvider(IdentityProviderModel identityProvider); void updateIdentityProvider(IdentityProviderModel identityProvider);
Set<IdentityProviderMapperModel> getIdentityProviderMappers();
Set<IdentityProviderMapperModel> getIdentityProviderMappersByAlias(String brokerAlias); /**
* @deprecated Use {@link #getIdentityProviderMappersStream() getIdentityProviderMappersStream} instead.
*/
@Deprecated
default Set<IdentityProviderMapperModel> getIdentityProviderMappers() {
return getIdentityProviderMappersStream().collect(Collectors.toSet());
}
Stream<IdentityProviderMapperModel> getIdentityProviderMappersStream();
/**
* @deprecated Use {@link #getIdentityProviderMappersByAliasStream(String) getIdentityProviderMappersByAliasStream} instead.
*/
@Deprecated
default Set<IdentityProviderMapperModel> getIdentityProviderMappersByAlias(String brokerAlias) {
return getIdentityProviderMappersByAliasStream(brokerAlias).collect(Collectors.toSet());
}
Stream<IdentityProviderMapperModel> getIdentityProviderMappersByAliasStream(String brokerAlias);
IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model); IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model);
void removeIdentityProviderMapper(IdentityProviderMapperModel mapping); void removeIdentityProviderMapper(IdentityProviderMapperModel mapping);
void updateIdentityProviderMapper(IdentityProviderMapperModel mapping); void updateIdentityProviderMapper(IdentityProviderMapperModel mapping);
@ -422,7 +503,15 @@ public interface RealmModel extends RoleContainerModel {
void updateComponent(ComponentModel component); void updateComponent(ComponentModel component);
void removeComponent(ComponentModel component); void removeComponent(ComponentModel component);
void removeComponents(String parentId); void removeComponents(String parentId);
List<ComponentModel> getComponents(String parentId, String providerType);
/**
* @deprecated Use {@link #getComponentsStream(String, String) getComponentsStream} instead.
*/
@Deprecated
default List<ComponentModel> getComponents(String parentId, String providerType) {
return getComponentsStream(parentId, providerType).collect(Collectors.toList());
}
/** /**
* Returns stream of ComponentModels for specific parentId and providerType. * Returns stream of ComponentModels for specific parentId and providerType.
@ -430,43 +519,85 @@ public interface RealmModel extends RoleContainerModel {
* @param providerType type of provider * @param providerType type of provider
* @return stream of ComponentModels * @return stream of ComponentModels
*/ */
default Stream<ComponentModel> getComponentsStream(String parentId, String providerType) { Stream<ComponentModel> getComponentsStream(String parentId, String providerType);
return getComponents(parentId, providerType).stream();
Stream<ComponentModel> getComponentsStream(String parentId);
/**
* @deprecated Use {@link #getComponentsStream(String) getComponentsStream} instead.
*/
@Deprecated
default List<ComponentModel> getComponents(String parentId) {
return getComponentsStream(parentId).collect(Collectors.toList());
} }
List<ComponentModel> getComponents(String parentId); /**
* @deprecated Use {@link #getComponentsStream() getComponentsStream} instead.
*/
@Deprecated
default List<ComponentModel> getComponents() {
return getComponentsStream().collect(Collectors.toList());
}
Stream<ComponentModel> getComponentsStream();
List<ComponentModel> getComponents();
ComponentModel getComponent(String id); ComponentModel getComponent(String id);
default /**
List<UserStorageProviderModel> getUserStorageProviders() { * @deprecated Use {@link #getUserStorageProvidersStream() getUserStorageProvidersStream} instead.
List<UserStorageProviderModel> list = new LinkedList<>(); */
for (ComponentModel component : getComponents(getId(), UserStorageProvider.class.getName())) { @Deprecated
list.add(new UserStorageProviderModel(component)); default List<UserStorageProviderModel> getUserStorageProviders() {
} return getUserStorageProvidersStream().collect(Collectors.toList());
Collections.sort(list, UserStorageProviderModel.comparator);
return list;
} }
default /**
List<ClientStorageProviderModel> getClientStorageProviders() { * Returns sorted {@link UserStorageProviderModel UserStorageProviderModel} as a stream.
List<ClientStorageProviderModel> list = new LinkedList<>(); * It should be used with forEachOrdered if the ordering is required.
for (ComponentModel component : getComponents(getId(), ClientStorageProvider.class.getName())) { * @return Sorted stream
list.add(new ClientStorageProviderModel(component)); */
} default Stream<UserStorageProviderModel> getUserStorageProvidersStream() {
Collections.sort(list, ClientStorageProviderModel.comparator); return getComponentsStream(getId(), UserStorageProvider.class.getName())
return list; .map(UserStorageProviderModel::new)
.sorted(UserStorageProviderModel.comparator);
} }
default /**
List<RoleStorageProviderModel> getRoleStorageProviders() { * @deprecated Use {@link #getClientStorageProvidersStream() getClientStorageProvidersStream} instead.
List<RoleStorageProviderModel> list = new LinkedList<>(); */
for (ComponentModel component : getComponents(getId(), RoleStorageProvider.class.getName())) { @Deprecated
list.add(new RoleStorageProviderModel(component)); default List<ClientStorageProviderModel> getClientStorageProviders() {
} return getClientStorageProvidersStream().collect(Collectors.toList());
Collections.sort(list, RoleStorageProviderModel.comparator); }
return list;
/**
* Returns sorted {@link ClientStorageProviderModel ClientStorageProviderModel} as a stream.
* It should be used with forEachOrdered if the ordering is required.
* @return Sorted stream
*/
default Stream<ClientStorageProviderModel> getClientStorageProvidersStream() {
return getComponentsStream(getId(), ClientStorageProvider.class.getName())
.map(ClientStorageProviderModel::new)
.sorted(ClientStorageProviderModel.comparator);
}
/**
* @deprecated Use {@link #getRoleStorageProvidersStream() getRoleStorageProvidersStream} instead.
*/
@Deprecated
default List<RoleStorageProviderModel> getRoleStorageProviders() {
return getRoleStorageProvidersStream().collect(Collectors.toList());
}
/**
* Returns sorted {@link RoleStorageProviderModel RoleStorageProviderModel} as a stream.
* It should be used with forEachOrdered if the ordering is required.
* @return Sorted stream
*/
default Stream<RoleStorageProviderModel> getRoleStorageProvidersStream() {
return getComponentsStream(getId(), RoleStorageProvider.class.getName())
.map(RoleStorageProviderModel::new)
.sorted(RoleStorageProviderModel.comparator);
} }
/** /**
@ -516,11 +647,27 @@ public interface RealmModel extends RoleContainerModel {
void setEventsExpiration(long expiration); void setEventsExpiration(long expiration);
Set<String> getEventsListeners(); /**
* @deprecated Use {@link #getEventsListenersStream() getEventsListenersStream} instead.
*/
@Deprecated
default Set<String> getEventsListeners() {
return getEventsListenersStream().collect(Collectors.toSet());
}
Stream<String> getEventsListenersStream();
void setEventsListeners(Set<String> listeners); void setEventsListeners(Set<String> listeners);
Set<String> getEnabledEventTypes(); /**
* @deprecated Use {@link #getEnabledEventTypesStream() getEnabledEventTypesStream} instead.
*/
@Deprecated
default Set<String> getEnabledEventTypes() {
return getEnabledEventTypesStream().collect(Collectors.toSet());
}
Stream<String> getEnabledEventTypesStream();
void setEnabledEventTypes(Set<String> enabledEventTypes); void setEnabledEventTypes(Set<String> enabledEventTypes);
@ -540,7 +687,17 @@ public interface RealmModel extends RoleContainerModel {
boolean isInternationalizationEnabled(); boolean isInternationalizationEnabled();
void setInternationalizationEnabled(boolean enabled); void setInternationalizationEnabled(boolean enabled);
Set<String> getSupportedLocales();
/**
* @deprecated Use {@link #getSupportedLocalesStream() getSupportedLocalesStream} instead.
*/
@Deprecated
default Set<String> getSupportedLocales() {
return getSupportedLocalesStream().collect(Collectors.toSet());
}
Stream<String> getSupportedLocalesStream();
void setSupportedLocales(Set<String> locales); void setSupportedLocales(Set<String> locales);
String getDefaultLocale(); String getDefaultLocale();
void setDefaultLocale(String locale); void setDefaultLocale(String locale);
@ -561,6 +718,9 @@ public interface RealmModel extends RoleContainerModel {
GroupModel getGroupById(String id); GroupModel getGroupById(String id);
/**
* @deprecated Use {@link #getGroupsStream() getGroupsStream} instead.
*/
@Deprecated @Deprecated
default List<GroupModel> getGroups() { default List<GroupModel> getGroups() {
return getGroupsStream().collect(Collectors.toList()); return getGroupsStream().collect(Collectors.toList());
@ -571,6 +731,9 @@ public interface RealmModel extends RoleContainerModel {
Long getGroupsCount(Boolean onlyTopGroups); Long getGroupsCount(Boolean onlyTopGroups);
Long getGroupsCountByNameContaining(String search); Long getGroupsCountByNameContaining(String search);
/**
* @deprecated Use {@link #getTopLevelGroups() getTopLevelGroups} instead.
*/
@Deprecated @Deprecated
default List<GroupModel> getTopLevelGroups() { default List<GroupModel> getTopLevelGroups() {
return getTopLevelGroupsStream().collect(Collectors.toList()); return getTopLevelGroupsStream().collect(Collectors.toList());
@ -578,6 +741,9 @@ public interface RealmModel extends RoleContainerModel {
Stream<GroupModel> getTopLevelGroupsStream(); Stream<GroupModel> getTopLevelGroupsStream();
/**
* @deprecated Use {@link #getTopLevelGroupsStream(Integer, Integer) getTopLevelGroupsStream} instead.
*/
@Deprecated @Deprecated
default List<GroupModel> getTopLevelGroups(Integer first, Integer max) { default List<GroupModel> getTopLevelGroups(Integer first, Integer max) {
return getTopLevelGroupsStream(first, max).collect(Collectors.toList()); return getTopLevelGroupsStream(first, max).collect(Collectors.toList());
@ -585,6 +751,9 @@ public interface RealmModel extends RoleContainerModel {
Stream<GroupModel> getTopLevelGroupsStream(Integer first, Integer max); Stream<GroupModel> getTopLevelGroupsStream(Integer first, Integer max);
/**
* @deprecated Use {@link #searchForGroupByNameStream(String, Integer, Integer) searchForGroupByName} instead.
*/
@Deprecated @Deprecated
default List<GroupModel> searchForGroupByName(String search, Integer first, Integer max) { default List<GroupModel> searchForGroupByName(String search, Integer first, Integer max) {
return searchForGroupByNameStream(search, first, max).collect(Collectors.toList()); return searchForGroupByNameStream(search, first, max).collect(Collectors.toList());
@ -595,7 +764,15 @@ public interface RealmModel extends RoleContainerModel {
boolean removeGroup(GroupModel group); boolean removeGroup(GroupModel group);
void moveGroup(GroupModel group, GroupModel toParent); void moveGroup(GroupModel group, GroupModel toParent);
List<ClientScopeModel> getClientScopes(); /**
* @deprecated Use {@link #getClientScopesStream() getClientScopesStream} instead.
*/
@Deprecated
default List<ClientScopeModel> getClientScopes() {
return getClientScopesStream().collect(Collectors.toList());
}
Stream<ClientScopeModel> getClientScopesStream();
ClientScopeModel addClientScope(String name); ClientScopeModel addClientScope(String name);
@ -607,6 +784,14 @@ public interface RealmModel extends RoleContainerModel {
void addDefaultClientScope(ClientScopeModel clientScope, boolean defaultScope); void addDefaultClientScope(ClientScopeModel clientScope, boolean defaultScope);
void removeDefaultClientScope(ClientScopeModel clientScope); void removeDefaultClientScope(ClientScopeModel clientScope);
List<ClientScopeModel> getDefaultClientScopes(boolean defaultScope);
/**
* @deprecated Use {@link #getDefaultClientScopesStream(boolean) getDefaultClientScopesStream} instead.
*/
@Deprecated
default List<ClientScopeModel> getDefaultClientScopes(boolean defaultScope) {
return getDefaultClientScopesStream(defaultScope).collect(Collectors.toList());
}
Stream<ClientScopeModel> getDefaultClientScopesStream(boolean defaultScope);
} }

View file

@ -23,6 +23,7 @@ import org.keycloak.provider.Provider;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -39,14 +40,43 @@ public interface RealmProvider extends Provider /* TODO: Remove in future versio
ClientScopeModel getClientScopeById(String id, RealmModel realm); ClientScopeModel getClientScopeById(String id, RealmModel realm);
List<RealmModel> getRealms(); /**
List<RealmModel> getRealmsWithProviderType(Class<?> type); * @deprecated Use {@link #getRealmsStream() getRealmsStream} instead.
*/
@Deprecated
default List<RealmModel> getRealms() {
return getRealmsStream().collect(Collectors.toList());
}
Stream<RealmModel> getRealmsStream();
/**
* @deprecated Use {@link #getRealmsWithProviderTypeStream(Class)} getRealmsWithProviderTypeStream} instead.
*/
@Deprecated
default List<RealmModel> getRealmsWithProviderType(Class<?> type) {
return getRealmsWithProviderTypeStream(type).collect(Collectors.toList());
}
Stream<RealmModel> getRealmsWithProviderTypeStream(Class<?> type);
boolean removeRealm(String id); boolean removeRealm(String id);
ClientInitialAccessModel createClientInitialAccessModel(RealmModel realm, int expiration, int count); ClientInitialAccessModel createClientInitialAccessModel(RealmModel realm, int expiration, int count);
ClientInitialAccessModel getClientInitialAccessModel(RealmModel realm, String id); ClientInitialAccessModel getClientInitialAccessModel(RealmModel realm, String id);
void removeClientInitialAccessModel(RealmModel realm, String id); void removeClientInitialAccessModel(RealmModel realm, String id);
List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm);
/**
* @deprecated Use {@link #listClientInitialAccessStream(RealmModel)} listClientInitialAccessStream} instead.
*/
@Deprecated
default List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
return listClientInitialAccessStream(realm).collect(Collectors.toList());
}
Stream<ClientInitialAccessModel> listClientInitialAccessStream(RealmModel realm);
void removeExpiredClientInitialAccess(); void removeExpiredClientInitialAccess();
void decreaseRemainingCount(RealmModel realm, ClientInitialAccessModel clientInitialAccess); // Separate provider method to ensure we decrease remainingCount atomically instead of doing classic update void decreaseRemainingCount(RealmModel realm, ClientInitialAccessModel clientInitialAccess); // Separate provider method to ensure we decrease remainingCount atomically instead of doing classic update

View file

@ -42,7 +42,7 @@ public interface GroupLookupProvider {
* @param firstResult First result to return. Ignored if {@code null}. * @param firstResult First result to return. Ignored if {@code null}.
* @param maxResults Maximum number of results to return. Ignored if {@code null}. * @param maxResults Maximum number of results to return. Ignored if {@code null}.
* @return List of groups with the given string in name. * @return List of groups with the given string in name.
* @deprecated Use {@link #searchForGroupByNameStream(RealmModel, String, Integer, Integer)} searchForGroupByNameStream} instead. * @deprecated Use {@link #searchForGroupByNameStream(RealmModel, String, Integer, Integer) searchForGroupByNameStream} instead.
*/ */
@Deprecated @Deprecated
default List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer firstResult, Integer maxResults) { default List<GroupModel> searchForGroupByName(RealmModel realm, String search, Integer firstResult, Integer maxResults) {

View file

@ -39,7 +39,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.AuthenticationFlowResolver; import org.keycloak.models.utils.AuthenticationFlowResolver;
import org.keycloak.models.utils.FormMessage; import org.keycloak.models.utils.FormMessage;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.LoginProtocol.Error; import org.keycloak.protocol.LoginProtocol.Error;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
@ -302,15 +301,15 @@ public class AuthenticationProcessor {
@Override @Override
public AuthenticationExecutionModel.Requirement getCategoryRequirementFromCurrentFlow(String authenticatorCategory) { public AuthenticationExecutionModel.Requirement getCategoryRequirementFromCurrentFlow(String authenticatorCategory) {
List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutions(execution.getParentFlow()); return realm.getAuthenticationExecutionsStream(execution.getParentFlow())
for (AuthenticationExecutionModel exe : executions) { .filter(e -> {
AuthenticatorFactory factory = (AuthenticatorFactory) getSession().getKeycloakSessionFactory().getProviderFactory(Authenticator.class, exe.getAuthenticator()); AuthenticatorFactory factory = (AuthenticatorFactory) getSession().getKeycloakSessionFactory()
if (factory != null && factory.getReferenceCategory().equals(authenticatorCategory)) { .getProviderFactory(Authenticator.class, e.getAuthenticator());
return exe.getRequirement(); return factory != null && factory.getReferenceCategory().equals(authenticatorCategory);
} })
.map(AuthenticationExecutionModel::getRequirement)
} .findFirst()
return null; .orElse(null);
} }
@Override @Override
@ -1045,7 +1044,7 @@ public class AuthenticationProcessor {
} }
public void evaluateRequiredActionTriggers() { public void evaluateRequiredActionTriggers() {
AuthenticationManager.evaluateRequiredActionTriggers(session, authenticationSession, connection, request, uriInfo, event, realm, authenticationSession.getAuthenticatedUser()); AuthenticationManager.evaluateRequiredActionTriggers(session, authenticationSession, request, event, realm, authenticationSession.getAuthenticatedUser());
} }
public Response finishAuthentication(LoginProtocol protocol) { public Response finishAuthentication(LoginProtocol protocol) {
@ -1076,7 +1075,7 @@ public class AuthenticationProcessor {
} }
public String nextRequiredAction() { public String nextRequiredAction() {
return AuthenticationManager.nextRequiredAction(session, authenticationSession, connection, request, uriInfo, event); return AuthenticationManager.nextRequiredAction(session, authenticationSession, request, event);
} }
public AuthenticationProcessor.Result createAuthenticatorContext(AuthenticationExecutionModel model, Authenticator authenticator, List<AuthenticationExecutionModel> executions) { public AuthenticationProcessor.Result createAuthenticatorContext(AuthenticationExecutionModel model, Authenticator authenticator, List<AuthenticationExecutionModel> executions) {

View file

@ -24,10 +24,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.credential.CredentialModel; import org.keycloak.credential.CredentialModel;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
@ -136,7 +132,8 @@ class AuthenticationSelectionResolver {
} }
// Find the corresponding execution. If it is 1st REQUIRED execution in the particular subflow, we need to consider parent flow as well // Find the corresponding execution. If it is 1st REQUIRED execution in the particular subflow, we need to consider parent flow as well
List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutions(execution.getParentFlow()); List<AuthenticationExecutionModel> executions = realm.getAuthenticationExecutionsStream(execution.getParentFlow())
.collect(Collectors.toList());
int executionIndex = executions.indexOf(execution); int executionIndex = executions.indexOf(execution);
if (executionIndex != 0) { if (executionIndex != 0) {
return flowId; return flowId;
@ -188,11 +185,9 @@ class AuthenticationSelectionResolver {
logger.debugf("Going through the flow '%s' for adding executions", flowModel.getAlias()); logger.debugf("Going through the flow '%s' for adding executions", flowModel.getAlias());
List<AuthenticationExecutionModel> executions = processor.getRealm().getAuthenticationExecutions(flowId);
List<AuthenticationExecutionModel> requiredList = new ArrayList<>(); List<AuthenticationExecutionModel> requiredList = new ArrayList<>();
List<AuthenticationExecutionModel> alternativeList = new ArrayList<>(); List<AuthenticationExecutionModel> alternativeList = new ArrayList<>();
flow.fillListsOfExecutions(executions, requiredList, alternativeList); flow.fillListsOfExecutions(processor.getRealm().getAuthenticationExecutionsStream(flowId), requiredList, alternativeList);
// If requiredList is not empty, we're going to collect just very first execution from the flow // If requiredList is not empty, we're going to collect just very first execution from the flow
if (!requiredList.isEmpty()) { if (!requiredList.isEmpty()) {

View file

@ -1,78 +0,0 @@
/*
* Copyright 2016 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.authentication;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.RealmModel;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AuthenticatorUtil {
public static List<AuthenticationExecutionModel> getEnabledExecutionsRecursively(RealmModel realm, String flowId) {
List<AuthenticationExecutionModel> executions = new LinkedList<>();
recurseExecutions(realm, flowId, executions);
return executions;
}
public static void recurseExecutions(RealmModel realm, String flowId, List<AuthenticationExecutionModel> executions) {
List<AuthenticationExecutionModel> authenticationExecutions = realm.getAuthenticationExecutions(flowId);
if (authenticationExecutions == null) return;
for (AuthenticationExecutionModel model : authenticationExecutions) {
executions.add(model);
if (model.isAuthenticatorFlow() && model.isEnabled()) {
recurseExecutions(realm, model.getFlowId(), executions);
}
}
}
public static AuthenticationExecutionModel findExecutionByAuthenticator(RealmModel realm, String flowId, String authProviderId) {
for (AuthenticationExecutionModel model : realm.getAuthenticationExecutions(flowId)) {
if (model.isAuthenticatorFlow()) {
AuthenticationExecutionModel recurse = findExecutionByAuthenticator(realm, model.getFlowId(), authProviderId);
if (recurse != null) return recurse;
}
if (model.getAuthenticator().equals(authProviderId)) {
return model;
}
}
return null;
}
public static boolean isEnabled(RealmModel realm, String flowId, String authProviderId) {
AuthenticationExecutionModel execution = findExecutionByAuthenticator(realm, flowId, authProviderId);
if (execution == null) {
return false;
}
return execution.isEnabled();
}
public static boolean isRequired(RealmModel realm, String flowId, String authProviderId) {
AuthenticationExecutionModel execution = findExecutionByAuthenticator(realm, flowId, authProviderId);
if (execution == null) {
return false;
}
return execution.isRequired();
}
}

View file

@ -29,7 +29,9 @@ import org.keycloak.services.ServicesLogger;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -106,19 +108,23 @@ public class ClientAuthenticationFlow implements AuthenticationFlow {
} }
protected List<AuthenticationExecutionModel> findExecutionsToRun() { protected List<AuthenticationExecutionModel> findExecutionsToRun() {
List<AuthenticationExecutionModel> executions = processor.getRealm().getAuthenticationExecutions(flow.getId()); List<AuthenticationExecutionModel> executionsToRun = new LinkedList<>();
List<AuthenticationExecutionModel> executionsToRun = new ArrayList<>(); List<AuthenticationExecutionModel> finalExecutionsToRun = executionsToRun;
Optional<AuthenticationExecutionModel> first = processor.getRealm().getAuthenticationExecutionsStream(flow.getId())
.filter(e -> {
if (e.isRequired()) {
return true;
} else if (e.isAlternative()){
finalExecutionsToRun.add(e);
return false;
}
return false;
}).findFirst();
for (AuthenticationExecutionModel execution : executions) { if (first.isPresent())
if (execution.isRequired()) { executionsToRun = Arrays.asList(first.get());
executionsToRun = Arrays.asList(execution); else
break; executionsToRun.addAll(finalExecutionsToRun);
}
if (execution.isAlternative()) {
executionsToRun.add(execution);
}
}
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
List<String> exIds = new ArrayList<>(); List<String> exIds = new ArrayList<>();

View file

@ -23,7 +23,6 @@ import org.keycloak.authentication.authenticators.conditional.ConditionalAuthent
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.services.ServicesLogger; import org.keycloak.services.ServicesLogger;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
@ -35,7 +34,9 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -52,7 +53,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
public DefaultAuthenticationFlow(AuthenticationProcessor processor, AuthenticationFlowModel flow) { public DefaultAuthenticationFlow(AuthenticationProcessor processor, AuthenticationFlowModel flow) {
this.processor = processor; this.processor = processor;
this.flow = flow; this.flow = flow;
this.executions = processor.getRealm().getAuthenticationExecutions(flow.getId()); this.executions = processor.getRealm().getAuthenticationExecutionsStream(flow.getId()).collect(Collectors.toList());
} }
protected boolean isProcessed(AuthenticationExecutionModel model) { protected boolean isProcessed(AuthenticationExecutionModel model) {
@ -204,13 +205,13 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
*/ */
private String checkAndValidateParentFlow(AuthenticationExecutionModel model) { private String checkAndValidateParentFlow(AuthenticationExecutionModel model) {
while (true) { while (true) {
List<AuthenticationExecutionModel> localExecutions = processor.getRealm().getAuthenticationExecutions(model.getParentFlow());
AuthenticationExecutionModel parentFlowExecutionModel = processor.getRealm().getAuthenticationExecutionByFlowId(model.getParentFlow()); AuthenticationExecutionModel parentFlowExecutionModel = processor.getRealm().getAuthenticationExecutionByFlowId(model.getParentFlow());
if (parentFlowExecutionModel != null) { if (parentFlowExecutionModel != null) {
List<AuthenticationExecutionModel> requiredExecutions = new LinkedList<>(); List<AuthenticationExecutionModel> requiredExecutions = new LinkedList<>();
List<AuthenticationExecutionModel> alternativeExecutions = new LinkedList<>(); List<AuthenticationExecutionModel> alternativeExecutions = new LinkedList<>();
fillListsOfExecutions(localExecutions, requiredExecutions, alternativeExecutions); fillListsOfExecutions(processor.getRealm().getAuthenticationExecutionsStream(model.getParentFlow()),
requiredExecutions, alternativeExecutions);
// Note: If we evaluate alternative execution, we will also doublecheck that there are not required elements in same subflow // Note: If we evaluate alternative execution, we will also doublecheck that there are not required elements in same subflow
if ((model.isRequired() && requiredExecutions.stream().allMatch(processor::isSuccessful)) || if ((model.isRequired() && requiredExecutions.stream().allMatch(processor::isSuccessful)) ||
@ -237,7 +238,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
List<AuthenticationExecutionModel> requiredList = new ArrayList<>(); List<AuthenticationExecutionModel> requiredList = new ArrayList<>();
List<AuthenticationExecutionModel> alternativeList = new ArrayList<>(); List<AuthenticationExecutionModel> alternativeList = new ArrayList<>();
fillListsOfExecutions(executions, requiredList, alternativeList); fillListsOfExecutions(executions.stream(), requiredList, alternativeList);
//handle required elements : all required elements need to be executed //handle required elements : all required elements need to be executed
boolean requiredElementsSuccessful = true; boolean requiredElementsSuccessful = true;
@ -296,16 +297,16 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
/** /**
* Just iterates over executionsToProcess and fill "requiredList" and "alternativeList" according to it * Just iterates over executionsToProcess and fill "requiredList" and "alternativeList" according to it
*/ */
void fillListsOfExecutions(List<AuthenticationExecutionModel> executionsToProcess, List<AuthenticationExecutionModel> requiredList, List<AuthenticationExecutionModel> alternativeList) { void fillListsOfExecutions(Stream<AuthenticationExecutionModel> executionsToProcess, List<AuthenticationExecutionModel> requiredList, List<AuthenticationExecutionModel> alternativeList) {
for (AuthenticationExecutionModel execution : executionsToProcess) { executionsToProcess
if (isConditionalAuthenticator(execution)) { .filter(((Predicate<AuthenticationExecutionModel>) this::isConditionalAuthenticator).negate())
continue; .forEachOrdered(execution -> {
} else if (execution.isRequired() || execution.isConditional()) { if (execution.isRequired() || execution.isConditional()) {
requiredList.add(execution); requiredList.add(execution);
} else if (execution.isAlternative()) { } else if (execution.isAlternative()) {
alternativeList.add(execution); alternativeList.add(execution);
} }
} });
if (!requiredList.isEmpty() && !alternativeList.isEmpty()) { if (!requiredList.isEmpty() && !alternativeList.isEmpty()) {
List<String> alternativeIds = alternativeList.stream() List<String> alternativeIds = alternativeList.stream()
@ -327,12 +328,14 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
if (model == null || !model.isAuthenticatorFlow() || !model.isConditional()) { if (model == null || !model.isAuthenticatorFlow() || !model.isConditional()) {
return false; return false;
}; };
List<AuthenticationExecutionModel> modelList = processor.getRealm().getAuthenticationExecutions(model.getFlowId()); List<AuthenticationExecutionModel> modelList = processor.getRealm()
.getAuthenticationExecutionsStream(model.getFlowId()).collect(Collectors.toList());
List<AuthenticationExecutionModel> conditionalAuthenticatorList = modelList.stream() List<AuthenticationExecutionModel> conditionalAuthenticatorList = modelList.stream()
.filter(this::isConditionalAuthenticator) .filter(this::isConditionalAuthenticator)
.filter(s -> s.isEnabled()) .filter(s -> s.isEnabled())
.collect(Collectors.toList()); .collect(Collectors.toList());
return conditionalAuthenticatorList.isEmpty() || conditionalAuthenticatorList.stream().anyMatch(m-> conditionalNotMatched(m, modelList)); return conditionalAuthenticatorList.isEmpty() || conditionalAuthenticatorList.stream()
.anyMatch(m -> conditionalNotMatched(m, modelList));
} }
private boolean isConditionalAuthenticator(AuthenticationExecutionModel model) { private boolean isConditionalAuthenticator(AuthenticationExecutionModel model) {

View file

@ -42,6 +42,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -57,7 +58,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
public FormAuthenticationFlow(AuthenticationProcessor processor, AuthenticationExecutionModel execution) { public FormAuthenticationFlow(AuthenticationProcessor processor, AuthenticationExecutionModel execution) {
this.processor = processor; this.processor = processor;
this.formExecution = execution; this.formExecution = execution;
formActionExecutions = processor.getRealm().getAuthenticationExecutions(execution.getFlowId()); formActionExecutions = processor.getRealm().getAuthenticationExecutionsStream(execution.getFlowId()).collect(Collectors.toList());
formAuthenticator = processor.getSession().getProvider(FormAuthenticator.class, execution.getAuthenticator()); formAuthenticator = processor.getSession().getProvider(FormAuthenticator.class, execution.getAuthenticator());
} }

View file

@ -103,7 +103,7 @@ public class ExecuteActionsActionTokenHandler extends AbstractActionTokenHander<
// verify user email as we know it is valid as this entry point would never have gotten here. // verify user email as we know it is valid as this entry point would never have gotten here.
user.setEmailVerified(true); user.setEmailVerified(true);
String nextAction = AuthenticationManager.nextRequiredAction(tokenContext.getSession(), authSession, tokenContext.getClientConnection(), tokenContext.getRequest(), tokenContext.getUriInfo(), tokenContext.getEvent()); String nextAction = AuthenticationManager.nextRequiredAction(tokenContext.getSession(), authSession, tokenContext.getRequest(), tokenContext.getEvent());
return AuthenticationManager.redirectToRequiredActions(tokenContext.getSession(), tokenContext.getRealm(), authSession, tokenContext.getUriInfo(), nextAction); return AuthenticationManager.redirectToRequiredActions(tokenContext.getSession(), tokenContext.getRealm(), authSession, tokenContext.getUriInfo(), nextAction);
} }

View file

@ -111,7 +111,7 @@ public class VerifyEmailActionTokenHandler extends AbstractActionTokenHander<Ver
tokenContext.setEvent(event.clone().removeDetail(Details.EMAIL).event(EventType.LOGIN)); tokenContext.setEvent(event.clone().removeDetail(Details.EMAIL).event(EventType.LOGIN));
String nextAction = AuthenticationManager.nextRequiredAction(session, authSession, tokenContext.getClientConnection(), tokenContext.getRequest(), uriInfo, event); String nextAction = AuthenticationManager.nextRequiredAction(session, authSession, tokenContext.getRequest(), event);
return AuthenticationManager.redirectToRequiredActions(session, realm, authSession, uriInfo, nextAction); return AuthenticationManager.redirectToRequiredActions(session, realm, authSession, uriInfo, nextAction);
} }

View file

@ -18,7 +18,6 @@
package org.keycloak.authentication.authenticators.browser; package org.keycloak.authentication.authenticators.browser;
import org.keycloak.authentication.AuthenticationFlowContext; import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.models.AuthenticatorConfigModel;
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;
@ -287,8 +286,7 @@ public class ConditionalOtpFormAuthenticator extends OTPFormAuthenticator {
private boolean isOTPRequired(KeycloakSession session, RealmModel realm, UserModel user) { private boolean isOTPRequired(KeycloakSession session, RealmModel realm, UserModel user) {
MultivaluedMap<String, String> requestHeaders = session.getContext().getRequestHeaders().getRequestHeaders(); MultivaluedMap<String, String> requestHeaders = session.getContext().getRequestHeaders().getRequestHeaders();
for (AuthenticatorConfigModel configModel : realm.getAuthenticatorConfigs()) { return realm.getAuthenticatorConfigsStream().anyMatch(configModel -> {
if (tryConcludeBasedOn(voteForUserOtpControlAttribute(user, configModel.getConfig()))) { if (tryConcludeBasedOn(voteForUserOtpControlAttribute(user, configModel.getConfig()))) {
return true; return true;
} }
@ -311,8 +309,8 @@ public class ConditionalOtpFormAuthenticator extends OTPFormAuthenticator {
|| voteForDefaultFallback(configModel.getConfig()) == ABSTAIN)) { || voteForDefaultFallback(configModel.getConfig()) == ABSTAIN)) {
return true; return true;
} }
} return false;
return false; });
} }
private boolean containsConditionalOtpConfig(Map config) { private boolean containsConditionalOtpConfig(Map config) {

View file

@ -34,7 +34,8 @@ import org.keycloak.services.managers.ClientSessionCode;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.Objects;
import java.util.Optional;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -67,27 +68,28 @@ public class IdentityProviderAuthenticator implements Authenticator {
} }
private void redirect(AuthenticationFlowContext context, String providerId) { private void redirect(AuthenticationFlowContext context, String providerId) {
List<IdentityProviderModel> identityProviders = context.getRealm().getIdentityProviders(); Optional<IdentityProviderModel> idp = context.getRealm().getIdentityProvidersStream()
for (IdentityProviderModel identityProvider : identityProviders) { .filter(IdentityProviderModel::isEnabled)
if (identityProvider.isEnabled() && providerId.equals(identityProvider.getAlias())) { .filter(identityProvider -> Objects.equals(providerId, identityProvider.getAlias()))
String accessCode = new ClientSessionCode<>(context.getSession(), context.getRealm(), context.getAuthenticationSession()).getOrGenerateCode(); .findFirst();
String clientId = context.getAuthenticationSession().getClient().getClientId(); if (idp.isPresent()) {
String tabId = context.getAuthenticationSession().getTabId(); String accessCode = new ClientSessionCode<>(context.getSession(), context.getRealm(), context.getAuthenticationSession()).getOrGenerateCode();
URI location = Urls.identityProviderAuthnRequest(context.getUriInfo().getBaseUri(), providerId, context.getRealm().getName(), accessCode, clientId, tabId); String clientId = context.getAuthenticationSession().getClient().getClientId();
if (context.getAuthenticationSession().getClientNote(OAuth2Constants.DISPLAY) != null) { String tabId = context.getAuthenticationSession().getTabId();
location = UriBuilder.fromUri(location).queryParam(OAuth2Constants.DISPLAY, context.getAuthenticationSession().getClientNote(OAuth2Constants.DISPLAY)).build(); URI location = Urls.identityProviderAuthnRequest(context.getUriInfo().getBaseUri(), providerId, context.getRealm().getName(), accessCode, clientId, tabId);
} if (context.getAuthenticationSession().getClientNote(OAuth2Constants.DISPLAY) != null) {
Response response = Response.seeOther(location) location = UriBuilder.fromUri(location).queryParam(OAuth2Constants.DISPLAY, context.getAuthenticationSession().getClientNote(OAuth2Constants.DISPLAY)).build();
.build();
// will forward the request to the IDP with prompt=none if the IDP accepts forwards with prompt=none.
if ("none".equals(context.getAuthenticationSession().getClientNote(OIDCLoginProtocol.PROMPT_PARAM)) &&
Boolean.valueOf(identityProvider.getConfig().get(ACCEPTS_PROMPT_NONE))) {
context.getAuthenticationSession().setAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN, "true");
}
LOG.debugf("Redirecting to %s", providerId);
context.forceChallenge(response);
return;
} }
Response response = Response.seeOther(location)
.build();
// will forward the request to the IDP with prompt=none if the IDP accepts forwards with prompt=none.
if ("none".equals(context.getAuthenticationSession().getClientNote(OIDCLoginProtocol.PROMPT_PARAM)) &&
Boolean.valueOf(idp.get().getConfig().get(ACCEPTS_PROMPT_NONE))) {
context.getAuthenticationSession().setAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN, "true");
}
LOG.debugf("Redirecting to %s", providerId);
context.forceChallenge(response);
return;
} }
LOG.warnf("Provider not found or not enabled for realm %s", providerId); LOG.warnf("Provider not found or not enabled for realm %s", providerId);

View file

@ -1,7 +1,8 @@
package org.keycloak.authentication.authenticators.conditional; package org.keycloak.authentication.authenticators.conditional;
import java.util.ArrayList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects;
import org.keycloak.authentication.AuthenticationFlowContext; import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.Authenticator;
@ -20,34 +21,19 @@ public class ConditionalUserConfiguredAuthenticator implements ConditionalAuthen
} }
private boolean matchConditionInFlow(AuthenticationFlowContext context, String flowId) { private boolean matchConditionInFlow(AuthenticationFlowContext context, String flowId) {
List<AuthenticationExecutionModel> executions = context.getRealm().getAuthenticationExecutions(flowId); List<AuthenticationExecutionModel> requiredExecutions = new LinkedList<>();
if (executions==null) { List<AuthenticationExecutionModel> alternativeExecutions = new LinkedList<>();
return true; context.getRealm().getAuthenticationExecutionsStream(flowId)
} //Check if the execution's authenticator is a conditional authenticator, as they must not be evaluated here.
List<AuthenticationExecutionModel> requiredExecutions = new ArrayList<>(); .filter(e -> isConditionalExecution(context, e))
List<AuthenticationExecutionModel> alternativeExecutions = new ArrayList<>(); .filter(e -> !Objects.equals(context.getExecution().getId(), e.getId()) && !e.isAuthenticatorFlow())
executions.forEach(e -> { .forEachOrdered(e -> {
//Check if the execution's authenticator is a conditional authenticator, as they must not be evaluated here. if (e.isRequired()) {
boolean isConditionalAuthenticator = false; requiredExecutions.add(e);
try { } else if (e.isAlternative()) {
AuthenticatorFactory factory = (AuthenticatorFactory) context.getSession().getKeycloakSessionFactory().getProviderFactory(Authenticator.class, e.getAuthenticator()); alternativeExecutions.add(e);
if (factory != null) {
Authenticator auth = factory.create(context.getSession());
if (auth instanceof ConditionalAuthenticator) {
isConditionalAuthenticator = true;
} }
} });
} catch (Exception exception) {
//don't need to catch this
}
if (!context.getExecution().getId().equals(e.getId()) && !e.isAuthenticatorFlow() && !isConditionalAuthenticator) {
if (e.isRequired()) {
requiredExecutions.add(e);
} else if (e.isAlternative()) {
alternativeExecutions.add(e);
}
}
});
if (!requiredExecutions.isEmpty()) { if (!requiredExecutions.isEmpty()) {
return requiredExecutions.stream().allMatch(e -> isConfiguredFor(e, context)); return requiredExecutions.stream().allMatch(e -> isConfiguredFor(e, context));
} else if (!alternativeExecutions.isEmpty()) { } else if (!alternativeExecutions.isEmpty()) {
@ -56,6 +42,18 @@ public class ConditionalUserConfiguredAuthenticator implements ConditionalAuthen
return true; return true;
} }
private boolean isConditionalExecution(AuthenticationFlowContext context, AuthenticationExecutionModel e) {
AuthenticatorFactory factory = (AuthenticatorFactory) context.getSession().getKeycloakSessionFactory()
.getProviderFactory(Authenticator.class, e.getAuthenticator());
if (factory != null) {
Authenticator auth = factory.create(context.getSession());
if (auth instanceof ConditionalAuthenticator) {
return false;
}
}
return true;
}
private boolean isConfiguredFor(AuthenticationExecutionModel model, AuthenticationFlowContext context) { private boolean isConfiguredFor(AuthenticationExecutionModel model, AuthenticationFlowContext context) {
if (model.isAuthenticatorFlow()) { if (model.isAuthenticatorFlow()) {
return matchConditionInFlow(context, model.getId()); return matchConditionInFlow(context, model.getId());

View file

@ -25,7 +25,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CachedUserModel; import org.keycloak.models.cache.CachedUserModel;
import org.keycloak.models.cache.OnUserCache; import org.keycloak.models.cache.OnUserCache;
import org.keycloak.models.cache.UserCache; import org.keycloak.models.cache.UserCache;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.storage.StorageId; import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageManager; import org.keycloak.storage.UserStorageManager;
import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProvider;
@ -36,8 +35,10 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -172,11 +173,9 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
if (toValidate.isEmpty()) return true; if (toValidate.isEmpty()) return true;
List<CredentialInputValidator> credentialProviders = getCredentialProviders(session, realm, CredentialInputValidator.class); getCredentialProviders(session, CredentialInputValidator.class)
for (CredentialInputValidator validator : credentialProviders) { .forEach(validator -> validate(realm, user, toValidate, validator));
validate(realm, user, toValidate, validator);
}
return toValidate.isEmpty(); return toValidate.isEmpty();
} }
@ -190,14 +189,11 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
} }
} }
public static <T> List<T> getCredentialProviders(KeycloakSession session, RealmModel realm, Class<T> type) { public static <T> Stream<T> getCredentialProviders(KeycloakSession session, Class<T> type) {
List<T> list = new LinkedList<T>(); return session.getKeycloakSessionFactory().getProviderFactories(CredentialProvider.class)
for (ProviderFactory f : session.getKeycloakSessionFactory().getProviderFactories(CredentialProvider.class)) { .stream()
if (!Types.supports(type, f, CredentialProviderFactory.class)) continue; .filter(f -> Types.supports(type, f, CredentialProviderFactory.class))
list.add((T) session.getProvider(CredentialProvider.class, f.getId())); .map(f -> (T) session.getProvider(CredentialProvider.class, f.getId()));
}
return list;
} }
@Override @Override
@ -224,14 +220,9 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
} }
} }
List<CredentialInputUpdater> credentialProviders = getCredentialProviders(session, realm, CredentialInputUpdater.class); return getCredentialProviders(session, CredentialInputUpdater.class)
for (CredentialInputUpdater updater : credentialProviders) { .filter(updater -> updater.supportsCredentialType(input.getType()))
if (!updater.supportsCredentialType(input.getType())) continue; .anyMatch(updater -> updater.updateCredential(realm, user, input));
if (updater.updateCredential(realm, user, input)) return true;
}
return false;
} }
@Override @Override
@ -259,14 +250,9 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
} }
List<CredentialInputUpdater> credentialProviders = getCredentialProviders(session, realm, CredentialInputUpdater.class); getCredentialProviders(session, CredentialInputUpdater.class)
for (CredentialInputUpdater updater : credentialProviders) { .filter(updater -> updater.supportsCredentialType(credentialType))
if (!updater.supportsCredentialType(credentialType)) continue; .forEach(updater -> updater.disableCredentialType(realm, user, credentialType));
updater.disableCredentialType(realm, user, credentialType);
}
} }
@Override @Override
@ -291,10 +277,11 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
} }
List<CredentialInputUpdater> credentialProviders = getCredentialProviders(session, realm, CredentialInputUpdater.class); types.addAll(getCredentialProviders(session, CredentialInputUpdater.class)
for (CredentialInputUpdater updater : credentialProviders) { .map(updater -> updater.getDisableableCredentialTypes(realm, user))
types.addAll(updater.getDisableableCredentialTypes(realm, user)); .flatMap(Set::stream)
} .collect(Collectors.toSet()));
return types; return types;
} }
@ -347,50 +334,38 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
@Override @Override
public boolean isConfiguredLocally(RealmModel realm, UserModel user, String type) { public boolean isConfiguredLocally(RealmModel realm, UserModel user, String type) {
List<CredentialInputValidator> credentialProviders = getCredentialProviders(session, realm, CredentialInputValidator.class); return getCredentialProviders(session, CredentialInputValidator.class)
for (CredentialInputValidator validator : credentialProviders) { .anyMatch(validator -> validator.supportsCredentialType(type) && validator.isConfiguredFor(realm, user, type));
if (validator.supportsCredentialType(type) && validator.isConfiguredFor(realm, user, type)) {
return true;
}
}
return false;
} }
@Override @Override
public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) { public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) {
List<CredentialAuthentication> list = UserStorageManager.getEnabledStorageProviders(session, realm, CredentialAuthentication.class); CredentialValidationOutput output = authenticate(
for (CredentialAuthentication auth : list) { UserStorageManager.getEnabledStorageProviders(session, realm, CredentialAuthentication.class),
if (auth.supportsCredentialAuthenticationFor(input.getType())) { realm, input);
CredentialValidationOutput output = auth.authenticate(realm, input);
if (output != null) return output;
}
}
list = getCredentialProviders(session, realm, CredentialAuthentication.class); return (output != null) ? output : authenticate(getCredentialProviders(session, CredentialAuthentication.class),
for (CredentialAuthentication auth : list) { realm, input);
if (auth.supportsCredentialAuthenticationFor(input.getType())) { }
CredentialValidationOutput output = auth.authenticate(realm, input);
if (output != null) return output;
}
}
return null; public CredentialValidationOutput authenticate(Stream<CredentialAuthentication> storageProviders,
RealmModel realm, CredentialInput input) {
return storageProviders
.filter(auth -> auth.supportsCredentialAuthenticationFor(input.getType()))
.map(auth -> auth.authenticate(realm, input))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
} }
@Override @Override
public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) { public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) {
List<OnUserCache> credentialProviders = getCredentialProviders(session, realm, OnUserCache.class); getCredentialProviders(session, OnUserCache.class).forEach(validator -> validator.onCache(realm, user, delegate));
for (OnUserCache validator : credentialProviders) {
validator.onCache(realm, user, delegate);
}
} }
@Override @Override
public List<String> getConfiguredUserStorageCredentialTypes(RealmModel realm, UserModel user) { public List<String> getConfiguredUserStorageCredentialTypes(RealmModel realm, UserModel user) {
List<CredentialProvider> credentialProviders = getCredentialProviders(session, realm, CredentialProvider.class); return getCredentialProviders(session, CredentialProvider.class).map(CredentialProvider::getType)
return credentialProviders.stream().map(CredentialProvider::getType)
.filter(credentialType -> UserStorageCredentialConfigured.CONFIGURED == isConfiguredThroughUserStorage(realm, user, credentialType)) .filter(credentialType -> UserStorageCredentialConfigured.CONFIGURED == isConfiguredThroughUserStorage(realm, user, credentialType))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.exportimport.singlefile; package org.keycloak.exportimport.singlefile;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.exportimport.ExportProvider; import org.keycloak.exportimport.ExportProvider;
import org.keycloak.exportimport.util.ExportImportSessionTask; import org.keycloak.exportimport.util.ExportImportSessionTask;
@ -27,13 +28,12 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.util.JsonSerialization; import org.keycloak.services.util.ObjectMapperResolver;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.stream.Stream;
import java.util.List;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -59,15 +59,11 @@ public class SingleFileExportProvider implements ExportProvider {
@Override @Override
protected void runExportImportTask(KeycloakSession session) throws IOException { protected void runExportImportTask(KeycloakSession session) throws IOException {
List<RealmModel> realms = session.realms().getRealms(); Stream<RealmRepresentation> realms = session.realms().getRealmsStream()
List<RealmRepresentation> reps = new ArrayList<>(); .map(realm -> ExportUtils.exportRealm(session, realm, true, true));
for (RealmModel realm : realms) {
reps.add(ExportUtils.exportRealm(session, realm, true, true));
}
writeToFile(reps); writeToFile(realms);
} }
}); });
} }
@ -92,7 +88,10 @@ public class SingleFileExportProvider implements ExportProvider {
} }
private ObjectMapper getObjectMapper() { private ObjectMapper getObjectMapper() {
return JsonSerialization.prettyMapper; ObjectMapper streamSerializer = ObjectMapperResolver.createStreamSerializer();
streamSerializer.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
streamSerializer.enable(SerializationFeature.INDENT_OUTPUT);
return streamSerializer;
} }
private void writeToFile(Object reps) throws IOException { private void writeToFile(Object reps) throws IOException {

View file

@ -43,7 +43,6 @@ import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.StoreFactory; import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.credential.CredentialModel; import org.keycloak.credential.CredentialModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
@ -56,7 +55,6 @@ import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ClientScopeRepresentation;
import org.keycloak.representations.idm.ComponentExportRepresentation; import org.keycloak.representations.idm.ComponentExportRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation; import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@ -98,23 +96,11 @@ public class ExportUtils {
rep.setKeycloakVersion(Version.VERSION_KEYCLOAK); rep.setKeycloakVersion(Version.VERSION_KEYCLOAK);
// Client Scopes // Client Scopes
List<ClientScopeModel> clientScopeModels = realm.getClientScopes(); rep.setClientScopes(realm.getClientScopesStream().map(ModelToRepresentation::toRepresentation).collect(Collectors.toList()));
List<ClientScopeRepresentation> clientScopesReps = new ArrayList<>(); rep.setDefaultDefaultClientScopes(realm.getDefaultClientScopesStream(true)
for (ClientScopeModel app : clientScopeModels) { .map(ClientScopeModel::getName).collect(Collectors.toList()));
ClientScopeRepresentation clientRep = ModelToRepresentation.toRepresentation(app); rep.setDefaultOptionalClientScopes(realm.getDefaultClientScopesStream(false)
clientScopesReps.add(clientRep); .map(ClientScopeModel::getName).collect(Collectors.toList()));
}
rep.setClientScopes(clientScopesReps);
List<String> defaultClientScopeNames = realm.getDefaultClientScopes(true).stream().map((ClientScopeModel clientScope) -> {
return clientScope.getName();
}).collect(Collectors.toList());
rep.setDefaultDefaultClientScopes(defaultClientScopeNames);
List<String> optionalClientScopeNames = realm.getDefaultClientScopes(false).stream().map((ClientScopeModel clientScope) -> {
return clientScope.getName();
}).collect(Collectors.toList());
rep.setDefaultOptionalClientScopes(optionalClientScopeNames);
// Clients // Clients
List<ClientModel> clients = Collections.emptyList(); List<ClientModel> clients = Collections.emptyList();
@ -199,7 +185,7 @@ public class ExportUtils {
} }
// Scopes of client scopes // Scopes of client scopes
for (ClientScopeModel clientScope : realm.getClientScopes()) { realm.getClientScopesStream().forEach(clientScope -> {
Set<RoleModel> clientScopes = clientScope.getScopeMappingsStream().collect(Collectors.toSet()); Set<RoleModel> clientScopes = clientScope.getScopeMappingsStream().collect(Collectors.toSet());
ScopeMappingRepresentation scopeMappingRep = null; ScopeMappingRepresentation scopeMappingRep = null;
for (RoleModel scope : clientScopes) { for (RoleModel scope : clientScopes) {
@ -232,7 +218,7 @@ public class ExportUtils {
currentClientTemplateScope.role(scope.getName()); currentClientTemplateScope.role(scope.getName());
} }
} }
} });
if (clientScopeReps.size() > 0) { if (clientScopeReps.size() > 0) {
rep.setClientScopeMappings(clientScopeReps); rep.setClientScopeMappings(clientScopeReps);
@ -285,9 +271,8 @@ public class ExportUtils {
} }
public static MultivaluedHashMap<String, ComponentExportRepresentation> exportComponents(RealmModel realm, String parentId) { public static MultivaluedHashMap<String, ComponentExportRepresentation> exportComponents(RealmModel realm, String parentId) {
List<ComponentModel> componentList = realm.getComponents(parentId);
MultivaluedHashMap<String, ComponentExportRepresentation> components = new MultivaluedHashMap<>(); MultivaluedHashMap<String, ComponentExportRepresentation> components = new MultivaluedHashMap<>();
for (ComponentModel component : componentList) { realm.getComponentsStream(parentId).forEach(component -> {
ComponentExportRepresentation compRep = new ComponentExportRepresentation(); ComponentExportRepresentation compRep = new ComponentExportRepresentation();
compRep.setId(component.getId()); compRep.setId(component.getId());
compRep.setProviderId(component.getProviderId()); compRep.setProviderId(component.getProviderId());
@ -296,7 +281,7 @@ public class ExportUtils {
compRep.setSubType(component.getSubType()); compRep.setSubType(component.getSubType());
compRep.setSubComponents(exportComponents(realm, component.getId())); compRep.setSubComponents(exportComponents(realm, component.getId()));
components.add(component.getProviderType(), compRep); components.add(component.getProviderType(), compRep);
} });
return components; return components;
} }

View file

@ -68,12 +68,12 @@ public class ImportUtils {
// If master was imported, we may need to re-create realm management clients // If master was imported, we may need to re-create realm management clients
if (masterImported) { if (masterImported) {
for (RealmModel realm : session.realms().getRealms()) { session.realms().getRealmsStream()
if (realm.getMasterAdminClient() == null) { .filter(realm -> realm.getMasterAdminClient() == null)
logger.infof("Re-created management client in master realm for realm '%s'", realm.getName()); .forEach(realm -> {
new RealmManager(session).setupMasterAdminManagement(realm); logger.infof("Re-created management client in master realm for realm '%s'", realm.getName());
} new RealmManager(session).setupMasterAdminManagement(realm);
} });
} }
} }
@ -99,9 +99,7 @@ public class ImportUtils {
logger.infof("Realm '%s' already exists. Removing it before import", realmName); logger.infof("Realm '%s' already exists. Removing it before import", realmName);
if (Config.getAdminRealm().equals(realm.getId())) { if (Config.getAdminRealm().equals(realm.getId())) {
// Delete all masterAdmin apps due to foreign key constraints // Delete all masterAdmin apps due to foreign key constraints
for (RealmModel currRealm : model.getRealms()) { model.getRealmsStream().forEach(r -> r.setMasterAdminClient(null));
currRealm.setMasterAdminClient(null);
}
} }
// TODO: For migration between versions, it should be possible to delete just realm but keep it's users // TODO: For migration between versions, it should be possible to delete just realm but keep it's users
model.removeRealm(realm.getId()); model.removeRealm(realm.getId());

View file

@ -31,6 +31,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -47,7 +48,7 @@ public abstract class MultipleStepsExportProvider implements ExportProvider {
@Override @Override
public void run(KeycloakSession session) { public void run(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); List<RealmModel> realms = session.realms().getRealmsStream().collect(Collectors.toList());
holder.realms = realms; holder.realms = realms;
} }

View file

@ -27,9 +27,10 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.resources.account.AccountFormService; import org.keycloak.services.resources.account.AccountFormService;
import java.net.URI; import java.net.URI;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -39,41 +40,36 @@ public class AccountFederatedIdentityBean {
private static OrderedModel.OrderedModelComparator<FederatedIdentityEntry> IDP_COMPARATOR_INSTANCE = new OrderedModel.OrderedModelComparator<>(); private static OrderedModel.OrderedModelComparator<FederatedIdentityEntry> IDP_COMPARATOR_INSTANCE = new OrderedModel.OrderedModelComparator<>();
private final List<FederatedIdentityEntry> identities = new ArrayList<>(); private final List<FederatedIdentityEntry> identities;
private final boolean removeLinkPossible; private final boolean removeLinkPossible;
private final KeycloakSession session; private final KeycloakSession session;
public AccountFederatedIdentityBean(KeycloakSession session, RealmModel realm, UserModel user, URI baseUri, String stateChecker) { public AccountFederatedIdentityBean(KeycloakSession session, RealmModel realm, UserModel user, URI baseUri, String stateChecker) {
this.session = session; this.session = session;
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm); Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
int availableIdentities = 0; AtomicInteger availableIdentities = new AtomicInteger(0);
if (identityProviders != null && !identityProviders.isEmpty()) { this.identities = realm.getIdentityProvidersStream()
for (IdentityProviderModel provider : identityProviders) { .filter(IdentityProviderModel::isEnabled)
if (!provider.isEnabled()) { .map(provider -> {
continue; String providerId = provider.getAlias();
}
String providerId = provider.getAlias();
FederatedIdentityModel identity = getIdentity(identities, providerId); FederatedIdentityModel identity = getIdentity(identities, providerId);
if (identity != null) { if (identity != null) {
availableIdentities++; availableIdentities.getAndIncrement();
} }
String displayName = KeycloakModelUtils.getIdentityProviderDisplayName(session, provider); String displayName = KeycloakModelUtils.getIdentityProviderDisplayName(session, provider);
FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, displayName, provider.getAlias(), provider.getAlias(), return new FederatedIdentityEntry(identity, displayName, provider.getAlias(), provider.getAlias(),
provider.getConfig() != null ? provider.getConfig().get("guiOrder") : null); provider.getConfig() != null ? provider.getConfig().get("guiOrder") : null);
this.identities.add(entry); })
} .sorted(IDP_COMPARATOR_INSTANCE)
} .collect(Collectors.toList());
this.identities.sort(IDP_COMPARATOR_INSTANCE);
// 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
this.removeLinkPossible = availableIdentities > 1 || user.getFederationLink() != null || AccountFormService.isPasswordSet(session, realm, user); this.removeLinkPossible = availableIdentities.get() > 1 || user.getFederationLink() != null || AccountFormService.isPasswordSet(session, realm, user);
} }
private FederatedIdentityModel getIdentity(Set<FederatedIdentityModel> identities, String providerId) { private FederatedIdentityModel getIdentity(Set<FederatedIdentityModel> identities, String providerId) {

View file

@ -19,6 +19,7 @@ package org.keycloak.forms.account.freemarker.model;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:gerbermichi@me.com">Michael Gerber</a> * @author <a href="mailto:gerbermichi@me.com">Michael Gerber</a>
@ -58,7 +59,7 @@ public class RealmBean {
} }
public Set<String> getSupportedLocales(){ public Set<String> getSupportedLocales(){
return realm.getSupportedLocales(); return realm.getSupportedLocalesStream().collect(Collectors.toSet());
} }
public boolean isEditUsernameAllowed() { public boolean isEditUsernameAllowed() {

View file

@ -398,8 +398,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
if (realm != null) { if (realm != null) {
attributes.put("realm", new RealmBean(realm)); attributes.put("realm", new RealmBean(realm));
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders(); List<IdentityProviderModel> identityProviders = LoginFormsUtil
identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData, context); .filterIdentityProviders(realm.getIdentityProvidersStream(), session, context);
attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUriWithCodeAndClientId)); attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUriWithCodeAndClientId));
attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri)); attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri));

View file

@ -36,6 +36,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* Various util methods, so the logic is not hardcoded in freemarker beans * Various util methods, so the logic is not hardcoded in freemarker beans
@ -78,8 +79,7 @@ public class LoginFormsUtil {
} }
} }
public static List<IdentityProviderModel> filterIdentityProviders(List<IdentityProviderModel> providers, KeycloakSession session, RealmModel realm, public static List<IdentityProviderModel> filterIdentityProviders(Stream<IdentityProviderModel> providers, KeycloakSession session, AuthenticationFlowContext context) {
Map<String, Object> attributes, MultivaluedMap<String, String> formData, AuthenticationFlowContext context) {
if (context != null) { if (context != null) {
AuthenticationSessionModel authSession = context.getAuthenticationSession(); AuthenticationSessionModel authSession = context.getAuthenticationSession();
@ -87,11 +87,11 @@ public class LoginFormsUtil {
if (serializedCtx != null) { if (serializedCtx != null) {
IdentityProviderModel idp = serializedCtx.deserialize(session, authSession).getIdpConfig(); IdentityProviderModel idp = serializedCtx.deserialize(session, authSession).getIdpConfig();
return providers.stream() return providers
.filter(p -> !Objects.equals(p.getAlias(), idp.getAlias())) .filter(p -> !Objects.equals(p.getAlias(), idp.getAlias()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }
return providers; return providers.collect(Collectors.toList());
} }
} }

View file

@ -17,9 +17,10 @@
package org.keycloak.forms.login.freemarker.model; package org.keycloak.forms.login.freemarker.model;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import java.util.Objects;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@ -86,12 +87,8 @@ public class RealmBean {
} }
public boolean isPassword() { public boolean isPassword() {
for (RequiredCredentialModel r : realm.getRequiredCredentials()) { return realm.getRequiredCredentialsStream()
if (r.getType().equals(CredentialRepresentation.PASSWORD)) { .anyMatch(r -> Objects.equals(r.getType(), CredentialRepresentation.PASSWORD));
return true;
}
}
return false;
} }
} }

View file

@ -31,11 +31,8 @@ import javax.crypto.SecretKey;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.Comparator; import java.util.*;
import java.util.HashMap; import java.util.stream.Collectors;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -246,22 +243,22 @@ public class DefaultKeyManager implements KeyManager {
private List<KeyProvider> getProviders(RealmModel realm) { private List<KeyProvider> getProviders(RealmModel realm) {
List<KeyProvider> providers = providersMap.get(realm.getId()); List<KeyProvider> providers = providersMap.get(realm.getId());
if (providers == null) { if (providers == null) {
providers = new LinkedList<>(); providers = realm.getComponentsStream(realm.getId(), KeyProvider.class.getName())
.sorted(new ProviderComparator())
List<ComponentModel> components = new LinkedList<>(realm.getComponents(realm.getId(), KeyProvider.class.getName())); .map(c -> {
components.sort(new ProviderComparator()); try {
ProviderFactory<KeyProvider> f = session.getKeycloakSessionFactory().getProviderFactory(KeyProvider.class, c.getProviderId());
for (ComponentModel c : components) { KeyProviderFactory factory = (KeyProviderFactory) f;
try { KeyProvider provider = factory.create(session, c);
ProviderFactory<KeyProvider> f = session.getKeycloakSessionFactory().getProviderFactory(KeyProvider.class, c.getProviderId()); session.enlistForClose(provider);
KeyProviderFactory factory = (KeyProviderFactory) f; return provider;
KeyProvider provider = factory.create(session, c); } catch (Throwable t) {
session.enlistForClose(provider); logger.errorv(t, "Failed to load provider {0}", c.getId());
providers.add(provider); return null;
} catch (Throwable t) { }
logger.errorv(t, "Failed to load provider {0}", c.getId()); })
} .filter(Objects::nonNull)
} .collect(Collectors.toList());
providersMap.put(realm.getId(), providers); providersMap.put(realm.getId(), providers);
} }

View file

@ -20,17 +20,13 @@ import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.util.CookieHelper;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.storage.ReadOnlyException;
import javax.ws.rs.core.Cookie; import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriInfo;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.stream.Collectors;
public class DefaultLocaleSelectorProvider implements LocaleSelectorProvider { public class DefaultLocaleSelectorProvider implements LocaleSelectorProvider {
@ -168,19 +164,19 @@ public class DefaultLocaleSelectorProvider implements LocaleSelectorProvider {
} }
private Locale findLocale(RealmModel realm, String... localeStrings) { private Locale findLocale(RealmModel realm, String... localeStrings) {
Set<String> supportedLocales = realm.getSupportedLocales(); List<Locale> supportedLocales = realm.getSupportedLocalesStream()
.map(Locale::forLanguageTag).collect(Collectors.toList());
for (String localeString : localeStrings) { for (String localeString : localeStrings) {
if (localeString != null) { if (localeString != null) {
Locale result = null; Locale result = null;
Locale search = Locale.forLanguageTag(localeString); Locale search = Locale.forLanguageTag(localeString);
for (String languageTag : supportedLocales) { for (Locale supportedLocale : supportedLocales) {
Locale locale = Locale.forLanguageTag(languageTag); if (supportedLocale.getLanguage().equals(search.getLanguage())) {
if (locale.getLanguage().equals(search.getLanguage())) { if (search.getCountry().equals("") ^ supportedLocale.getCountry().equals("") && result == null) {
if (search.getCountry().equals("") ^ locale.getCountry().equals("") && result == null) { result = supportedLocale;
result = locale;
} }
if (locale.getCountry().equals(search.getCountry())) { if (supportedLocale.getCountry().equals(search.getCountry())) {
return locale; return supportedLocale;
} }
} }
} }

View file

@ -47,6 +47,8 @@ import java.net.URI;
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.Objects;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -119,13 +121,10 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
config.setClaimTypesSupported(DEFAULT_CLAIM_TYPES_SUPPORTED); config.setClaimTypesSupported(DEFAULT_CLAIM_TYPES_SUPPORTED);
config.setClaimsParameterSupported(true); config.setClaimsParameterSupported(true);
List<ClientScopeModel> scopes = realm.getClientScopes(); List<String> scopeNames = realm.getClientScopesStream()
List<String> scopeNames = new LinkedList<>(); .filter(clientScope -> Objects.equals(OIDCLoginProtocol.LOGIN_PROTOCOL, clientScope.getProtocol()))
for (ClientScopeModel clientScope : scopes) { .map(ClientScopeModel::getName)
if (OIDCLoginProtocol.LOGIN_PROTOCOL.equals(clientScope.getProtocol())) { .collect(Collectors.toList());
scopeNames.add(clientScope.getName());
}
}
scopeNames.add(0, OAuth2Constants.SCOPE_OPENID); scopeNames.add(0, OAuth2Constants.SCOPE_OPENID);
config.setScopesSupported(scopeNames); config.setScopesSupported(scopeNames);

View file

@ -25,8 +25,6 @@ import org.keycloak.TokenCategory;
import org.keycloak.TokenVerifier; import org.keycloak.TokenVerifier;
import org.keycloak.broker.oidc.OIDCIdentityProvider; import org.keycloak.broker.oidc.OIDCIdentityProvider;
import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
@ -44,7 +42,6 @@ import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.ClientSessionContext; import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -78,7 +75,6 @@ import org.keycloak.services.util.MtlsHoKTokenUtil;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.util.TokenUtil; import org.keycloak.util.TokenUtil;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@ -1092,13 +1088,14 @@ public class TokenManager {
} }
LogoutToken logoutToken = logoutTokenOptional.get(); LogoutToken logoutToken = logoutTokenOptional.get();
List<OIDCIdentityProvider> identityProviders = getOIDCIdentityProviders(realm, session); List<OIDCIdentityProvider> identityProviders = getOIDCIdentityProviders(realm, session).collect(Collectors.toList());
if (identityProviders.isEmpty()) { if (identityProviders.isEmpty()) {
return LogoutTokenValidationCode.COULD_NOT_FIND_IDP; return LogoutTokenValidationCode.COULD_NOT_FIND_IDP;
} }
List<OIDCIdentityProvider> validOidcIdentityProviders = validateLogoutTokenAgainstIdpProvider(identityProviders, encodedLogoutToken, logoutToken); Stream<OIDCIdentityProvider> validOidcIdentityProviders =
if (validOidcIdentityProviders.isEmpty()) { validateLogoutTokenAgainstIdpProvider(identityProviders.stream(), encodedLogoutToken, logoutToken);
if (validOidcIdentityProviders.count() == 0) {
return LogoutTokenValidationCode.TOKEN_VERIFICATION_WITH_IDP_FAILED; return LogoutTokenValidationCode.TOKEN_VERIFICATION_WITH_IDP_FAILED;
} }
@ -1135,43 +1132,37 @@ public class TokenManager {
} }
public List<OIDCIdentityProvider> getValidOIDCIdentityProvidersForBackchannelLogout(RealmModel realm, KeycloakSession session, String encodedLogoutToken, LogoutToken logoutToken) { public Stream<OIDCIdentityProvider> getValidOIDCIdentityProvidersForBackchannelLogout(RealmModel realm, KeycloakSession session, String encodedLogoutToken, LogoutToken logoutToken) {
List<OIDCIdentityProvider> identityProviders = getOIDCIdentityProviders(realm, session); return validateLogoutTokenAgainstIdpProvider(getOIDCIdentityProviders(realm, session), encodedLogoutToken, logoutToken);
return validateLogoutTokenAgainstIdpProvider(identityProviders, encodedLogoutToken, logoutToken);
} }
public List<OIDCIdentityProvider> validateLogoutTokenAgainstIdpProvider(List<OIDCIdentityProvider> oidcIdps, String encodedLogoutToken, LogoutToken logoutToken) { public Stream<OIDCIdentityProvider> validateLogoutTokenAgainstIdpProvider(Stream<OIDCIdentityProvider> oidcIdps, String encodedLogoutToken, LogoutToken logoutToken) {
List<OIDCIdentityProvider> validIdps = new ArrayList<>(); return oidcIdps
for (OIDCIdentityProvider oidcIdp : oidcIdps) { .filter(oidcIdp -> oidcIdp.getConfig().getIssuer() != null)
if (oidcIdp.getConfig().getIssuer() != null) { .filter(oidcIdp -> oidcIdp.isIssuer(logoutToken.getIssuer(), null))
if (oidcIdp.isIssuer(logoutToken.getIssuer(), null)) { .filter(oidcIdp -> {
try { try {
oidcIdp.validateToken(encodedLogoutToken); oidcIdp.validateToken(encodedLogoutToken);
validIdps.add(oidcIdp); return true;
} catch (IdentityBrokerException e) { } catch (IdentityBrokerException e) {
logger.debugf("LogoutToken verification with identity provider failed", e.getMessage()); logger.debugf("LogoutToken verification with identity provider failed", e.getMessage());
} return false;
} }
} });
}
return validIdps;
} }
private List<OIDCIdentityProvider> getOIDCIdentityProviders(RealmModel realm, KeycloakSession session) { private Stream<OIDCIdentityProvider> getOIDCIdentityProviders(RealmModel realm, KeycloakSession session) {
List<OIDCIdentityProvider> availableProviders = new ArrayList<>();
try { try {
for (IdentityProviderModel idpModel : realm.getIdentityProviders()) { return realm.getIdentityProvidersStream()
IdentityProviderFactory factory = IdentityBrokerService.getIdentityProviderFactory(session, idpModel); .map(idpModel ->
IdentityProvider identityProvider = factory.create(session, idpModel); IdentityBrokerService.getIdentityProviderFactory(session, idpModel).create(session, idpModel))
if (identityProvider instanceof OIDCIdentityProvider) { .filter(OIDCIdentityProvider.class::isInstance)
availableProviders.add(((OIDCIdentityProvider) identityProvider)); .map(OIDCIdentityProvider.class::cast);
}
}
} catch (IdentityBrokerException e) { } catch (IdentityBrokerException e) {
logger.warnf("LogoutToken verification with identity provider failed", e.getMessage()); logger.warnf("LogoutToken verification with identity provider failed", e.getMessage());
} }
return availableProviders; return Stream.empty();
} }
private boolean checkLogoutTokenForEvents(LogoutToken logoutToken) { private boolean checkLogoutTokenForEvents(LogoutToken logoutToken) {

View file

@ -46,7 +46,6 @@ import org.keycloak.representations.RefreshToken;
import org.keycloak.services.ErrorPage; import org.keycloak.services.ErrorPage;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
import org.keycloak.services.clientpolicy.LogoutRequestContext; import org.keycloak.services.clientpolicy.LogoutRequestContext;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.managers.UserSessionManager;
@ -63,7 +62,8 @@ import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -270,10 +270,9 @@ public class LogoutEndpoint {
LogoutToken logoutToken = tokenManager.toLogoutToken(encodedLogoutToken).get(); LogoutToken logoutToken = tokenManager.toLogoutToken(encodedLogoutToken).get();
List<String> identityProviderAliases = tokenManager.getValidOIDCIdentityProvidersForBackchannelLogout(realm, Stream<String> identityProviderAliases = tokenManager.getValidOIDCIdentityProvidersForBackchannelLogout(realm,
session, encodedLogoutToken, logoutToken).stream() session, encodedLogoutToken, logoutToken)
.map(idp -> idp.getConfig().getAlias()) .map(idp -> idp.getConfig().getAlias());
.collect(Collectors.toList());
boolean logoutOfflineSessions = Boolean.parseBoolean(logoutToken.getEvents() boolean logoutOfflineSessions = Boolean.parseBoolean(logoutToken.getEvents()
.getOrDefault(TokenUtil.TOKEN_BACKCHANNEL_LOGOUT_EVENT_REVOKE_OFFLINE_TOKENS, false).toString()); .getOrDefault(TokenUtil.TOKEN_BACKCHANNEL_LOGOUT_EVENT_REVOKE_OFFLINE_TOKENS, false).toString());
@ -313,10 +312,10 @@ public class LogoutEndpoint {
} }
private BackchannelLogoutResponse backchannelLogoutWithSessionId(String sessionId, private BackchannelLogoutResponse backchannelLogoutWithSessionId(String sessionId,
List<String> identityProviderAliases, boolean logoutOfflineSessions) { Stream<String> identityProviderAliases, boolean logoutOfflineSessions) {
BackchannelLogoutResponse backchannelLogoutResponse = new BackchannelLogoutResponse(); AtomicReference<BackchannelLogoutResponse> backchannelLogoutResponse = new AtomicReference<>(new BackchannelLogoutResponse());
backchannelLogoutResponse.setLocalLogoutSucceeded(true); backchannelLogoutResponse.get().setLocalLogoutSucceeded(true);
for (String identityProviderAlias : identityProviderAliases) { identityProviderAliases.forEach(identityProviderAlias -> {
UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm, UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm,
identityProviderAlias + "." + sessionId); identityProviderAlias + "." + sessionId);
@ -325,11 +324,11 @@ public class LogoutEndpoint {
} }
if (userSession != null) { if (userSession != null) {
backchannelLogoutResponse = logoutUserSession(userSession); backchannelLogoutResponse.set(logoutUserSession(userSession));
} }
} });
return backchannelLogoutResponse; return backchannelLogoutResponse.get();
} }
private void logoutOfflineUserSession(String brokerSessionId) { private void logoutOfflineUserSession(String brokerSessionId) {
@ -341,10 +340,11 @@ public class LogoutEndpoint {
} }
private BackchannelLogoutResponse backchannelLogoutFederatedUserId(String federatedUserId, private BackchannelLogoutResponse backchannelLogoutFederatedUserId(String federatedUserId,
List<String> identityProviderAliases, boolean logoutOfflineSessions) { Stream<String> identityProviderAliases,
boolean logoutOfflineSessions) {
BackchannelLogoutResponse backchannelLogoutResponse = new BackchannelLogoutResponse(); BackchannelLogoutResponse backchannelLogoutResponse = new BackchannelLogoutResponse();
backchannelLogoutResponse.setLocalLogoutSucceeded(true); backchannelLogoutResponse.setLocalLogoutSucceeded(true);
for (String identityProviderAlias : identityProviderAliases) { identityProviderAliases.forEach(identityProviderAlias -> {
List<UserSessionModel> userSessions = session.sessions().getUserSessionByBrokerUserId(realm, List<UserSessionModel> userSessions = session.sessions().getUserSessionByBrokerUserId(realm,
identityProviderAlias + "." + federatedUserId); identityProviderAlias + "." + federatedUserId);
@ -360,7 +360,7 @@ public class LogoutEndpoint {
userBackchannelLogoutResponse.getClientResponses() userBackchannelLogoutResponse.getClientResponses()
.forEach(backchannelLogoutResponse::addClientResponses); .forEach(backchannelLogoutResponse::addClientResponses);
} }
} });
return backchannelLogoutResponse; return backchannelLogoutResponse;
} }

View file

@ -127,8 +127,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID; import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID;
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME; import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME;
@ -1051,33 +1053,34 @@ public class TokenEndpoint {
} }
public Response exchangeExternalToken(String issuer, String subjectToken) { public Response exchangeExternalToken(String issuer, String subjectToken) {
ExchangeExternalToken externalIdp = null; AtomicReference<ExchangeExternalToken> externalIdp = new AtomicReference<>(null);
IdentityProviderModel externalIdpModel = null; AtomicReference<IdentityProviderModel> externalIdpModel = new AtomicReference<>(null);
for (IdentityProviderModel idpModel : realm.getIdentityProviders()) { realm.getIdentityProvidersStream().filter(idpModel -> {
IdentityProviderFactory factory = IdentityBrokerService.getIdentityProviderFactory(session, idpModel); IdentityProviderFactory factory = IdentityBrokerService.getIdentityProviderFactory(session, idpModel);
IdentityProvider idp = factory.create(session, idpModel); IdentityProvider idp = factory.create(session, idpModel);
if (idp instanceof ExchangeExternalToken) { if (idp instanceof ExchangeExternalToken) {
ExchangeExternalToken external = (ExchangeExternalToken) idp; ExchangeExternalToken external = (ExchangeExternalToken) idp;
if (idpModel.getAlias().equals(issuer) || external.isIssuer(issuer, formParams)) { if (idpModel.getAlias().equals(issuer) || external.isIssuer(issuer, formParams)) {
externalIdp = external; externalIdp.set(external);
externalIdpModel = idpModel; externalIdpModel.set(idpModel);
break; return true;
} }
} }
} return false;
}).findFirst();
if (externalIdp == null) { if (externalIdp.get() == null) {
event.error(Errors.INVALID_ISSUER); event.error(Errors.INVALID_ISSUER);
throw new CorsErrorResponseException(cors, Errors.INVALID_ISSUER, "Invalid " + OAuth2Constants.SUBJECT_ISSUER + " parameter", Response.Status.BAD_REQUEST); throw new CorsErrorResponseException(cors, Errors.INVALID_ISSUER, "Invalid " + OAuth2Constants.SUBJECT_ISSUER + " parameter", Response.Status.BAD_REQUEST);
} }
if (!AdminPermissions.management(session, realm).idps().canExchangeTo(client, externalIdpModel)) { if (!AdminPermissions.management(session, realm).idps().canExchangeTo(client, externalIdpModel.get())) {
event.detail(Details.REASON, "client not allowed to exchange subject_issuer"); event.detail(Details.REASON, "client not allowed to exchange subject_issuer");
event.error(Errors.NOT_ALLOWED); event.error(Errors.NOT_ALLOWED);
throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN); throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
} }
BrokeredIdentityContext context = externalIdp.exchangeExternal(event, formParams); BrokeredIdentityContext context = externalIdp.get().exchangeExternal(event, formParams);
if (context == null) { if (context == null) {
event.error(Errors.INVALID_ISSUER); event.error(Errors.INVALID_ISSUER);
throw new CorsErrorResponseException(cors, Errors.INVALID_ISSUER, "Invalid " + OAuth2Constants.SUBJECT_ISSUER + " parameter", Response.Status.BAD_REQUEST); throw new CorsErrorResponseException(cors, Errors.INVALID_ISSUER, "Invalid " + OAuth2Constants.SUBJECT_ISSUER + " parameter", Response.Status.BAD_REQUEST);
@ -1086,10 +1089,10 @@ public class TokenEndpoint {
UserModel user = importUserFromExternalIdentity(context); UserModel user = importUserFromExternalIdentity(context);
UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "external-exchange", false, null, null); UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "external-exchange", false, null, null);
externalIdp.exchangeExternalComplete(userSession, context, formParams); externalIdp.get().exchangeExternalComplete(userSession, context, formParams);
// this must exist so that we can obtain access token from user session if idp's store tokens is off // this must exist so that we can obtain access token from user session if idp's store tokens is off
userSession.setNote(IdentityProvider.EXTERNAL_IDENTITY_PROVIDER, externalIdpModel.getAlias()); userSession.setNote(IdentityProvider.EXTERNAL_IDENTITY_PROVIDER, externalIdpModel.get().getAlias());
userSession.setNote(IdentityProvider.FEDERATED_ACCESS_TOKEN, subjectToken); userSession.setNote(IdentityProvider.FEDERATED_ACCESS_TOKEN, subjectToken);
return exchangeClientToClient(user, userSession); return exchangeClientToClient(user, userSession);
@ -1106,13 +1109,12 @@ public class TokenEndpoint {
//session.getContext().setClient(authenticationSession.getClient()); //session.getContext().setClient(authenticationSession.getClient());
context.getIdp().preprocessFederatedIdentity(session, realm, context); context.getIdp().preprocessFederatedIdentity(session, realm, context);
Set<IdentityProviderMapperModel> mappers = realm.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias()); Set<IdentityProviderMapperModel> mappers = realm.getIdentityProviderMappersByAliasStream(context.getIdpConfig().getAlias())
if (mappers != null) { .collect(Collectors.toSet());
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (IdentityProviderMapperModel mapper : mappers) { for (IdentityProviderMapperModel mapper : mappers) {
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
target.preprocessFederatedIdentity(session, realm, mapper, context); target.preprocessFederatedIdentity(session, realm, mapper, context);
}
} }
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(), FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(),
@ -1163,12 +1165,10 @@ public class TokenEndpoint {
session.users().addFederatedIdentity(realm, user, federatedIdentityModel); session.users().addFederatedIdentity(realm, user, federatedIdentityModel);
context.getIdp().importNewUser(session, realm, user, context); context.getIdp().importNewUser(session, realm, user, context);
if (mappers != null) {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); for (IdentityProviderMapperModel mapper : mappers) {
for (IdentityProviderMapperModel mapper : mappers) { IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); target.importNewUser(session, realm, user, mapper, context);
target.importNewUser(session, realm, user, mapper, context);
}
} }
if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(user.getEmail())) { if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(user.getEmail())) {
@ -1188,12 +1188,10 @@ public class TokenEndpoint {
} }
context.getIdp().updateBrokeredUser(session, realm, user, context); context.getIdp().updateBrokeredUser(session, realm, user, context);
if (mappers != null) {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); for (IdentityProviderMapperModel mapper : mappers) {
for (IdentityProviderMapperModel mapper : mappers) { IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); IdentityProviderMapperSyncModeDelegate.delegateUpdateBrokeredUser(session, realm, user, mapper, context, target);
IdentityProviderMapperSyncModeDelegate.delegateUpdateBrokeredUser(session, realm, user, mapper, context, target);
}
} }
} }
return user; return user;

View file

@ -22,7 +22,6 @@ import org.keycloak.authentication.ClientAuthenticator;
import org.keycloak.authentication.ClientAuthenticatorFactory; import org.keycloak.authentication.ClientAuthenticatorFactory;
import org.keycloak.authorization.admin.AuthorizationService; import org.keycloak.authorization.admin.AuthorizationService;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
@ -111,15 +110,15 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
// Check if there is client scope with audience protocol mapper created for particular client. If yes, admin wants verifying token audience // Check if there is client scope with audience protocol mapper created for particular client. If yes, admin wants verifying token audience
String clientId = client.getClientId(); String clientId = client.getClientId();
for (ClientScopeModel clientScope : client.getRealm().getClientScopes()) { return client.getRealm().getClientScopesStream().anyMatch(clientScope -> {
for (ProtocolMapperModel protocolMapper : clientScope.getProtocolMappers()) { for (ProtocolMapperModel protocolMapper : clientScope.getProtocolMappers()) {
if (AudienceProtocolMapper.PROVIDER_ID.equals(protocolMapper.getProtocolMapper()) && (clientId.equals(protocolMapper.getConfig().get(AudienceProtocolMapper.INCLUDED_CLIENT_AUDIENCE)))) { if (AudienceProtocolMapper.PROVIDER_ID.equals(protocolMapper.getProtocolMapper()) &&
(clientId.equals(protocolMapper.getConfig().get(AudienceProtocolMapper.INCLUDED_CLIENT_AUDIENCE)))) {
return true; return true;
} }
} }
} return false;
});
return false;
} }

View file

@ -45,6 +45,7 @@ import javax.xml.soap.SOAPHeaderElement;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -149,12 +150,9 @@ public class SamlEcpProfileService extends SamlService {
@Override @Override
protected AuthenticationFlowModel getAuthenticationFlow(AuthenticationSessionModel authSession) { protected AuthenticationFlowModel getAuthenticationFlow(AuthenticationSessionModel authSession) {
for (AuthenticationFlowModel flowModel : realm.getAuthenticationFlows()) { return realm.getAuthenticationFlowsStream()
if (flowModel.getAlias().equals(DefaultAuthenticationFlows.SAML_ECP_FLOW)) { .filter(flow -> Objects.equals(flow.getAlias(), DefaultAuthenticationFlows.SAML_ECP_FLOW))
return flowModel; .findFirst()
} .orElseThrow(() -> new RuntimeException("Could not resolve authentication flow for SAML ECP Profile."));
}
throw new RuntimeException("Could not resolve authentication flow for SAML ECP Profile.");
} }
} }

View file

@ -17,20 +17,13 @@
package org.keycloak.services.clientpolicy; package org.keycloak.services.clientpolicy;
import java.util.HashMap; import java.util.*;
import java.util.LinkedList; import java.util.stream.Collectors;
import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyManager;
import org.keycloak.services.clientpolicy.ClientPolicyProvider;
import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider; import org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider;
import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider; import org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider;
@ -67,18 +60,20 @@ public class DefaultClientPolicyManager implements ClientPolicyManager {
private List<ClientPolicyProvider> getProviders(RealmModel realm) { private List<ClientPolicyProvider> getProviders(RealmModel realm) {
List<ClientPolicyProvider> providers = providersMap.get(realm.getId()); List<ClientPolicyProvider> providers = providersMap.get(realm.getId());
if (providers == null) { if (providers == null) {
providers = new LinkedList<>(); providers = realm.getComponentsStream(realm.getId(), ClientPolicyProvider.class.getName())
List<ComponentModel> policyModels = realm.getComponents(realm.getId(), ClientPolicyProvider.class.getName()); .map(policyModel -> {
for (ComponentModel policyModel : policyModels) { try {
try { ClientPolicyProvider policy = session.getProvider(ClientPolicyProvider.class, policyModel);
ClientPolicyProvider policy = session.getProvider(ClientPolicyProvider.class, policyModel); ClientPolicyLogger.logv(logger, "Loaded Policy Name = {0}", policyModel.getName());
ClientPolicyLogger.logv(logger, "Loaded Policy Name = {0}", policyModel.getName()); session.enlistForClose(policy);
session.enlistForClose(policy); return policy;
providers.add(policy); } catch (Throwable t) {
} catch (Throwable t) { logger.errorv(t, "Failed to load provider {0}", policyModel.getId());
logger.errorv(t, "Failed to load provider {0}", policyModel.getId()); return null;
} }
} })
.filter(Objects::nonNull)
.collect(Collectors.toList());
providersMap.put(realm.getId(), providers); providersMap.put(realm.getId(), providers);
} else { } else {
ClientPolicyLogger.log(logger, "Use cached policies."); ClientPolicyLogger.log(logger, "Use cached policies.");

View file

@ -22,7 +22,7 @@ import org.keycloak.component.ComponentModel;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class ClientRegistrationPolicyException extends Exception { public class ClientRegistrationPolicyException extends RuntimeException {
private ComponentModel policyModel; private ComponentModel policyModel;

View file

@ -17,9 +17,7 @@
package org.keycloak.services.clientregistration.policy; package org.keycloak.services.clientregistration.policy;
import java.util.List; import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
@ -97,36 +95,34 @@ public class ClientRegistrationPolicyManager {
private static void triggerPolicies(KeycloakSession session, ClientRegistrationProvider provider, RegistrationAuth authType, String opDescription, ClientRegOperation op) throws ClientRegistrationPolicyException { private static void triggerPolicies(KeycloakSession session, ClientRegistrationProvider provider, RegistrationAuth authType,
String opDescription, ClientRegOperation op) throws ClientRegistrationPolicyException {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
String policyTypeKey = getComponentTypeKey(authType); String policyTypeKey = getComponentTypeKey(authType);
List<ComponentModel> policyModels = realm.getComponents(realm.getId(), ClientRegistrationPolicy.class.getName()); realm.getComponentsStream(realm.getId(), ClientRegistrationPolicy.class.getName())
.filter(componentModel -> Objects.equals(componentModel.getSubType(), policyTypeKey))
.forEach(policyModel -> runPolicy(policyModel, session, provider, opDescription, op));
}
policyModels = policyModels.stream().filter((ComponentModel model) -> { private static void runPolicy(ComponentModel policyModel, KeycloakSession session, ClientRegistrationProvider provider,
String opDescription, ClientRegOperation op) throws ClientRegistrationPolicyException {
ClientRegistrationPolicy policy = session.getProvider(ClientRegistrationPolicy.class, policyModel);
if (policy == null) {
throw new ClientRegistrationPolicyException("Policy of type '" + policyModel.getProviderId() + "' not found");
}
return policyTypeKey.equals(model.getSubType()); if (logger.isTraceEnabled()) {
logger.tracef("Running policy '%s' %s", policyModel.getName(), opDescription);
}
}).collect(Collectors.toList()); try {
op.run(policy);
for (ComponentModel policyModel : policyModels) { } catch (ClientRegistrationPolicyException crpe) {
ClientRegistrationPolicy policy = session.getProvider(ClientRegistrationPolicy.class, policyModel); provider.getEvent().detail(Details.CLIENT_REGISTRATION_POLICY, policyModel.getName());
if (policy == null) { crpe.setPolicyModel(policyModel);
throw new ClientRegistrationPolicyException("Policy of type '" + policyModel.getProviderId() + "' not found"); ServicesLogger.LOGGER.clientRegistrationRequestRejected(opDescription, crpe.getMessage());
} throw crpe;
if (logger.isTraceEnabled()) {
logger.tracef("Running policy '%s' %s", policyModel.getName(), opDescription);
}
try {
op.run(policy);
} catch (ClientRegistrationPolicyException crpe) {
provider.getEvent().detail(Details.CLIENT_REGISTRATION_POLICY, policyModel.getName());
crpe.setPolicyModel(policyModel);
ServicesLogger.LOGGER.clientRegistrationRequestRejected(opDescription, crpe.getMessage());
throw crpe;
}
} }
} }

View file

@ -19,7 +19,6 @@ package org.keycloak.services.clientregistration.policy;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -57,10 +56,9 @@ public class DefaultClientRegistrationPolicies {
public static void addDefaultPolicies(RealmModel realm) { public static void addDefaultPolicies(RealmModel realm) {
String anonPolicyType = ClientRegistrationPolicyManager.getComponentTypeKey(RegistrationAuth.ANONYMOUS); String anonPolicyType = ClientRegistrationPolicyManager.getComponentTypeKey(RegistrationAuth.ANONYMOUS);
String authPolicyType = ClientRegistrationPolicyManager.getComponentTypeKey(RegistrationAuth.AUTHENTICATED); String authPolicyType = ClientRegistrationPolicyManager.getComponentTypeKey(RegistrationAuth.AUTHENTICATED);
List<ComponentModel> policies = realm.getComponents(realm.getId(), ClientRegistrationPolicy.class.getName());
// Probably an issue if admin removes all policies intentionally... // Probably an issue if admin removes all policies intentionally...
if (policies == null ||policies.isEmpty()) { if (realm.getComponentsStream(realm.getId(), ClientRegistrationPolicy.class.getName()).count() == 0) {
addAnonymousPolicies(realm, anonPolicyType); addAnonymousPolicies(realm, anonPolicyType);
addAuthPolicies(realm, authPolicyType); addAuthPolicies(realm, authPolicyType);
} }

View file

@ -124,13 +124,7 @@ public class ClientScopesClientRegistrationPolicy implements ClientRegistrationP
// If allowDefaultScopes, then realm default scopes are allowed as default scopes (+ optional scopes are allowed as optional scopes) // If allowDefaultScopes, then realm default scopes are allowed as default scopes (+ optional scopes are allowed as optional scopes)
boolean allowDefaultScopes = componentModel.get(ClientScopesClientRegistrationPolicyFactory.ALLOW_DEFAULT_SCOPES, true); boolean allowDefaultScopes = componentModel.get(ClientScopesClientRegistrationPolicyFactory.ALLOW_DEFAULT_SCOPES, true);
if (allowDefaultScopes) { if (allowDefaultScopes) {
List<String> scopeNames = realm.getDefaultClientScopes(defaultScopes).stream().map((ClientScopeModel clientScope) -> { allAllowed.addAll(realm.getDefaultClientScopesStream(defaultScopes).map(ClientScopeModel::getName).collect(Collectors.toList()));
return clientScope.getName();
}).collect(Collectors.toList());
allAllowed.addAll(scopeNames);
} }
return allAllowed; return allAllowed;

View file

@ -87,13 +87,7 @@ public class ClientScopesClientRegistrationPolicyFactory extends AbstractClientR
if (realm == null) { if (realm == null) {
return Collections.emptyList(); return Collections.emptyList();
} else { } else {
List<ClientScopeModel> clientScopes = realm.getClientScopes(); return realm.getClientScopesStream().map(ClientScopeModel::getName).collect(Collectors.toList());
return clientScopes.stream().map((ClientScopeModel clientScope) -> {
return clientScope.getName();
}).collect(Collectors.toList());
} }
} }

View file

@ -884,7 +884,7 @@ public class AuthenticationManager {
public static Response nextActionAfterAuthentication(KeycloakSession session, AuthenticationSessionModel authSession, public static Response nextActionAfterAuthentication(KeycloakSession session, AuthenticationSessionModel authSession,
ClientConnection clientConnection, ClientConnection clientConnection,
HttpRequest request, UriInfo uriInfo, EventBuilder event) { HttpRequest request, UriInfo uriInfo, EventBuilder event) {
Response requiredAction = actionRequired(session, authSession, clientConnection, request, uriInfo, event); Response requiredAction = actionRequired(session, authSession, request, event);
if (requiredAction != null) return requiredAction; if (requiredAction != null) return requiredAction;
return finishedRequiredActions(session, authSession, null, clientConnection, request, uriInfo, event); return finishedRequiredActions(session, authSession, null, clientConnection, request, uriInfo, event);
@ -962,13 +962,12 @@ public class AuthenticationManager {
// Return null if action is not required. Or the name of the requiredAction in case it is required. // Return null if action is not required. Or the name of the requiredAction in case it is required.
public static String nextRequiredAction(final KeycloakSession session, final AuthenticationSessionModel authSession, public static String nextRequiredAction(final KeycloakSession session, final AuthenticationSessionModel authSession,
final ClientConnection clientConnection, final HttpRequest request, final EventBuilder event) {
final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
final RealmModel realm = authSession.getRealm(); final RealmModel realm = authSession.getRealm();
final UserModel user = authSession.getAuthenticatedUser(); final UserModel user = authSession.getAuthenticatedUser();
final ClientModel client = authSession.getClient(); final ClientModel client = authSession.getClient();
evaluateRequiredActionTriggers(session, authSession, clientConnection, request, uriInfo, event, realm, user); evaluateRequiredActionTriggers(session, authSession, request, event, realm, user);
if (!user.getRequiredActions().isEmpty()) { if (!user.getRequiredActions().isEmpty()) {
return user.getRequiredActions().iterator().next(); return user.getRequiredActions().iterator().next();
@ -1018,14 +1017,12 @@ public class AuthenticationManager {
public static Response actionRequired(final KeycloakSession session, final AuthenticationSessionModel authSession, public static Response actionRequired(final KeycloakSession session, final AuthenticationSessionModel authSession,
final ClientConnection clientConnection, final HttpRequest request, final EventBuilder event) {
final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
final RealmModel realm = authSession.getRealm(); final RealmModel realm = authSession.getRealm();
final UserModel user = authSession.getAuthenticatedUser(); final UserModel user = authSession.getAuthenticatedUser();
final ClientModel client = authSession.getClient(); final ClientModel client = authSession.getClient();
evaluateRequiredActionTriggers(session, authSession, clientConnection, request, uriInfo, event, realm, user); evaluateRequiredActionTriggers(session, authSession, request, event, realm, user);
logger.debugv("processAccessCode: go to oauth page?: {0}", client.isConsentRequired()); logger.debugv("processAccessCode: go to oauth page?: {0}", client.isConsentRequired());
@ -1142,10 +1139,11 @@ public class AuthenticationManager {
String kcAction = authSession.getClientNote(Constants.KC_ACTION); String kcAction = authSession.getClientNote(Constants.KC_ACTION);
if (kcAction != null) { if (kcAction != null) {
for (RequiredActionProviderModel m : realm.getRequiredActionProviders()) { Optional<RequiredActionProviderModel> requiredAction = realm.getRequiredActionProvidersStream()
if (m.getProviderId().equals(kcAction)) { .filter(m -> Objects.equals(m.getProviderId(), kcAction))
return executeAction(session, authSession, m, request, event, realm, user, true); .findFirst();
} if (requiredAction.isPresent()) {
return executeAction(session, authSession, requiredAction.get(), request, event, realm, user, true);
} }
logger.debugv("Requested action {0} not configured for realm", kcAction); logger.debugv("Requested action {0} not configured for realm", kcAction);
@ -1230,40 +1228,53 @@ public class AuthenticationManager {
return actions; return actions;
} }
public static void evaluateRequiredActionTriggers(final KeycloakSession session, final AuthenticationSessionModel authSession, final ClientConnection clientConnection, final HttpRequest request, final UriInfo uriInfo, final EventBuilder event, final RealmModel realm, final UserModel user) { public static void evaluateRequiredActionTriggers(final KeycloakSession session, final AuthenticationSessionModel authSession,
final HttpRequest request, final EventBuilder event,
final RealmModel realm, final UserModel user) {
// see if any required actions need triggering, i.e. an expired password // see if any required actions need triggering, i.e. an expired password
for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) { realm.getRequiredActionProvidersStream()
if (!model.isEnabled()) continue; .filter(RequiredActionProviderModel::isEnabled)
RequiredActionFactory factory = (RequiredActionFactory)session.getKeycloakSessionFactory().getProviderFactory(RequiredActionProvider.class, model.getProviderId()); .map(model -> toRequiredActionFactory(session, model))
if (factory == null) { .forEachOrdered(f -> evaluateRequiredAction(session, authSession, request, event, realm, user, f));
throw new RuntimeException("Unable to find factory for Required Action: " + model.getProviderId() + " did you forget to declare it in a META-INF/services file?"); }
private static void evaluateRequiredAction(final KeycloakSession session, final AuthenticationSessionModel authSession,
final HttpRequest request, final EventBuilder event, final RealmModel realm,
final UserModel user, RequiredActionFactory factory) {
RequiredActionProvider provider = factory.create(session);
RequiredActionContextResult result = new RequiredActionContextResult(authSession, realm, event, session, request, user, factory) {
@Override
public void challenge(Response response) {
throw new RuntimeException("Not allowed to call challenge() within evaluateTriggers()");
} }
RequiredActionProvider provider = factory.create(session);
RequiredActionContextResult result = new RequiredActionContextResult(authSession, realm, event, session, request, user, factory) {
@Override
public void challenge(Response response) {
throw new RuntimeException("Not allowed to call challenge() within evaluateTriggers()");
}
@Override @Override
public void failure() { public void failure() {
throw new RuntimeException("Not allowed to call failure() within evaluateTriggers()"); throw new RuntimeException("Not allowed to call failure() within evaluateTriggers()");
} }
@Override @Override
public void success() { public void success() {
throw new RuntimeException("Not allowed to call success() within evaluateTriggers()"); throw new RuntimeException("Not allowed to call success() within evaluateTriggers()");
} }
@Override @Override
public void ignore() { public void ignore() {
throw new RuntimeException("Not allowed to call ignore() within evaluateTriggers()"); throw new RuntimeException("Not allowed to call ignore() within evaluateTriggers()");
} }
}; };
provider.evaluateTriggers(result); provider.evaluateTriggers(result);
}
private static RequiredActionFactory toRequiredActionFactory(KeycloakSession session, RequiredActionProviderModel model) {
RequiredActionFactory factory = (RequiredActionFactory) session.getKeycloakSessionFactory()
.getProviderFactory(RequiredActionProvider.class, model.getProviderId());
if (factory == null) {
throw new RuntimeException("Unable to find factory for Required Action: "
+ model.getProviderId() + " did you forget to declare it in a META-INF/services file?");
} }
return factory;
} }
public static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, boolean checkTokenType, public static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, boolean checkTokenType,

View file

@ -52,7 +52,6 @@ import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.sessions.AuthenticationSessionProvider; import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.services.clientregistration.policy.DefaultClientRegistrationPolicies; import org.keycloak.services.clientregistration.policy.DefaultClientRegistrationPolicies;
import java.util.Collections; import java.util.Collections;
@ -126,11 +125,11 @@ public class RealmManager {
} }
protected void setupAuthenticationFlows(RealmModel realm) { protected void setupAuthenticationFlows(RealmModel realm) {
if (realm.getAuthenticationFlows().size() == 0) DefaultAuthenticationFlows.addFlows(realm); if (realm.getAuthenticationFlowsStream().count() == 0) DefaultAuthenticationFlows.addFlows(realm);
} }
protected void setupRequiredActions(RealmModel realm) { protected void setupRequiredActions(RealmModel realm) {
if (realm.getRequiredActionProviders().size() == 0) DefaultRequiredActions.addActions(realm); if (realm.getRequiredActionProvidersStream().count() == 0) DefaultRequiredActions.addActions(realm);
} }
private void setupOfflineTokens(RealmModel realm, RealmRepresentation realmRep) { private void setupOfflineTokens(RealmModel realm, RealmRepresentation realmRep) {
@ -270,11 +269,9 @@ public class RealmManager {
} }
// Refresh periodic sync tasks for configured storageProviders // Refresh periodic sync tasks for configured storageProviders
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
UserStorageSyncManager storageSync = new UserStorageSyncManager(); UserStorageSyncManager storageSync = new UserStorageSyncManager();
for (UserStorageProviderModel provider : storageProviders) { realm.getUserStorageProvidersStream()
storageSync.notifyToRefreshPeriodicSync(session, realm, provider, true); .forEachOrdered(provider -> storageSync.notifyToRefreshPeriodicSync(session, realm, provider, true));
}
} }
return removed; return removed;
@ -576,11 +573,9 @@ public class RealmManager {
setupRequiredActions(realm); setupRequiredActions(realm);
// Refresh periodic sync tasks for configured storageProviders // Refresh periodic sync tasks for configured storageProviders
List<UserStorageProviderModel> storageProviders = realm.getUserStorageProviders();
UserStorageSyncManager storageSync = new UserStorageSyncManager(); UserStorageSyncManager storageSync = new UserStorageSyncManager();
for (UserStorageProviderModel provider : storageProviders) { realm.getUserStorageProvidersStream()
storageSync.notifyToRefreshPeriodicSync(session, realm, provider, false); .forEachOrdered(provider -> storageSync.notifyToRefreshPeriodicSync(session, realm, provider, false));
}
setupAuthorizationServices(realm); setupAuthorizationServices(realm);
setupClientRegistrations(realm); setupClientRegistrations(realm);

View file

@ -35,8 +35,9 @@ import org.keycloak.storage.user.ImportSynchronization;
import org.keycloak.storage.user.SynchronizationResult; import org.keycloak.storage.user.SynchronizationResult;
import org.keycloak.timer.TimerProvider; import org.keycloak.timer.TimerProvider;
import java.util.List; import java.util.Objects;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
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>
@ -58,16 +59,16 @@ public class UserStorageSyncManager {
@Override @Override
public void run(KeycloakSession session) { public void run(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealmsWithProviderType(UserStorageProvider.class); Stream<RealmModel> realms = session.realms().getRealmsWithProviderTypeStream(UserStorageProvider.class);
for (final RealmModel realm : realms) { realms.forEach(realm -> {
List<UserStorageProviderModel> providers = realm.getUserStorageProviders(); Stream<UserStorageProviderModel> providers = realm.getUserStorageProvidersStream();
for (final UserStorageProviderModel provider : providers) { providers.forEachOrdered(provider -> {
UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, provider.getProviderId()); UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, provider.getProviderId());
if (factory instanceof ImportSynchronization && provider.isImportEnabled()) { if (factory instanceof ImportSynchronization && provider.isImportEnabled()) {
refreshPeriodicSyncForProvider(sessionFactory, timer, provider, realm.getId()); refreshPeriodicSyncForProvider(sessionFactory, timer, provider, realm.getId());
} }
} });
} });
ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class); ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
clusterProvider.registerListener(USER_STORAGE_TASK_KEY, new UserStorageClusterListener(sessionFactory)); clusterProvider.registerListener(USER_STORAGE_TASK_KEY, new UserStorageClusterListener(sessionFactory));
@ -254,20 +255,18 @@ public class UserStorageSyncManager {
@Override @Override
public void run(KeycloakSession session) { public void run(KeycloakSession session) {
RealmModel persistentRealm = session.realms().getRealm(realmId); RealmModel persistentRealm = session.realms().getRealm(realmId);
List<UserStorageProviderModel> persistentFedProviders = persistentRealm.getUserStorageProviders(); persistentRealm.getUserStorageProvidersStream()
for (UserStorageProviderModel persistentFedProvider : persistentFedProviders) { .filter(persistentFedProvider -> Objects.equals(provider.getId(), persistentFedProvider.getId()))
if (provider.getId().equals(persistentFedProvider.getId())) { .forEachOrdered(persistentFedProvider -> {
// Update persistent provider in DB // Update persistent provider in DB
int lastSync = Time.currentTime(); int lastSync = Time.currentTime();
persistentFedProvider.setLastSync(lastSync); persistentFedProvider.setLastSync(lastSync);
persistentRealm.updateComponent(persistentFedProvider); persistentRealm.updateComponent(persistentFedProvider);
// Update "cached" reference // Update "cached" reference
provider.setLastSync(lastSync); provider.setLastSync(lastSync);
} });
}
} }
}); });
} }

View file

@ -51,7 +51,6 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionContext; import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.IdentityProviderSyncMode; import org.keycloak.models.IdentityProviderSyncMode;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -538,14 +537,12 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
session.getContext().setClient(authenticationSession.getClient()); session.getContext().setClient(authenticationSession.getClient());
context.getIdp().preprocessFederatedIdentity(session, realmModel, context); context.getIdp().preprocessFederatedIdentity(session, realmModel, context);
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias()); KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
if (mappers != null) { realmModel.getIdentityProviderMappersByAliasStream(context.getIdpConfig().getAlias()).forEach(mapper -> {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory
for (IdentityProviderMapperModel mapper : mappers) { .getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); target.preprocessFederatedIdentity(session, realmModel, mapper, context);
target.preprocessFederatedIdentity(session, realmModel, mapper, context); });
}
}
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(), FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(),
context.getUsername(), context.getToken()); context.getUsername(), context.getToken());
@ -717,14 +714,12 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
logger.debugf("Registered new user '%s' after first login with identity provider '%s'. Identity provider username is '%s' . ", federatedUser.getUsername(), providerId, context.getUsername()); logger.debugf("Registered new user '%s' after first login with identity provider '%s'. Identity provider username is '%s' . ", federatedUser.getUsername(), providerId, context.getUsername());
context.getIdp().importNewUser(session, realmModel, federatedUser, context); context.getIdp().importNewUser(session, realmModel, federatedUser, context);
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(providerId); KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
if (mappers != null) { realmModel.getIdentityProviderMappersByAliasStream(providerId).forEach(mapper -> {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory
for (IdentityProviderMapperModel mapper : mappers) { .getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); target.importNewUser(session, realmModel, federatedUser, mapper, context);
target.importNewUser(session, realmModel, federatedUser, mapper, context); });
}
}
if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(federatedUser.getEmail()) && !Boolean.parseBoolean(authSession.getAuthNote(AbstractIdpAuthenticator.UPDATE_PROFILE_EMAIL_CHANGED))) { if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(federatedUser.getEmail()) && !Boolean.parseBoolean(authSession.getAuthNote(AbstractIdpAuthenticator.UPDATE_PROFILE_EMAIL_CHANGED))) {
logger.debugf("Email verified automatically after registration of user '%s' through Identity provider '%s' ", federatedUser.getUsername(), context.getIdpConfig().getAlias()); logger.debugf("Email verified automatically after registration of user '%s' through Identity provider '%s' ", federatedUser.getUsername(), context.getIdpConfig().getAlias());
@ -861,7 +856,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
AuthenticationManager.setClientScopesInSession(authSession); AuthenticationManager.setClientScopesInSession(authSession);
String nextRequiredAction = AuthenticationManager.nextRequiredAction(session, authSession, clientConnection, request, session.getContext().getUri(), event); String nextRequiredAction = AuthenticationManager.nextRequiredAction(session, authSession, request, event);
if (nextRequiredAction != null) { if (nextRequiredAction != null) {
if ("true".equals(authSession.getAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN))) { if ("true".equals(authSession.getAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN))) {
logger.errorf("Required action %s found. Auth requests using prompt=none are incompatible with required actions", nextRequiredAction); logger.errorf("Required action %s found. Auth requests using prompt=none are incompatible with required actions", nextRequiredAction);
@ -1019,15 +1014,12 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
// Skip DB write if tokens are null or equal // Skip DB write if tokens are null or equal
updateToken(context, federatedUser, federatedIdentityModel); updateToken(context, federatedUser, federatedIdentityModel);
context.getIdp().updateBrokeredUser(session, realmModel, federatedUser, context); context.getIdp().updateBrokeredUser(session, realmModel, federatedUser, context);
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias()); KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
if (mappers != null) { realmModel.getIdentityProviderMappersByAliasStream(context.getIdpConfig().getAlias()).forEach(mapper -> {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); IdentityProviderMapper target = (IdentityProviderMapper) sessionFactory
for (IdentityProviderMapperModel mapper : mappers) { .getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); IdentityProviderMapperSyncModeDelegate.delegateUpdateBrokeredUser(session, realmModel, federatedUser, mapper, context, target);
IdentityProviderMapperSyncModeDelegate.delegateUpdateBrokeredUser(session, realmModel, federatedUser, mapper, context, target); });
}
}
} }
private void setBasicUserAttributes(BrokeredIdentityContext context, UserModel federatedUser) { private void setBasicUserAttributes(BrokeredIdentityContext context, UserModel federatedUser) {

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