Avoid iterating through all mappers when running the config event listeners
Closes #32233 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
3274591fe1
commit
557d7e87b2
10 changed files with 131 additions and 152 deletions
|
@ -239,8 +239,8 @@ public class InfinispanIdentityProviderStorageProvider implements IdentityProvid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<IdentityProviderMapperModel> getMappersStream() {
|
public Stream<IdentityProviderMapperModel> getMappersStream(Map<String, String> options, Integer first, Integer max) {
|
||||||
return idpDelegate.getMappersStream();
|
return idpDelegate.getMappersStream(options, first, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -238,7 +238,9 @@ public class JpaIdentityProviderStorageProvider implements IdentityProviderStora
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ALIAS:
|
||||||
case FIRST_BROKER_LOGIN_FLOW_ID:
|
case FIRST_BROKER_LOGIN_FLOW_ID:
|
||||||
|
case POST_BROKER_LOGIN_FLOW_ID:
|
||||||
case ORGANIZATION_ID: {
|
case ORGANIZATION_ID: {
|
||||||
if (StringUtil.isBlank(value)) {
|
if (StringUtil.isBlank(value)) {
|
||||||
predicates.add(builder.isNull(idp.get(key)));
|
predicates.add(builder.isNull(idp.get(key)));
|
||||||
|
@ -388,16 +390,52 @@ public class JpaIdentityProviderStorageProvider implements IdentityProviderStora
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<IdentityProviderMapperModel> getMappersStream() {
|
public Stream<IdentityProviderMapperModel> getMappersStream(Map<String, String> options, Integer first, Integer max) {
|
||||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||||
CriteriaQuery<IdentityProviderMapperEntity> query = builder.createQuery(IdentityProviderMapperEntity.class);
|
CriteriaQuery<IdentityProviderMapperEntity> query = builder.createQuery(IdentityProviderMapperEntity.class);
|
||||||
Root<IdentityProviderMapperEntity> mapper = query.from(IdentityProviderMapperEntity.class);
|
Root<IdentityProviderMapperEntity> idp = query.from(IdentityProviderMapperEntity.class);
|
||||||
|
|
||||||
Predicate predicate = builder.equal(mapper.get("realmId"), getRealm().getId());
|
List<Predicate> predicates = new ArrayList<>();
|
||||||
|
predicates.add(builder.equal(idp.get("realmId"), getRealm().getId()));
|
||||||
|
|
||||||
TypedQuery<IdentityProviderMapperEntity> typedQuery = em.createQuery(query.select(mapper).where(predicate));
|
if (options != null) {
|
||||||
|
for (Map.Entry<String, String> entry : options.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = entry.getValue();
|
||||||
|
if (StringUtil.isBlank(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String dbProductName = em.unwrap(Session.class).doReturningWork(connection -> connection.getMetaData().getDatabaseProductName());
|
||||||
|
MapJoin<IdentityProviderMapperEntity, String, String> configJoin = idp.joinMap("config");
|
||||||
|
Predicate configNamePredicate = builder.equal(configJoin.key(), key);
|
||||||
|
|
||||||
return closing(typedQuery.getResultStream().map(this::toModel));
|
if (dbProductName.equals("Oracle")) {
|
||||||
|
// Oracle is not able to compare a CLOB with a VARCHAR unless it being converted with TO_CHAR
|
||||||
|
// But for this all values in the table need to be smaller than 4K, otherwise the cast will fail with
|
||||||
|
// "ORA-22835: Buffer too small for CLOB to CHAR" (even if it is in another row).
|
||||||
|
// This leaves DBMS_LOB.COMPARE and DBMS_LOB.INSTR as the options to compare the CLOB with the value.
|
||||||
|
if (value.endsWith("*")) {
|
||||||
|
// prefix search - use DBMS_LOB.INSTR
|
||||||
|
value = value.substring(0, value.length() - 1);
|
||||||
|
Predicate configValuePredicate = builder.equal(builder.function("DBMS_LOB.INSTR", Integer.class, configJoin.value(), builder.literal(value)), 1);
|
||||||
|
predicates.add(builder.and(configNamePredicate, configValuePredicate));
|
||||||
|
} else {
|
||||||
|
Predicate configValuePredicate = builder.equal(builder.function("DBMS_LOB.COMPARE", Integer.class, configJoin.value(), builder.literal(value)), 0);
|
||||||
|
predicates.add(builder.and(configNamePredicate, configValuePredicate));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value.endsWith("*")) {
|
||||||
|
value = value.replace("%", "\\%").replace("_", "\\_").replace("*", "%");
|
||||||
|
predicates.add(builder.and(configNamePredicate, builder.like(configJoin.value(), value)));
|
||||||
|
} else {
|
||||||
|
predicates.add(builder.and(configNamePredicate, builder.equal(configJoin.value(), value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedQuery<IdentityProviderMapperEntity> typedQuery = em.createQuery(query.select(idp).where(predicates.toArray(Predicate[]::new)));
|
||||||
|
return closing(paginateQuery(typedQuery, first, max).getResultStream()).map(this::toModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,40 +32,14 @@ import java.util.function.Consumer;
|
||||||
* @author <a href="mailto:daniel.fesenmeyer@bosch.io">Daniel Fesenmeyer</a>
|
* @author <a href="mailto:daniel.fesenmeyer@bosch.io">Daniel Fesenmeyer</a>
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractConfigPropertySynchronizer<T extends ProviderEvent> implements ConfigSynchronizer<T> {
|
public abstract class AbstractConfigPropertySynchronizer<T extends ProviderEvent> implements ConfigSynchronizer<T> {
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(AbstractConfigPropertySynchronizer.class);
|
private static final Logger LOG = Logger.getLogger(AbstractConfigPropertySynchronizer.class);
|
||||||
|
|
||||||
protected abstract String getConfigPropertyName();
|
protected void logEventProcessed(String configPropertyName, String previousValue, String newValue, String realmName,
|
||||||
|
String mapperName, String idpAlias) {
|
||||||
|
LOG.infof(
|
||||||
|
"Reference of type '%s' changed from '%s' to '%s' in realm '%s'. Adjusting the reference from mapper '%s' of IDP '%s'.",
|
||||||
|
configPropertyName, previousValue, newValue, realmName, mapperName, idpAlias);
|
||||||
|
|
||||||
protected abstract void updateConfigPropertyIfNecessary(T event, String currentPropertyValue,
|
|
||||||
Consumer<String> propertyUpdater);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void handleEvent(T event, IdentityProviderMapperModel idpMapper) {
|
|
||||||
Map<String, String> config = idpMapper.getConfig();
|
|
||||||
if (config == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String configPropertyName = getConfigPropertyName();
|
|
||||||
String configuredValue = config.get(configPropertyName);
|
|
||||||
if (StringUtil.isBlank(configuredValue)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Consumer<String> propertyUpdater = value -> config.put(configPropertyName, value);
|
|
||||||
|
|
||||||
updateConfigPropertyIfNecessary(event, configuredValue, propertyUpdater);
|
|
||||||
|
|
||||||
final String newConfiguredValue = config.get(configPropertyName);
|
|
||||||
if (!configuredValue.equals(newConfiguredValue)) {
|
|
||||||
RealmModel realm = extractRealm(event);
|
|
||||||
|
|
||||||
LOG.infof(
|
|
||||||
"Reference of type '%s' changed from '%s' to '%s' in realm '%s'. Adjusting the reference from mapper '%s' of IDP '%s'.",
|
|
||||||
configPropertyName, configuredValue, newConfiguredValue, realm.getName(), idpMapper.getName(),
|
|
||||||
idpMapper.getIdentityProviderAlias());
|
|
||||||
getKeycloakSession(event).identityProviders().updateMapper(idpMapper);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,24 +42,12 @@ public final class ConfigSyncEventListener implements ProviderEventListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(ProviderEvent event) {
|
public void onEvent(ProviderEvent event) {
|
||||||
List<IdentityProviderMapperModel> realmMappers = null;
|
|
||||||
|
|
||||||
for (ConfigSynchronizer<? extends ProviderEvent> s : SYNCHRONIZERS) {
|
for (ConfigSynchronizer<? extends ProviderEvent> s : SYNCHRONIZERS) {
|
||||||
ConfigSynchronizer<ProviderEvent> configSynchronizer = (ConfigSynchronizer<ProviderEvent>) s;
|
ConfigSynchronizer<ProviderEvent> configSynchronizer = (ConfigSynchronizer<ProviderEvent>) s;
|
||||||
|
|
||||||
if (eventMatchesSynchronizer(event, configSynchronizer)) {
|
if (eventMatchesSynchronizer(event, configSynchronizer)) {
|
||||||
LOG.debugf("Synchronizer %s matches event: %s", configSynchronizer, event);
|
LOG.debugf("Synchronizer %s matches event: %s", configSynchronizer, event);
|
||||||
|
configSynchronizer.handleEvent(event);
|
||||||
if (realmMappers == null) {
|
|
||||||
realmMappers = configSynchronizer.getKeycloakSession(event).identityProviders().getMappersStream()
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
realmMappers.forEach(idpMapper -> {
|
|
||||||
LOG.debugf("Apply synchronizer %s to event %s and mapper with name %s", configSynchronizer, event,
|
|
||||||
idpMapper.getName());
|
|
||||||
configSynchronizer.handleEvent(event, idpMapper);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
LOG.debugf("Synchronizer %s does not match event: %s", configSynchronizer, event);
|
LOG.debugf("Synchronizer %s does not match event: %s", configSynchronizer, event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,5 @@ import org.keycloak.provider.ProviderEvent;
|
||||||
public interface ConfigSynchronizer<T extends ProviderEvent> {
|
public interface ConfigSynchronizer<T extends ProviderEvent> {
|
||||||
Class<T> getEventClass();
|
Class<T> getEventClass();
|
||||||
|
|
||||||
RealmModel extractRealm(T event);
|
void handleEvent(T event);
|
||||||
|
}
|
||||||
KeycloakSession getKeycloakSession(T event);
|
|
||||||
|
|
||||||
void handleEvent(T event, IdentityProviderMapperModel idpMapper);
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.keycloak.models.utils.KeycloakModelUtils.GROUP_PATH_SEPARATOR;
|
import static org.keycloak.models.utils.KeycloakModelUtils.GROUP_PATH_SEPARATOR;
|
||||||
|
@ -46,37 +47,27 @@ public class GroupConfigPropertyByPathSynchronizer extends AbstractConfigPropert
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RealmModel extractRealm(GroupModel.GroupPathChangeEvent event) {
|
public void handleEvent(GroupModel.GroupPathChangeEvent event) {
|
||||||
return event.getRealm();
|
|
||||||
|
// first find all mappers that have a group config property that maps exactly to the changed path.
|
||||||
|
event.getKeycloakSession().identityProviders().getMappersStream(Map.of(ConfigConstants.GROUP, event.getPreviousPath()), null, null)
|
||||||
|
.forEach(idpMapper -> {
|
||||||
|
idpMapper.getConfig().put(ConfigConstants.GROUP, event.getNewPath());
|
||||||
|
super.logEventProcessed(ConfigConstants.GROUP, event.getPreviousPath(), event.getNewPath(), event.getRealm().getName(),
|
||||||
|
idpMapper.getName(), idpMapper.getIdentityProviderAlias());
|
||||||
|
event.getKeycloakSession().identityProviders().updateMapper(idpMapper);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then find all mappers that have a group config that maps to a sub-path of the changed path.
|
||||||
|
event.getKeycloakSession().identityProviders().getMappersStream(
|
||||||
|
Map.of(ConfigConstants.GROUP, event.getPreviousPath() + GROUP_PATH_SEPARATOR + "*"), null, null)
|
||||||
|
.forEach(idpMapper -> {
|
||||||
|
String currentGroupPath = idpMapper.getConfig().get(ConfigConstants.GROUP);
|
||||||
|
String newGroupPath = event.getNewPath() + currentGroupPath.substring(event.getPreviousPath().length());
|
||||||
|
idpMapper.getConfig().put(ConfigConstants.GROUP, newGroupPath);
|
||||||
|
super.logEventProcessed(ConfigConstants.GROUP, currentGroupPath, newGroupPath, event.getRealm().getName(),
|
||||||
|
idpMapper.getName(), idpMapper.getIdentityProviderAlias());
|
||||||
|
event.getKeycloakSession().identityProviders().updateMapper(idpMapper);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeycloakSession getKeycloakSession(GroupModel.GroupPathChangeEvent event) {
|
|
||||||
return event.getKeycloakSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getConfigPropertyName() {
|
|
||||||
return ConfigConstants.GROUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateConfigPropertyIfNecessary(GroupModel.GroupPathChangeEvent event,
|
|
||||||
String currentPropertyValue, Consumer<String> propertyUpdater) {
|
|
||||||
String configuredGroupPath = KeycloakModelUtils.normalizeGroupPath(currentPropertyValue);
|
|
||||||
|
|
||||||
String previousGroupPath = event.getPreviousPath();
|
|
||||||
if (configuredGroupPath.equals(previousGroupPath)) {
|
|
||||||
String newPath = event.getNewPath();
|
|
||||||
propertyUpdater.accept(newPath);
|
|
||||||
} else if (isSubGroupOf(configuredGroupPath, previousGroupPath)) {
|
|
||||||
String newPath = event.getNewPath() + configuredGroupPath.substring(previousGroupPath.length());
|
|
||||||
propertyUpdater.accept(newPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isSubGroupOf(String groupPath, String potentialParentGroupPath) {
|
|
||||||
return groupPath.startsWith(potentialParentGroupPath + GROUP_PATH_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,8 +31,7 @@ import java.util.function.Consumer;
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:daniel.fesenmeyer@bosch.io">Daniel Fesenmeyer</a>
|
* @author <a href="mailto:daniel.fesenmeyer@bosch.io">Daniel Fesenmeyer</a>
|
||||||
*/
|
*/
|
||||||
public class RoleConfigPropertyByClientIdSynchronizer
|
public class RoleConfigPropertyByClientIdSynchronizer extends AbstractConfigPropertySynchronizer<ClientModel.ClientIdChangeEvent> {
|
||||||
extends AbstractConfigPropertySynchronizer<ClientModel.ClientIdChangeEvent> {
|
|
||||||
|
|
||||||
public static final RoleConfigPropertyByClientIdSynchronizer INSTANCE =
|
public static final RoleConfigPropertyByClientIdSynchronizer INSTANCE =
|
||||||
new RoleConfigPropertyByClientIdSynchronizer();
|
new RoleConfigPropertyByClientIdSynchronizer();
|
||||||
|
@ -46,36 +46,17 @@ public class RoleConfigPropertyByClientIdSynchronizer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RealmModel extractRealm(ClientModel.ClientIdChangeEvent event) {
|
public void handleEvent(ClientModel.ClientIdChangeEvent event) {
|
||||||
return event.getUpdatedClient().getRealm();
|
// find all mappers that have a role config property that maps to a role associated with the changed client.
|
||||||
|
event.getKeycloakSession().identityProviders().getMappersStream(Map.of(ConfigConstants.ROLE, event.getPreviousClientId() + ".*"), null, null)
|
||||||
|
.forEach(idpMapper -> {
|
||||||
|
String currentRoleValue = idpMapper.getConfig().get(ConfigConstants.ROLE);
|
||||||
|
String configuredRoleName = KeycloakModelUtils.parseRole(currentRoleValue)[1];
|
||||||
|
String newRoleValue = KeycloakModelUtils.buildRoleQualifier(event.getNewClientId(), configuredRoleName);
|
||||||
|
idpMapper.getConfig().put(ConfigConstants.ROLE, newRoleValue);
|
||||||
|
super.logEventProcessed(ConfigConstants.ROLE, currentRoleValue, newRoleValue, event.getUpdatedClient().getRealm().getName(),
|
||||||
|
idpMapper.getName(), idpMapper.getIdentityProviderAlias());
|
||||||
|
event.getKeycloakSession().identityProviders().updateMapper(idpMapper);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeycloakSession getKeycloakSession(ClientModel.ClientIdChangeEvent event) {
|
|
||||||
return event.getKeycloakSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getConfigPropertyName() {
|
|
||||||
return ConfigConstants.ROLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateConfigPropertyIfNecessary(ClientModel.ClientIdChangeEvent event, String currentPropertyValue,
|
|
||||||
Consumer<String> propertyUpdater) {
|
|
||||||
String[] parsedConfiguredRoleQualifier = KeycloakModelUtils.parseRole(currentPropertyValue);
|
|
||||||
String configuredClientId = parsedConfiguredRoleQualifier[0];
|
|
||||||
if (configuredClientId == null) {
|
|
||||||
// a realm role is configured for the mapper, event is not relevant
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String configuredRoleName = parsedConfiguredRoleQualifier[1];
|
|
||||||
|
|
||||||
if (configuredClientId.equals(event.getPreviousClientId())) {
|
|
||||||
String newRoleQualifier = KeycloakModelUtils.buildRoleQualifier(event.getNewClientId(), configuredRoleName);
|
|
||||||
propertyUpdater.accept(newRoleQualifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,30 +47,17 @@ public class RoleConfigPropertyByRoleNameSynchronizer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RealmModel extractRealm(RoleModel.RoleNameChangeEvent event) {
|
public void handleEvent(RoleModel.RoleNameChangeEvent event) {
|
||||||
return event.getRealm();
|
// first find all mappers that have a role config property that maps exactly to the changed path.
|
||||||
|
String currentRoleValue = KeycloakModelUtils.buildRoleQualifier(event.getClientId(), event.getPreviousName());
|
||||||
|
event.getKeycloakSession().identityProviders().getMappersStream(Map.of(ConfigConstants.ROLE, currentRoleValue), null, null)
|
||||||
|
.forEach(idpMapper -> {
|
||||||
|
String newRoleValue = KeycloakModelUtils.buildRoleQualifier(event.getClientId(), event.getNewName());
|
||||||
|
idpMapper.getConfig().put(ConfigConstants.ROLE, newRoleValue);
|
||||||
|
super.logEventProcessed(ConfigConstants.ROLE, currentRoleValue, newRoleValue, event.getRealm().getName(),
|
||||||
|
idpMapper.getName(), idpMapper.getIdentityProviderAlias());
|
||||||
|
event.getKeycloakSession().identityProviders().updateMapper(idpMapper);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeycloakSession getKeycloakSession(RoleModel.RoleNameChangeEvent event) {
|
|
||||||
return event.getKeycloakSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getConfigPropertyName() {
|
|
||||||
return ConfigConstants.ROLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateConfigPropertyIfNecessary(RoleModel.RoleNameChangeEvent event, String currentPropertyValue,
|
|
||||||
Consumer<String> propertyUpdater) {
|
|
||||||
|
|
||||||
String previousRoleQualifier =
|
|
||||||
KeycloakModelUtils.buildRoleQualifier(event.getClientId(), event.getPreviousName());
|
|
||||||
if (previousRoleQualifier.equals(currentPropertyValue)) {
|
|
||||||
String newRoleQualifier = KeycloakModelUtils.buildRoleQualifier(event.getClientId(), event.getNewName());
|
|
||||||
propertyUpdater.accept(newRoleQualifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,14 +102,23 @@ public interface IdentityProviderStorageProvider extends Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all identity providers in the realm filtered according to the specified parameters.
|
* Returns all identity providers in the realm filtered according to the specified search options. The options include:
|
||||||
|
* <ul>
|
||||||
|
* <li>Regular fields found in {@link IdentityProviderModel}, such as {@code ALIAS}, {@code ENABLED}, {@code HIDE_ON_LOGIN}, etc;</li>
|
||||||
|
* <li>Special search keys also present in {@link IdentityProviderModel}. Those include {@code SEARCH}, used to perform
|
||||||
|
* exact, prefix, and infix searches by alias, and {@code ALIAS_NOT_IN}, used to perform searches for identity providers
|
||||||
|
* whose alias doesn't match any of the specified aliases (separated by comma);</li>
|
||||||
|
* <li>Any attribute found in the identity provider's config. If the option key doesn't match any of the previous
|
||||||
|
* cases, the implementations must search the providers whose config contains a pair that matches the specified search
|
||||||
|
* option</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param attrs a {@code Map} containig identity provider config attributes that must be matched.
|
* @param options a {@link Map} containing identity provider search options that must be matched.
|
||||||
* @param first the position of the first result to be processed (pagination offset). Ignored if negative or {@code null}.
|
* @param first the position of the first result to be processed (pagination offset). Ignored if negative or {@code null}.
|
||||||
* @param max the maximum number of results to be returned. Ignored if negative or {@code null}.
|
* @param max the maximum number of results to be returned. Ignored if negative or {@code null}.
|
||||||
* @return a non-null stream of {@link IdentityProviderModel}s that match the search criteria.
|
* @return a non-null stream of {@link IdentityProviderModel}s that match the search criteria.
|
||||||
*/
|
*/
|
||||||
Stream<IdentityProviderModel> getAllStream(Map<String, String> attrs, Integer first, Integer max);
|
Stream<IdentityProviderModel> getAllStream(Map<String, String> options, Integer first, Integer max);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all identity providers associated with the organization with the provided id.
|
* Returns all identity providers associated with the organization with the provided id.
|
||||||
|
@ -295,7 +304,19 @@ public interface IdentityProviderStorageProvider extends Provider {
|
||||||
* Returns all identity provider mappers as a stream.
|
* Returns all identity provider mappers as a stream.
|
||||||
* @return Stream of {@link IdentityProviderMapperModel}. Never returns {@code null}.
|
* @return Stream of {@link IdentityProviderMapperModel}. Never returns {@code null}.
|
||||||
*/
|
*/
|
||||||
Stream<IdentityProviderMapperModel> getMappersStream();
|
default Stream<IdentityProviderMapperModel> getMappersStream() {
|
||||||
|
return this.getMappersStream(Map.of(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all identity provider mappers in the realm filtered according to the specified search options.
|
||||||
|
*
|
||||||
|
* @param options a {@link Map} containing identity provider search options that must be matched.
|
||||||
|
* @param first the position of the first result to be processed (pagination offset). Ignored if negative or {@code null}.
|
||||||
|
* @param max the maximum number of results to be returned. Ignored if negative or {@code null}.
|
||||||
|
* @return a non-null stream of {@link IdentityProviderModel}s that match the search criteria.
|
||||||
|
*/
|
||||||
|
Stream<IdentityProviderMapperModel> getMappersStream(Map<String, String> options, Integer first, Integer max);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns identity provider mappers by the provided alias as a stream.
|
* Returns identity provider mappers by the provided alias as a stream.
|
||||||
|
|
|
@ -15,6 +15,8 @@ SSOTest
|
||||||
SamlClientTest
|
SamlClientTest
|
||||||
TransactionsTest
|
TransactionsTest
|
||||||
UserProfileTest
|
UserProfileTest
|
||||||
|
OidcAdvancedClaimToGroupMapperTest
|
||||||
|
OidcAdvancedClaimToRoleMapperTest
|
||||||
org.keycloak.testsuite.admin.**
|
org.keycloak.testsuite.admin.**
|
||||||
org.keycloak.testsuite.authz.**ManagementTest
|
org.keycloak.testsuite.authz.**ManagementTest
|
||||||
org.keycloak.testsuite.organization.admin.**
|
org.keycloak.testsuite.organization.admin.**
|
||||||
|
|
Loading…
Reference in a new issue