KEYCLOAK-15450 Complement methods for accessing realms with Stream variants
This commit is contained in:
parent
0621e4ceb9
commit
086f7b4696
148 changed files with 1844 additions and 2294 deletions
|
@ -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());
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<>();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
Loading…
Reference in a new issue