Move realms, clients, groups, roles, clientscopes into legacy module
- Introduces Datastore SPI for isolating data store methods - Introduces implementation of the datastore for legacy storage - Updates DefaultKeycloakSession to leverage Datastore SPI instead of direct creating of area providers by the session
This commit is contained in:
parent
247ff52187
commit
36f76a37ad
23 changed files with 816 additions and 208 deletions
|
@ -26,8 +26,10 @@ import org.keycloak.models.cache.CachedRealmModel;
|
|||
import org.keycloak.models.cache.infinispan.entities.*;
|
||||
import org.keycloak.models.cache.infinispan.events.*;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.storage.DatastoreProvider;
|
||||
import org.keycloak.storage.StorageId;
|
||||
import org.keycloak.storage.client.ClientStorageProviderModel;
|
||||
import org.keycloak.storage.datastore.LegacyDatastoreProvider;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -119,11 +121,13 @@ public class RealmCacheSession implements CacheRealmProvider {
|
|||
|
||||
protected boolean clearAll;
|
||||
protected final long startupRevision;
|
||||
private final LegacyDatastoreProvider datastoreProvider;
|
||||
|
||||
public RealmCacheSession(RealmCacheManager cache, KeycloakSession session) {
|
||||
this.cache = cache;
|
||||
this.session = session;
|
||||
this.startupRevision = cache.getCurrentCounter();
|
||||
this.datastoreProvider = (LegacyDatastoreProvider) session.getProvider(DatastoreProvider.class);
|
||||
session.getTransactionManager().enlistPrepare(getPrepareTransaction());
|
||||
session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
|
||||
}
|
||||
|
@ -146,31 +150,31 @@ public class RealmCacheSession implements CacheRealmProvider {
|
|||
public RealmProvider getRealmDelegate() {
|
||||
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
|
||||
if (realmDelegate != null) return realmDelegate;
|
||||
realmDelegate = session.realmLocalStorage();
|
||||
realmDelegate = session.getProvider(RealmProvider.class);
|
||||
return realmDelegate;
|
||||
}
|
||||
public ClientProvider getClientDelegate() {
|
||||
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
|
||||
if (clientDelegate != null) return clientDelegate;
|
||||
clientDelegate = session.clientStorageManager();
|
||||
clientDelegate = this.datastoreProvider.clientStorageManager();
|
||||
return clientDelegate;
|
||||
}
|
||||
public ClientScopeProvider getClientScopeDelegate() {
|
||||
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
|
||||
if (clientScopeDelegate != null) return clientScopeDelegate;
|
||||
clientScopeDelegate = session.clientScopeStorageManager();
|
||||
clientScopeDelegate = this.datastoreProvider.clientScopeStorageManager();
|
||||
return clientScopeDelegate;
|
||||
}
|
||||
public RoleProvider getRoleDelegate() {
|
||||
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
|
||||
if (roleDelegate != null) return roleDelegate;
|
||||
roleDelegate = session.roleStorageManager();
|
||||
roleDelegate = this.datastoreProvider.roleStorageManager();
|
||||
return roleDelegate;
|
||||
}
|
||||
public GroupProvider getGroupDelegate() {
|
||||
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
|
||||
if (groupDelegate != null) return groupDelegate;
|
||||
groupDelegate = session.groupStorageManager();
|
||||
groupDelegate = this.datastoreProvider.groupStorageManager();
|
||||
return groupDelegate;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.storage;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.common.util.reflections.Types;
|
||||
import org.keycloak.component.ComponentFactory;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.utils.ServicesUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <ProviderType> This type will be used for looking for factories that produce instances of desired providers
|
||||
* @param <StorageProviderModelType> Type of model used for creating provider, it needs to extend
|
||||
* CacheableStorageProviderModel as it has {@code isEnabled()} method and also extend
|
||||
* PrioritizedComponentModel which is required for sorting providers based on its
|
||||
* priorities
|
||||
*/
|
||||
public abstract class AbstractStorageManager<ProviderType extends Provider,
|
||||
StorageProviderModelType extends CacheableStorageProviderModel> {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(AbstractStorageManager.class);
|
||||
|
||||
/**
|
||||
* Timeouts are used as time boundary for obtaining models from an external storage. Default value is set
|
||||
* to 3000 milliseconds and it's configurable.
|
||||
*/
|
||||
private static final Long STORAGE_PROVIDER_DEFAULT_TIMEOUT = 3000L;
|
||||
protected final KeycloakSession session;
|
||||
private final Class<ProviderType> providerTypeClass;
|
||||
private final Class<? extends ProviderFactory> factoryTypeClass;
|
||||
private final Function<ComponentModel, StorageProviderModelType> toStorageProviderModelTypeFunction;
|
||||
private final String configScope;
|
||||
private Long storageProviderTimeout;
|
||||
|
||||
public AbstractStorageManager(KeycloakSession session, Class<? extends ProviderFactory> factoryTypeClass, Class<ProviderType> providerTypeClass, Function<ComponentModel, StorageProviderModelType> toStorageProviderModelTypeFunction, String configScope) {
|
||||
this.session = session;
|
||||
this.providerTypeClass = providerTypeClass;
|
||||
this.factoryTypeClass = factoryTypeClass;
|
||||
this.toStorageProviderModelTypeFunction = toStorageProviderModelTypeFunction;
|
||||
this.configScope = configScope;
|
||||
}
|
||||
|
||||
protected Long getStorageProviderTimeout() {
|
||||
if (storageProviderTimeout == null) {
|
||||
storageProviderTimeout = Config.scope(configScope).getLong("storageProviderTimeout", STORAGE_PROVIDER_DEFAULT_TIMEOUT);
|
||||
}
|
||||
return storageProviderTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory with the providerId, which produce instances of type CreatedProviderType
|
||||
* @param providerId id of factory that produce desired instances
|
||||
* @return A factory that implements {@code ComponentFactory<CreatedProviderType, ProviderType>}
|
||||
*/
|
||||
protected <T extends ProviderType> ComponentFactory<T, ProviderType> getStorageProviderFactory(String providerId) {
|
||||
return (ComponentFactory<T, ProviderType>) session.getKeycloakSessionFactory()
|
||||
.getProviderFactory(providerTypeClass, providerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stream of all storageProviders within the realm that implements the capabilityInterface.
|
||||
*
|
||||
* @param realm realm
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @return enabled storage providers for realm and @{code getProviderTypeClass()}
|
||||
*/
|
||||
protected <T> Stream<T> getEnabledStorageProviders(RealmModel realm, Class<T> capabilityInterface) {
|
||||
return getStorageProviderModels(realm, providerTypeClass)
|
||||
.map(toStorageProviderModelTypeFunction)
|
||||
.filter(StorageProviderModelType::isEnabled)
|
||||
.sorted(StorageProviderModelType.comparator)
|
||||
.map(storageProviderModelType -> getStorageProviderInstance(storageProviderModelType, capabilityInterface, false))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all enabled StorageProviders that implements the capabilityInterface, applies applyFunction on each of
|
||||
* them and then join the results together.
|
||||
*
|
||||
* !! Each StorageProvider has a limited time to respond, if it fails to do it, empty stream is returned !!
|
||||
*
|
||||
* @param realm realm
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @param applyFunction function that is applied on StorageProviders
|
||||
* @param <R> result of applyFunction
|
||||
* @return a stream with all results from all StorageProviders
|
||||
*/
|
||||
protected <R, T> Stream<R> flatMapEnabledStorageProvidersWithTimeout(RealmModel realm, Class<T> capabilityInterface, Function<T, ? extends Stream<R>> applyFunction) {
|
||||
return getEnabledStorageProviders(realm, capabilityInterface)
|
||||
.flatMap(ServicesUtils.timeBound(session, getStorageProviderTimeout(), applyFunction));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all enabled StorageProviders that implements the capabilityInterface, applies applyFunction on each of
|
||||
* them and returns the stream.
|
||||
*
|
||||
* !! Each StorageProvider has a limited time to respond, if it fails to do it, null is returned !!
|
||||
*
|
||||
* @param realm realm
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @param applyFunction function that is applied on StorageProviders
|
||||
* @param <R> Result of applyFunction
|
||||
* @return First result from StorageProviders
|
||||
*/
|
||||
protected <R, T> Stream<R> mapEnabledStorageProvidersWithTimeout(RealmModel realm, Class<T> capabilityInterface, Function<T, R> applyFunction) {
|
||||
return getEnabledStorageProviders(realm, capabilityInterface)
|
||||
.map(ServicesUtils.timeBoundOne(session, getStorageProviderTimeout(), applyFunction))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all enabled StorageProviders that implements the capabilityInterface and call applyFunction on each
|
||||
*
|
||||
* !! Each StorageProvider has a limited time for consuming !!
|
||||
*
|
||||
* @param realm realm
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @param consumer function that is applied on StorageProviders
|
||||
*/
|
||||
protected <T> void consumeEnabledStorageProvidersWithTimeout(RealmModel realm, Class<T> capabilityInterface, Consumer<T> consumer) {
|
||||
getEnabledStorageProviders(realm, capabilityInterface)
|
||||
.forEachOrdered(ServicesUtils.consumeWithTimeBound(session, getStorageProviderTimeout(), consumer));
|
||||
}
|
||||
|
||||
|
||||
protected <T> T getStorageProviderInstance(RealmModel realm, String providerId, Class<T> capabilityInterface) {
|
||||
return getStorageProviderInstance(realm, providerId, capabilityInterface, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of provider with the providerId within the realm or null if storage provider with providerId
|
||||
* doesn't implement capabilityInterface.
|
||||
*
|
||||
* @param realm realm
|
||||
* @param providerId id of ComponentModel within database/storage
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @return an instance of type CreatedProviderType or null if storage provider with providerId doesn't implement capabilityInterface
|
||||
*/
|
||||
protected <T> T getStorageProviderInstance(RealmModel realm, String providerId, Class<T> capabilityInterface, boolean includeDisabled) {
|
||||
if (providerId == null || capabilityInterface == null) return null;
|
||||
return getStorageProviderInstance(getStorageProviderModel(realm, providerId), capabilityInterface, includeDisabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of StorageProvider model corresponding realm and providerId
|
||||
* @param realm Realm.
|
||||
* @param providerId Id of desired provider.
|
||||
* @return An instance of type StorageProviderModelType
|
||||
*/
|
||||
protected StorageProviderModelType getStorageProviderModel(RealmModel realm, String providerId) {
|
||||
ComponentModel componentModel = realm.getComponent(providerId);
|
||||
if (componentModel == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return toStorageProviderModelTypeFunction.apply(componentModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of provider for the model or null if storage provider based on the model doesn't implement capabilityInterface.
|
||||
*
|
||||
* @param model StorageProviderModel obtained from database/storage
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @param <T> Required capability interface type
|
||||
* @return an instance of type T or null if storage provider based on the model doesn't exist or doesn't implement the capabilityInterface.
|
||||
*/
|
||||
protected <T> T getStorageProviderInstance(StorageProviderModelType model, Class<T> capabilityInterface) {
|
||||
return getStorageProviderInstance(model, capabilityInterface, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of provider for the model or null if storage provider based on the model doesn't implement capabilityInterface.
|
||||
*
|
||||
* @param model StorageProviderModel obtained from database/storage
|
||||
* @param capabilityInterface class of desired capabilityInterface.
|
||||
* For example, {@code GroupLookupProvider} or {@code UserQueryProvider}
|
||||
* @param includeDisabled If set to true, the method will return also disabled providers.
|
||||
* @return an instance of type T or null if storage provider based on the model doesn't exist or doesn't implement the capabilityInterface.
|
||||
*/
|
||||
protected <T> T getStorageProviderInstance(StorageProviderModelType model, Class<T> capabilityInterface, boolean includeDisabled) {
|
||||
if (model == null || (!model.isEnabled() && !includeDisabled) || capabilityInterface == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ProviderType instance = (ProviderType) session.getAttribute(model.getId());
|
||||
if (instance != null && capabilityInterface.isAssignableFrom(instance.getClass())) return capabilityInterface.cast(instance);
|
||||
|
||||
ComponentFactory<? extends ProviderType, ProviderType> factory = getStorageProviderFactory(model.getProviderId());
|
||||
if (factory == null) {
|
||||
LOG.warnv("Configured StorageProvider {0} of provider id {1} does not exist", model.getName(), model.getProviderId());
|
||||
return null;
|
||||
}
|
||||
if (!Types.supports(capabilityInterface, factory, factoryTypeClass)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
instance = factory.create(session, model);
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("StorageProvideFactory (of type " + factory.getClass().getName() + ") produced a null instance");
|
||||
}
|
||||
session.enlistForClose(instance);
|
||||
session.setAttribute(model.getId(), instance);
|
||||
return capabilityInterface.cast(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of ComponentModels of storageType.
|
||||
* @param realm Realm.
|
||||
* @param storageType Type.
|
||||
* @return Stream of ComponentModels
|
||||
*/
|
||||
public static Stream<ComponentModel> getStorageProviderModels(RealmModel realm, Class<? extends Provider> storageType) {
|
||||
return realm.getStorageProviders(storageType);
|
||||
}
|
||||
}
|
|
@ -33,13 +33,17 @@ public class ClientScopeStorageManager extends AbstractStorageManager<ClientScop
|
|||
ClientScopeStorageProviderModel::new, "clientscope");
|
||||
}
|
||||
|
||||
private ClientScopeProvider localStorage() {
|
||||
return session.getProvider(ClientScopeProvider.class);
|
||||
}
|
||||
|
||||
/* CLIENT SCOPE PROVIDER LOOKUP METHODS - implemented by client scope storage providers */
|
||||
|
||||
@Override
|
||||
public ClientScopeModel getClientScopeById(RealmModel realm, String id) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
if (storageId.getProviderId() == null) {
|
||||
return session.clientScopeLocalStorage().getClientScopeById(realm, id);
|
||||
return localStorage().getClientScopeById(realm, id);
|
||||
}
|
||||
|
||||
ClientScopeLookupProvider provider = getStorageProviderInstance(realm, storageId.getProviderId(), ClientScopeLookupProvider.class);
|
||||
|
@ -52,22 +56,22 @@ public class ClientScopeStorageManager extends AbstractStorageManager<ClientScop
|
|||
|
||||
@Override
|
||||
public Stream<ClientScopeModel> getClientScopesStream(RealmModel realm) {
|
||||
return session.clientScopeLocalStorage().getClientScopesStream(realm);
|
||||
return localStorage().getClientScopesStream(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientScopeModel addClientScope(RealmModel realm, String id, String name) {
|
||||
return session.clientScopeLocalStorage().addClientScope(realm, id, name);
|
||||
return localStorage().addClientScope(realm, id, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeClientScope(RealmModel realm, String id) {
|
||||
return session.clientScopeLocalStorage().removeClientScope(realm, id);
|
||||
return localStorage().removeClientScope(realm, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeClientScopes(RealmModel realm) {
|
||||
session.clientScopeLocalStorage().removeClientScopes(realm);
|
||||
localStorage().removeClientScopes(realm);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -50,6 +50,10 @@ public class ClientStorageManager implements ClientProvider {
|
|||
|
||||
private long clientStorageProviderTimeout;
|
||||
|
||||
private ClientProvider localStorage() {
|
||||
return session.getProvider(ClientProvider.class);
|
||||
}
|
||||
|
||||
public static boolean isStorageProviderEnabled(RealmModel realm, String providerId) {
|
||||
ClientStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||
return model.isEnabled();
|
||||
|
@ -131,7 +135,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
public ClientModel getClientById(RealmModel realm, String id) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
if (storageId.getProviderId() == null) {
|
||||
return session.clientLocalStorage().getClientById(realm, id);
|
||||
return localStorage().getClientById(realm, id);
|
||||
}
|
||||
ClientLookupProvider provider = (ClientLookupProvider)getStorageProvider(session, realm, storageId.getProviderId());
|
||||
if (provider == null) return null;
|
||||
|
@ -141,7 +145,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
|
||||
@Override
|
||||
public ClientModel getClientByClientId(RealmModel realm, String clientId) {
|
||||
ClientModel client = session.clientLocalStorage().getClientByClientId(realm, clientId);
|
||||
ClientModel client = localStorage().getClientByClientId(realm, clientId);
|
||||
if (client != null) {
|
||||
return client;
|
||||
}
|
||||
|
@ -174,7 +178,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
// how many results there will be; i.e. we need to query the clients without paginating them and perform pagination
|
||||
// later at this level
|
||||
if (hasEnabledStorageProviders(session, realm, ClientLookupProvider.class)) {
|
||||
Stream<ClientLookupProvider> providersStream = Stream.concat(Stream.of(session.clientLocalStorage()), getEnabledStorageProviders(session, realm, ClientLookupProvider.class));
|
||||
Stream<ClientLookupProvider> providersStream = Stream.concat(Stream.of(localStorage()), getEnabledStorageProviders(session, realm, ClientLookupProvider.class));
|
||||
|
||||
/*
|
||||
Obtaining clients from an external client storage is time-bounded. In case the external client storage
|
||||
|
@ -196,7 +200,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
return paginatedStream(res, firstResult, maxResults);
|
||||
}
|
||||
else {
|
||||
return paginatedQuery.query(session.clientLocalStorage(), firstResult, maxResults);
|
||||
return paginatedQuery.query(localStorage(), firstResult, maxResults);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +208,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
public Map<String, ClientScopeModel> getClientScopes(RealmModel realm, ClientModel client, boolean defaultScopes) {
|
||||
StorageId storageId = new StorageId(client.getId());
|
||||
if (storageId.getProviderId() == null) {
|
||||
return session.clientLocalStorage().getClientScopes(realm, client, defaultScopes);
|
||||
return localStorage().getClientScopes(realm, client, defaultScopes);
|
||||
}
|
||||
ClientLookupProvider provider = (ClientLookupProvider)getStorageProvider(session, client.getRealm(), storageId.getProviderId());
|
||||
if (provider == null) return null;
|
||||
|
@ -214,37 +218,37 @@ public class ClientStorageManager implements ClientProvider {
|
|||
|
||||
@Override
|
||||
public ClientModel addClient(RealmModel realm, String clientId) {
|
||||
return session.clientLocalStorage().addClient(realm, clientId);
|
||||
return localStorage().addClient(realm, clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientModel addClient(RealmModel realm, String id, String clientId) {
|
||||
return session.clientLocalStorage().addClient(realm, id, clientId);
|
||||
return localStorage().addClient(realm, id, clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> getClientsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
|
||||
return session.clientLocalStorage().getClientsStream(realm, firstResult, maxResults);
|
||||
return localStorage().getClientsStream(realm, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> getClientsStream(RealmModel realm) {
|
||||
return session.clientLocalStorage().getClientsStream(realm);
|
||||
return localStorage().getClientsStream(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getClientsCount(RealmModel realm) {
|
||||
return session.clientLocalStorage().getClientsCount(realm);
|
||||
return localStorage().getClientsCount(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> getAlwaysDisplayInConsoleClientsStream(RealmModel realm) {
|
||||
return session.clientLocalStorage().getAlwaysDisplayInConsoleClientsStream(realm);
|
||||
return localStorage().getAlwaysDisplayInConsoleClientsStream(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeClients(RealmModel realm) {
|
||||
session.clientLocalStorage().removeClients(realm);
|
||||
localStorage().removeClients(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -252,7 +256,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
if (!StorageId.isLocalStorage(client.getId())) {
|
||||
throw new RuntimeException("Federated clients do not support this operation");
|
||||
}
|
||||
session.clientLocalStorage().addClientScopes(realm, client, clientScopes, defaultScope);
|
||||
localStorage().addClientScopes(realm, client, clientScopes, defaultScope);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -260,12 +264,12 @@ public class ClientStorageManager implements ClientProvider {
|
|||
if (!StorageId.isLocalStorage(client.getId())) {
|
||||
throw new RuntimeException("Federated clients do not support this operation");
|
||||
}
|
||||
session.clientLocalStorage().removeClientScope(realm, client, clientScope);
|
||||
localStorage().removeClientScope(realm, client, clientScope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ClientModel, Set<String>> getAllRedirectUrisOfEnabledClients(RealmModel realm) {
|
||||
return session.clientLocalStorage().getAllRedirectUrisOfEnabledClients(realm);
|
||||
return localStorage().getAllRedirectUrisOfEnabledClients(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -278,7 +282,7 @@ public class ClientStorageManager implements ClientProvider {
|
|||
if (!StorageId.isLocalStorage(id)) {
|
||||
throw new RuntimeException("Federated clients do not support this operation");
|
||||
}
|
||||
return session.clientLocalStorage().removeClient(realm, id);
|
||||
return localStorage().removeClient(realm, id);
|
||||
}
|
||||
|
||||
|
|
@ -37,11 +37,15 @@ public class GroupStorageManager extends AbstractStorageManager<GroupStorageProv
|
|||
|
||||
/* GROUP PROVIDER LOOKUP METHODS - implemented by group storage providers */
|
||||
|
||||
private GroupProvider localStorage() {
|
||||
return session.getProvider(GroupProvider.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupById(RealmModel realm, String id) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
if (storageId.getProviderId() == null) {
|
||||
return session.groupLocalStorage().getGroupById(realm, id);
|
||||
return localStorage().getGroupById(realm, id);
|
||||
}
|
||||
|
||||
GroupLookupProvider provider = getStorageProviderInstance(realm, storageId.getProviderId(), GroupLookupProvider.class);
|
||||
|
@ -60,7 +64,7 @@ public class GroupStorageManager extends AbstractStorageManager<GroupStorageProv
|
|||
*/
|
||||
@Override
|
||||
public Stream<GroupModel> searchForGroupByNameStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
|
||||
Stream<GroupModel> local = session.groupLocalStorage().searchForGroupByNameStream(realm, search, firstResult, maxResults);
|
||||
Stream<GroupModel> local = localStorage().searchForGroupByNameStream(realm, search, firstResult, maxResults);
|
||||
Stream<GroupModel> ext = flatMapEnabledStorageProvidersWithTimeout(realm, GroupLookupProvider.class,
|
||||
p -> p.searchForGroupByNameStream(realm, search, firstResult, maxResults));
|
||||
|
||||
|
@ -71,57 +75,57 @@ public class GroupStorageManager extends AbstractStorageManager<GroupStorageProv
|
|||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsStream(RealmModel realm) {
|
||||
return session.groupLocalStorage().getGroupsStream(realm);
|
||||
return localStorage().getGroupsStream(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsStream(RealmModel realm, Stream<String> ids, String search, Integer first, Integer max) {
|
||||
return session.groupLocalStorage().getGroupsStream(realm, ids, search, first, max);
|
||||
return localStorage().getGroupsStream(realm, ids, search, first, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getGroupsCount(RealmModel realm, Boolean onlyTopGroups) {
|
||||
return session.groupLocalStorage().getGroupsCount(realm, onlyTopGroups);
|
||||
return localStorage().getGroupsCount(realm, onlyTopGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getGroupsCountByNameContaining(RealmModel realm, String search) {
|
||||
return session.groupLocalStorage().getGroupsCountByNameContaining(realm, search);
|
||||
return localStorage().getGroupsCountByNameContaining(realm, search);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsByRoleStream(RealmModel realm, RoleModel role, Integer firstResult, Integer maxResults) {
|
||||
return session.groupLocalStorage().getGroupsByRoleStream(realm, role, firstResult, maxResults);
|
||||
return localStorage().getGroupsByRoleStream(realm, role, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm) {
|
||||
return session.groupLocalStorage().getTopLevelGroupsStream(realm);
|
||||
return localStorage().getTopLevelGroupsStream(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm, Integer firstResult, Integer maxResults) {
|
||||
return session.groupLocalStorage().getTopLevelGroupsStream(realm, firstResult, maxResults);
|
||||
return localStorage().getTopLevelGroupsStream(realm, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel createGroup(RealmModel realm, String id, String name, GroupModel toParent) {
|
||||
return session.groupLocalStorage().createGroup(realm, id, name, toParent);
|
||||
return localStorage().createGroup(realm, id, name, toParent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(RealmModel realm, GroupModel group) {
|
||||
return session.groupLocalStorage().removeGroup(realm, group);
|
||||
return localStorage().removeGroup(realm, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveGroup(RealmModel realm, GroupModel group, GroupModel toParent) {
|
||||
session.groupLocalStorage().moveGroup(realm, group, toParent);
|
||||
localStorage().moveGroup(realm, group, toParent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTopLevelGroup(RealmModel realm, GroupModel subGroup) {
|
||||
session.groupLocalStorage().addTopLevelGroup(realm, subGroup);
|
||||
localStorage().addTopLevelGroup(realm, subGroup);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -45,6 +45,10 @@ public class RoleStorageManager implements RoleProvider {
|
|||
this.roleStorageProviderTimeout = roleStorageProviderTimeout;
|
||||
}
|
||||
|
||||
private RoleProvider localStorage() {
|
||||
return session.getProvider(RoleProvider.class);
|
||||
}
|
||||
|
||||
public static boolean isStorageProviderEnabled(RealmModel realm, String providerId) {
|
||||
RoleStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||
return model.isEnabled();
|
||||
|
@ -114,17 +118,17 @@ public class RoleStorageManager implements RoleProvider {
|
|||
|
||||
@Override
|
||||
public RoleModel addRealmRole(RealmModel realm, String name) {
|
||||
return session.roleLocalStorage().addRealmRole(realm, name);
|
||||
return localStorage().addRealmRole(realm, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel addRealmRole(RealmModel realm, String id, String name) {
|
||||
return session.roleLocalStorage().addRealmRole(realm, id, name);
|
||||
return localStorage().addRealmRole(realm, id, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel getRealmRole(RealmModel realm, String name) {
|
||||
RoleModel realmRole = session.roleLocalStorage().getRealmRole(realm, name);
|
||||
RoleModel realmRole = localStorage().getRealmRole(realm, name);
|
||||
if (realmRole != null) return realmRole;
|
||||
return getEnabledStorageProviders(session, realm, RoleLookupProvider.class)
|
||||
.map(provider -> provider.getRealmRole(realm, name))
|
||||
|
@ -137,7 +141,7 @@ public class RoleStorageManager implements RoleProvider {
|
|||
public RoleModel getRoleById(RealmModel realm, String id) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
if (storageId.getProviderId() == null) {
|
||||
return session.roleLocalStorage().getRoleById(realm, id);
|
||||
return localStorage().getRoleById(realm, id);
|
||||
}
|
||||
RoleLookupProvider provider = (RoleLookupProvider)getStorageProvider(session, realm, storageId.getProviderId());
|
||||
if (provider == null) return null;
|
||||
|
@ -147,12 +151,12 @@ public class RoleStorageManager implements RoleProvider {
|
|||
|
||||
@Override
|
||||
public Stream<RoleModel> getRealmRolesStream(RealmModel realm, Integer first, Integer max) {
|
||||
return session.roleLocalStorage().getRealmRolesStream(realm, first, max);
|
||||
return localStorage().getRealmRolesStream(realm, first, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<RoleModel> getRolesStream(RealmModel realm, Stream<String> ids, String search, Integer first, Integer max) {
|
||||
return session.roleLocalStorage().getRolesStream(realm, ids, search, first, max);
|
||||
return localStorage().getRolesStream(realm, ids, search, first, max);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +168,7 @@ public class RoleStorageManager implements RoleProvider {
|
|||
*/
|
||||
@Override
|
||||
public Stream<RoleModel> searchForRolesStream(RealmModel realm, String search, Integer first, Integer max) {
|
||||
Stream<RoleModel> local = session.roleLocalStorage().searchForRolesStream(realm, search, first, max);
|
||||
Stream<RoleModel> local = localStorage().searchForRolesStream(realm, search, first, max);
|
||||
Stream<RoleModel> ext = getEnabledStorageProviders(session, realm, RoleLookupProvider.class)
|
||||
.flatMap(ServicesUtils.timeBound(session,
|
||||
roleStorageProviderTimeout,
|
||||
|
@ -178,32 +182,32 @@ public class RoleStorageManager implements RoleProvider {
|
|||
if (!StorageId.isLocalStorage(role.getId())) {
|
||||
throw new RuntimeException("Federated roles do not support this operation");
|
||||
}
|
||||
return session.roleLocalStorage().removeRole(role);
|
||||
return localStorage().removeRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoles(RealmModel realm) {
|
||||
session.roleLocalStorage().removeRoles(realm);
|
||||
localStorage().removeRoles(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoles(ClientModel client) {
|
||||
session.roleLocalStorage().removeRoles(client);
|
||||
localStorage().removeRoles(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel addClientRole(ClientModel client, String name) {
|
||||
return session.roleLocalStorage().addClientRole(client, name);
|
||||
return localStorage().addClientRole(client, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel addClientRole(ClientModel client, String id, String name) {
|
||||
return session.roleLocalStorage().addClientRole(client, id, name);
|
||||
return localStorage().addClientRole(client, id, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel getClientRole(ClientModel client, String name) {
|
||||
RoleModel clientRole = session.roleLocalStorage().getClientRole(client, name);
|
||||
RoleModel clientRole = localStorage().getClientRole(client, name);
|
||||
if (clientRole != null) return clientRole;
|
||||
return getEnabledStorageProviders(session, client.getRealm(), RoleLookupProvider.class)
|
||||
.map(provider -> provider.getClientRole(client, name))
|
||||
|
@ -214,12 +218,12 @@ public class RoleStorageManager implements RoleProvider {
|
|||
|
||||
@Override
|
||||
public Stream<RoleModel> getClientRolesStream(ClientModel client) {
|
||||
return session.roleLocalStorage().getClientRolesStream(client);
|
||||
return localStorage().getClientRolesStream(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<RoleModel> getClientRolesStream(ClientModel client, Integer first, Integer max) {
|
||||
return session.roleLocalStorage().getClientRolesStream(client, first, max);
|
||||
return localStorage().getClientRolesStream(client, first, max);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,7 +235,7 @@ public class RoleStorageManager implements RoleProvider {
|
|||
*/
|
||||
@Override
|
||||
public Stream<RoleModel> searchForClientRolesStream(ClientModel client, String search, Integer first, Integer max) {
|
||||
Stream<RoleModel> local = session.roleLocalStorage().searchForClientRolesStream(client, search, first, max);
|
||||
Stream<RoleModel> local = localStorage().searchForClientRolesStream(client, search, first, max);
|
||||
Stream<RoleModel> ext = getEnabledStorageProviders(session, client.getRealm(), RoleLookupProvider.class)
|
||||
.flatMap(ServicesUtils.timeBound(session,
|
||||
roleStorageProviderTimeout,
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright 2022 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.
|
||||
#
|
||||
|
||||
org.keycloak.storage.datastore.LegacyDatastoreProviderFactory
|
|
@ -0,0 +1,157 @@
|
|||
package org.keycloak.storage.datastore;
|
||||
|
||||
import org.keycloak.models.ClientProvider;
|
||||
import org.keycloak.models.ClientScopeProvider;
|
||||
import org.keycloak.models.GroupProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleProvider;
|
||||
import org.keycloak.models.cache.CacheRealmProvider;
|
||||
import org.keycloak.storage.ClientScopeStorageManager;
|
||||
import org.keycloak.storage.ClientStorageManager;
|
||||
import org.keycloak.storage.DatastoreProvider;
|
||||
import org.keycloak.storage.GroupStorageManager;
|
||||
import org.keycloak.storage.RoleStorageManager;
|
||||
|
||||
public class LegacyDatastoreProvider implements DatastoreProvider {
|
||||
|
||||
private final LegacyDatastoreProviderFactory factory;
|
||||
private final KeycloakSession session;
|
||||
|
||||
private ClientProvider clientProvider;
|
||||
private ClientScopeProvider clientScopeProvider;
|
||||
private GroupProvider groupProvider;
|
||||
private RealmProvider realmProvider;
|
||||
private RoleProvider roleProvider;
|
||||
|
||||
private ClientScopeStorageManager clientScopeStorageManager;
|
||||
private RoleStorageManager roleStorageManager;
|
||||
private GroupStorageManager groupStorageManager;
|
||||
private ClientStorageManager clientStorageManager;
|
||||
|
||||
public LegacyDatastoreProvider(LegacyDatastoreProviderFactory factory, KeycloakSession session) {
|
||||
this.factory = factory;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public ClientProvider clientStorageManager() {
|
||||
if (clientStorageManager == null) {
|
||||
clientStorageManager = new ClientStorageManager(session, factory.getClientStorageProviderTimeout());
|
||||
}
|
||||
return clientStorageManager;
|
||||
}
|
||||
|
||||
public ClientScopeProvider clientScopeStorageManager() {
|
||||
if (clientScopeStorageManager == null) {
|
||||
clientScopeStorageManager = new ClientScopeStorageManager(session);
|
||||
}
|
||||
return clientScopeStorageManager;
|
||||
}
|
||||
|
||||
public RoleProvider roleStorageManager() {
|
||||
if (roleStorageManager == null) {
|
||||
roleStorageManager = new RoleStorageManager(session, factory.getRoleStorageProviderTimeout());
|
||||
}
|
||||
return roleStorageManager;
|
||||
}
|
||||
|
||||
public GroupProvider groupStorageManager() {
|
||||
if (groupStorageManager == null) {
|
||||
groupStorageManager = new GroupStorageManager(session);
|
||||
}
|
||||
return groupStorageManager;
|
||||
}
|
||||
|
||||
private ClientProvider getClientProvider() {
|
||||
// TODO: Extract ClientProvider from CacheRealmProvider and use that instead
|
||||
ClientProvider cache = session.getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return clientStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
private ClientScopeProvider getClientScopeProvider() {
|
||||
// TODO: Extract ClientScopeProvider from CacheRealmProvider and use that instead
|
||||
ClientScopeProvider cache = session.getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return clientScopeStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
private GroupProvider getGroupProvider() {
|
||||
// TODO: Extract GroupProvider from CacheRealmProvider and use that instead
|
||||
GroupProvider cache = session.getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return groupStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
private RealmProvider getRealmProvider() {
|
||||
CacheRealmProvider cache = session.getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return session.getProvider(RealmProvider.class);
|
||||
}
|
||||
}
|
||||
|
||||
private RoleProvider getRoleProvider() {
|
||||
// TODO: Extract RoleProvider from CacheRealmProvider and use that instead
|
||||
RoleProvider cache = session.getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return roleStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientProvider clients() {
|
||||
if (clientProvider == null) {
|
||||
clientProvider = getClientProvider();
|
||||
}
|
||||
return clientProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientScopeProvider clientScopes() {
|
||||
if (clientScopeProvider == null) {
|
||||
clientScopeProvider = getClientScopeProvider();
|
||||
}
|
||||
return clientScopeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupProvider groups() {
|
||||
if (groupProvider == null) {
|
||||
groupProvider = getGroupProvider();
|
||||
}
|
||||
return groupProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmProvider realms() {
|
||||
if (realmProvider == null) {
|
||||
realmProvider = getRealmProvider();
|
||||
}
|
||||
return realmProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleProvider roles() {
|
||||
if (roleProvider == null) {
|
||||
roleProvider = getRoleProvider();
|
||||
}
|
||||
return roleProvider;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.keycloak.storage.datastore;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.storage.DatastoreProvider;
|
||||
import org.keycloak.storage.DatastoreProviderFactory;
|
||||
|
||||
public class LegacyDatastoreProviderFactory implements DatastoreProviderFactory {
|
||||
|
||||
private static final String PROVIDER_ID = "legacy";
|
||||
private long clientStorageProviderTimeout;
|
||||
private long roleStorageProviderTimeout;
|
||||
|
||||
@Override
|
||||
public DatastoreProvider create(KeycloakSession session) {
|
||||
return new LegacyDatastoreProvider(this, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Scope config) {
|
||||
clientStorageProviderTimeout = Config.scope("client").getLong("storageProviderTimeout", 3000L);
|
||||
roleStorageProviderTimeout = Config.scope("role").getLong("storageProviderTimeout", 3000L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
public long getClientStorageProviderTimeout() {
|
||||
return clientStorageProviderTimeout;
|
||||
}
|
||||
|
||||
public long getRoleStorageProviderTimeout() {
|
||||
return roleStorageProviderTimeout;
|
||||
}
|
||||
|
||||
}
|
134
model/legacy/src/main/java/org/keycloak/utils/ServicesUtils.java
Normal file
134
model/legacy/src/main/java/org/keycloak/utils/ServicesUtils.java
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.utils;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.executors.ExecutorsProvider;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
||||
|
||||
/**
|
||||
* Utility class for general helper methods used across the keycloak-services.
|
||||
*/
|
||||
public class ServicesUtils {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ServicesUtils.class);
|
||||
|
||||
public static <T, R> Function<? super T,? extends Stream<? extends R>> timeBound(KeycloakSession session,
|
||||
long timeout,
|
||||
Function<T, ? extends Stream<R>> func) {
|
||||
ExecutorService executor = session.getProvider(ExecutorsProvider.class).getExecutor("storage-provider-threads");
|
||||
return p -> {
|
||||
// We are running another thread here, which serves as a time checking thread. When timeout is hit, the time
|
||||
// checking thread will send interrupted flag to main thread, which can cause interruption of func execution.
|
||||
// To support interruption func implementation should react to interrupt flag.
|
||||
// If func doesn't check the interrupted flag, the execution won't be interrupted and can take more time
|
||||
// than the threshold given by timeout variable
|
||||
Future<?> timeCheckingThread = executor.submit(timeWarningRunnable(timeout, Thread.currentThread()));
|
||||
try {
|
||||
// We cannot run func in different than main thread, because main thread have, for example, EntityManager
|
||||
// transaction context. If we run any operation on EntityManager in a different thread, it will fail
|
||||
// with a transaction doesn't exist error
|
||||
return func.apply(p);
|
||||
} finally {
|
||||
timeCheckingThread.cancel(true);
|
||||
|
||||
if (Thread.interrupted()) {
|
||||
logger.warnf("Execution with object [%s] exceeded specified time limit %d. %s", p, timeout, getShortStackTrace());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, R> Function<? super T, R> timeBoundOne(KeycloakSession session,
|
||||
long timeout,
|
||||
Function<T, R> func) {
|
||||
ExecutorService executor = session.getProvider(ExecutorsProvider.class).getExecutor("storage-provider-threads");
|
||||
return p -> {
|
||||
// We are running another thread here, which serves as a time checking thread. When timeout is hit, the time
|
||||
// checking thread will send interrupted flag to main thread, which can cause interruption of func execution.
|
||||
// To support interruption func implementation should react to interrupt flag.
|
||||
// If func doesn't check the interrupted flag, the execution won't be interrupted and can take more time
|
||||
// than the threshold given by timeout variable
|
||||
Future<?> warningThreadFuture = executor.submit(timeWarningRunnable(timeout, Thread.currentThread()));
|
||||
try {
|
||||
// We cannot run func in different than main thread, because main thread have, for example, EntityManager
|
||||
// transaction context. If we run any operation on EntityManager in a different thread, it will fail
|
||||
// with a transaction doesn't exist error
|
||||
return func.apply(p);
|
||||
} finally {
|
||||
warningThreadFuture.cancel(true);
|
||||
|
||||
if (Thread.interrupted()) {
|
||||
logger.warnf("Execution with object [%s] exceeded specified time limit %d. %s", p, timeout, getShortStackTrace());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> Consumer<? super T> consumeWithTimeBound(KeycloakSession session,
|
||||
long timeout,
|
||||
Consumer<T> func) {
|
||||
ExecutorService executor = session.getProvider(ExecutorsProvider.class).getExecutor("storage-provider-threads");
|
||||
return p -> {
|
||||
// We are running another thread here, which serves as a time checking thread. When timeout is hit, the time
|
||||
// checking thread will send interrupted flag to main thread, which can cause interruption of func execution.
|
||||
// To support interruption func implementation should react to interrupt flag.
|
||||
// If func doesn't check the interrupted flag, the execution won't be interrupted and can take more time
|
||||
// than the threshold given by timeout variable
|
||||
Future<?> warningThreadFuture = executor.submit(timeWarningRunnable(timeout, Thread.currentThread()));
|
||||
try {
|
||||
// We cannot run func in different than main thread, because main thread have, for example, EntityManager
|
||||
// transaction context. If we run any operation on EntityManager in a different thread, it will fail
|
||||
// with a transaction doesn't exist error
|
||||
func.accept(p);
|
||||
} finally {
|
||||
warningThreadFuture.cancel(true);
|
||||
|
||||
if (Thread.interrupted()) {
|
||||
logger.warnf("Execution with object [%s] exceeded specified time limit %d. %s", p, timeout, getShortStackTrace());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Runnable timeWarningRunnable(long timeout, Thread mainThread) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(timeout);
|
||||
} catch (InterruptedException exception) {
|
||||
return; // Do not interrupt if warning thread was interrupted (== main thread finished execution in time)
|
||||
}
|
||||
|
||||
mainThread.interrupt();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -124,6 +124,10 @@ public class ModelToRepresentation {
|
|||
}
|
||||
|
||||
|
||||
public static GroupRepresentation groupToBriefRepresentation(GroupModel g) {
|
||||
return toRepresentation(g, false);
|
||||
}
|
||||
|
||||
public static GroupRepresentation toRepresentation(GroupModel group, boolean full) {
|
||||
GroupRepresentation rep = new GroupRepresentation();
|
||||
rep.setId(group.getId());
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package org.keycloak.storage;
|
||||
|
||||
import org.keycloak.models.ClientProvider;
|
||||
import org.keycloak.models.ClientScopeProvider;
|
||||
import org.keycloak.models.GroupProvider;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleProvider;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
public interface DatastoreProvider extends Provider {
|
||||
|
||||
public ClientScopeProvider clientScopes();
|
||||
|
||||
public ClientProvider clients();
|
||||
|
||||
public GroupProvider groups();
|
||||
|
||||
public RealmProvider realms();
|
||||
|
||||
public RoleProvider roles();
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.keycloak.storage;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
public interface DatastoreProviderFactory extends ProviderFactory<DatastoreProvider> {
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.storage;
|
||||
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
public class DatastoreSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "datastore";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<DatastoreProvider> getProviderClass() {
|
||||
return DatastoreProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<DatastoreProviderFactory> getProviderFactoryClass() {
|
||||
return DatastoreProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -80,6 +80,7 @@ org.keycloak.credential.hash.PasswordHashSpi
|
|||
org.keycloak.credential.CredentialSpi
|
||||
org.keycloak.keys.PublicKeyStorageSpi
|
||||
org.keycloak.keys.KeySpi
|
||||
org.keycloak.storage.DatastoreSpi
|
||||
org.keycloak.storage.client.ClientStorageProviderSpi
|
||||
org.keycloak.storage.clientscope.ClientScopeStorageProviderSpi
|
||||
org.keycloak.storage.role.RoleStorageProviderSpi
|
||||
|
|
|
@ -225,6 +225,7 @@ public interface KeycloakSession {
|
|||
|
||||
/**
|
||||
* @return ClientScopeStorageManager instance
|
||||
* @deprecated Use {@link #clientScopes()} instead
|
||||
*/
|
||||
ClientScopeProvider clientScopeStorageManager();
|
||||
|
||||
|
@ -271,6 +272,7 @@ public interface KeycloakSession {
|
|||
/**
|
||||
* Keycloak specific local storage for client scopes. No cache in front, this api talks directly to database configured for Keycloak
|
||||
*
|
||||
* @deprecated Use {@link #clientScopes()} instead
|
||||
* @return
|
||||
*/
|
||||
ClientScopeProvider clientScopeLocalStorage();
|
||||
|
|
|
@ -80,7 +80,7 @@ public class RedirectUtils {
|
|||
@Deprecated
|
||||
private static Set<String> getValidateRedirectUris(KeycloakSession session) {
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
return session.clientStorageManager().getAllRedirectUrisOfEnabledClients(realm).entrySet().stream()
|
||||
return session.clients().getAllRedirectUrisOfEnabledClients(realm).entrySet().stream()
|
||||
.filter(me -> me.getKey().isEnabled() && OIDCLoginProtocol.LOGIN_PROTOCOL.equals(me.getKey().getProtocol()) && !me.getKey().isBearerOnly() && (me.getKey().isStandardFlowEnabled() || me.getKey().isImplicitFlowEnabled()))
|
||||
.map(me -> resolveValidRedirects(session, me.getKey().getRootUrl(), me.getValue()))
|
||||
.flatMap(Collection::stream)
|
||||
|
|
|
@ -24,33 +24,29 @@ import org.keycloak.keys.DefaultKeyManager;
|
|||
import org.keycloak.models.ClientProvider;
|
||||
import org.keycloak.models.ClientScopeProvider;
|
||||
import org.keycloak.models.GroupProvider;
|
||||
import org.keycloak.models.UserLoginFailureProvider;
|
||||
import org.keycloak.models.TokenManager;
|
||||
import org.keycloak.models.KeyManager;
|
||||
import org.keycloak.models.KeycloakContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakTransactionManager;
|
||||
import org.keycloak.models.KeyManager;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleProvider;
|
||||
import org.keycloak.models.ThemeManager;
|
||||
import org.keycloak.models.TokenManager;
|
||||
import org.keycloak.models.UserCredentialManager;
|
||||
import org.keycloak.models.UserLoginFailureProvider;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.cache.CacheRealmProvider;
|
||||
import org.keycloak.models.cache.UserCache;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
|
||||
import org.keycloak.provider.InvalidationHandler.ObjectType;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
|
||||
import org.keycloak.provider.InvalidationHandler.ObjectType;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyManager;
|
||||
import org.keycloak.sessions.AuthenticationSessionProvider;
|
||||
import org.keycloak.storage.ClientStorageManager;
|
||||
import org.keycloak.storage.ClientScopeStorageManager;
|
||||
import org.keycloak.storage.GroupStorageManager;
|
||||
import org.keycloak.storage.RoleStorageManager;
|
||||
import org.keycloak.storage.DatastoreProvider;
|
||||
import org.keycloak.storage.UserStorageManager;
|
||||
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
||||
import org.keycloak.vault.DefaultVaultTranscriber;
|
||||
|
@ -80,16 +76,8 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
private final DefaultKeycloakTransactionManager transactionManager;
|
||||
private final Map<String, Object> attributes = new HashMap<>();
|
||||
private final Map<InvalidableObjectType, Set<Object>> invalidationMap = new HashMap<>();
|
||||
private RealmProvider model;
|
||||
private ClientProvider clientProvider;
|
||||
private ClientScopeProvider clientScopeProvider;
|
||||
private GroupProvider groupProvider;
|
||||
private RoleProvider roleProvider;
|
||||
private DatastoreProvider datastoreProvider;
|
||||
private UserStorageManager userStorageManager;
|
||||
private ClientStorageManager clientStorageManager;
|
||||
private ClientScopeStorageManager clientScopeStorageManager;
|
||||
private RoleStorageManager roleStorageManager;
|
||||
private GroupStorageManager groupStorageManager;
|
||||
private UserCredentialStoreManager userCredentialStorageManager;
|
||||
private UserSessionProvider sessionProvider;
|
||||
private UserLoginFailureProvider userLoginFailureProvider;
|
||||
|
@ -113,53 +101,11 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
return context;
|
||||
}
|
||||
|
||||
private RealmProvider getRealmProvider() {
|
||||
CacheRealmProvider cache = getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return getProvider(RealmProvider.class);
|
||||
}
|
||||
}
|
||||
|
||||
private ClientProvider getClientProvider() {
|
||||
// TODO: Extract ClientProvider from CacheRealmProvider and use that instead
|
||||
ClientProvider cache = getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return clientStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
private ClientScopeProvider getClientScopeProvider() {
|
||||
// TODO: Extract ClientScopeProvider from CacheRealmProvider and use that instead
|
||||
ClientScopeProvider cache = getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return clientScopeStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
private GroupProvider getGroupProvider() {
|
||||
// TODO: Extract GroupProvider from CacheRealmProvider and use that instead
|
||||
GroupProvider cache = getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return groupStorageManager();
|
||||
}
|
||||
}
|
||||
|
||||
private RoleProvider getRoleProvider() {
|
||||
// TODO: Extract RoleProvider from CacheRealmProvider and use that instead
|
||||
RoleProvider cache = getProvider(CacheRealmProvider.class);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
} else {
|
||||
return roleStorageManager();
|
||||
private DatastoreProvider getDatastoreProvider() {
|
||||
if (this.datastoreProvider == null) {
|
||||
this.datastoreProvider = getProvider(DatastoreProvider.class);
|
||||
}
|
||||
return this.datastoreProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -228,59 +174,47 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
|
||||
@Override
|
||||
public RealmProvider realmLocalStorage() {
|
||||
return getProvider(RealmProvider.class);
|
||||
return realms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientProvider clientLocalStorage() {
|
||||
return getProvider(ClientProvider.class);
|
||||
return clients();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientScopeProvider clientScopeLocalStorage() {
|
||||
return getProvider(ClientScopeProvider.class);
|
||||
return clientScopes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupProvider groupLocalStorage() {
|
||||
return getProvider(GroupProvider.class);
|
||||
return groups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientProvider clientStorageManager() {
|
||||
if (clientStorageManager == null) {
|
||||
clientStorageManager = new ClientStorageManager(this, factory.getClientStorageProviderTimeout());
|
||||
}
|
||||
return clientStorageManager;
|
||||
return clients();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientScopeProvider clientScopeStorageManager() {
|
||||
if (clientScopeStorageManager == null) {
|
||||
clientScopeStorageManager = new ClientScopeStorageManager(this);
|
||||
}
|
||||
return clientScopeStorageManager;
|
||||
return clientScopes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleProvider roleLocalStorage() {
|
||||
return getProvider(RoleProvider.class);
|
||||
return roles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleProvider roleStorageManager() {
|
||||
if (roleStorageManager == null) {
|
||||
roleStorageManager = new RoleStorageManager(this, factory.getRoleStorageProviderTimeout());
|
||||
}
|
||||
return roleStorageManager;
|
||||
return roles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupProvider groupStorageManager() {
|
||||
if (groupStorageManager == null) {
|
||||
groupStorageManager = new GroupStorageManager(this);
|
||||
}
|
||||
return groupStorageManager;
|
||||
return groups();
|
||||
}
|
||||
|
||||
|
||||
|
@ -413,42 +347,27 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
|
||||
@Override
|
||||
public RealmProvider realms() {
|
||||
if (model == null) {
|
||||
model = getRealmProvider();
|
||||
}
|
||||
return model;
|
||||
return getDatastoreProvider().realms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientProvider clients() {
|
||||
if (clientProvider == null) {
|
||||
clientProvider = getClientProvider();
|
||||
}
|
||||
return clientProvider;
|
||||
return getDatastoreProvider().clients();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientScopeProvider clientScopes() {
|
||||
if (clientScopeProvider == null) {
|
||||
clientScopeProvider = getClientScopeProvider();
|
||||
}
|
||||
return clientScopeProvider;
|
||||
return getDatastoreProvider().clientScopes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupProvider groups() {
|
||||
if (groupProvider == null) {
|
||||
groupProvider = getGroupProvider();
|
||||
}
|
||||
return groupProvider;
|
||||
return getDatastoreProvider().groups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleProvider roles() {
|
||||
if (roleProvider == null) {
|
||||
roleProvider = getRoleProvider();
|
||||
}
|
||||
return roleProvider;
|
||||
return getDatastoreProvider().roles();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ import javax.ws.rs.core.MediaType;
|
|||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
|
@ -99,6 +101,7 @@ import org.keycloak.representations.idm.ClientScopeRepresentation;
|
|||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.LDAPCapabilityRepresentation;
|
||||
import org.keycloak.representations.idm.ManagementPermissionReference;
|
||||
import org.keycloak.representations.idm.PartialImportRepresentation;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
|
@ -113,13 +116,9 @@ import org.keycloak.services.managers.UserStorageSyncManager;
|
|||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.representations.idm.LDAPCapabilityRepresentation;
|
||||
import org.keycloak.utils.ProfileHelper;
|
||||
import org.keycloak.utils.ReservedCharValidator;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.keycloak.utils.ServicesUtils;
|
||||
|
||||
/**
|
||||
* Base resource class for the admin REST api of one realm
|
||||
*
|
||||
|
@ -1037,7 +1036,7 @@ public class RealmAdminResource {
|
|||
public Stream<GroupRepresentation> getDefaultGroups() {
|
||||
auth.realm().requireViewRealm();
|
||||
|
||||
return realm.getDefaultGroupsStream().map(ServicesUtils::groupToBriefRepresentation);
|
||||
return realm.getDefaultGroupsStream().map(ModelToRepresentation::groupToBriefRepresentation);
|
||||
}
|
||||
@PUT
|
||||
@NoCache
|
||||
|
|
|
@ -34,6 +34,7 @@ import static org.keycloak.common.util.StackUtil.getShortStackTrace;
|
|||
|
||||
/**
|
||||
* Utility class for general helper methods used across the keycloak-services.
|
||||
* @deprecated - DELETE once only used from within legacy datastore module
|
||||
*/
|
||||
public class ServicesUtils {
|
||||
|
||||
|
@ -131,8 +132,4 @@ public class ServicesUtils {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static GroupRepresentation groupToBriefRepresentation(GroupModel g) {
|
||||
return ModelToRepresentation.toRepresentation(g, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,102 +193,102 @@
|
|||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jpa</id>
|
||||
<id>legacy-jpa</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Jpa</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpa</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa+infinispan</id>
|
||||
<id>legacy-jpa+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,Jpa</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>Infinispan,LegacyJpa</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa+infinispan+client-storage</id>
|
||||
<id>legacy-jpa+infinispan+client-storage</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Jpa,Infinispan,HardcodedClientStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpa,Infinispan,HardcodedClientStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa+cross-dc-infinispan</id>
|
||||
<id>legacy-jpa+cross-dc-infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>CrossDCInfinispan,Jpa</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>CrossDCInfinispan,LegacyJpa</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa+cross-dc-infinispan-offline-sessions-preloading</id>
|
||||
<id>legacy-jpa+cross-dc-infinispan-offline-sessions-preloading</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>CrossDCInfinispan,Jpa</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>CrossDCInfinispan,LegacyJpa</keycloak.model.parameters>
|
||||
<keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>true</keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa+infinispan-offline-sessions-preloading</id>
|
||||
<id>legacy-jpa+infinispan-offline-sessions-preloading</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,Jpa</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>Infinispan,LegacyJpa</keycloak.model.parameters>
|
||||
<keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>true</keycloak.userSessions.infinispan.preloadOfflineSessionsFromDatabase>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation+infinispan</id>
|
||||
<id>legacy-jpa-federation+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,JpaFederation,TestsuiteUserMapStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>Infinispan,LegacyJpaFederation,TestsuiteUserMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation-backward+infinispan</id>
|
||||
<id>legacy-jpa-federation-backward+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>Infinispan,JpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>Infinispan,LegacyJpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation</id>
|
||||
<id>legacy-jpa-federation</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,TestsuiteUserMapStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpaFederation,TestsuiteUserMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation-backward</id>
|
||||
<id>legacy-jpa-federation-backward</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpaFederation,BackwardsCompatibilityUserStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation-file-storage</id>
|
||||
<id>legacy-jpa-federation-file-storage</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,TestsuiteUserFileStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpaFederation,TestsuiteUserFileStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation-file-storage+infinispan</id>
|
||||
<id>legacy-jpa-federation-file-storage+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,TestsuiteUserFileStorage,Infinispan</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpaFederation,TestsuiteUserFileStorage,Infinispan</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation+ldap</id>
|
||||
<id>legacy-jpa-federation+ldap</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,LdapUserStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpaFederation,LdapUserStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>jpa-federation+ldap+infinispan</id>
|
||||
<id>legacy-jpa-federation+ldap+infinispan</id>
|
||||
<properties>
|
||||
<keycloak.model.parameters>JpaFederation,LdapUserStorage,Infinispan</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpaFederation,LdapUserStorage,Infinispan</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
|
@ -296,7 +296,7 @@
|
|||
<id>map</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Jpa,Map,ConcurrentHashMapStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpa,Map,ConcurrentHashMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
|
@ -304,7 +304,7 @@
|
|||
<id>hot-rod</id>
|
||||
<properties>
|
||||
<keycloak.profile.feature.map_storage>enabled</keycloak.profile.feature.map_storage>
|
||||
<keycloak.model.parameters>Jpa,Map,HotRodMapStorage</keycloak.model.parameters>
|
||||
<keycloak.model.parameters>LegacyJpa,Map,HotRodMapStorage</keycloak.model.parameters>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ import org.keycloak.models.jpa.JpaRoleProviderFactory;
|
|||
import org.keycloak.models.jpa.JpaUserProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.storage.DatastoreSpi;
|
||||
import org.keycloak.storage.datastore.LegacyDatastoreProviderFactory;
|
||||
import org.keycloak.testsuite.model.Config;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
|
@ -48,7 +50,7 @@ import org.keycloak.protocol.LoginProtocolSpi;
|
|||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class Jpa extends KeycloakModelParameters {
|
||||
public class LegacyJpa extends KeycloakModelParameters {
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
// jpa-specific
|
||||
|
@ -57,6 +59,8 @@ public class Jpa extends KeycloakModelParameters {
|
|||
.add(LiquibaseConnectionSpi.class)
|
||||
.add(UserSessionPersisterSpi.class)
|
||||
|
||||
.add(DatastoreSpi.class)
|
||||
|
||||
//required for migrateModel
|
||||
.add(MigrationSpi.class)
|
||||
.add(LoginProtocolSpi.class)
|
||||
|
@ -65,6 +69,8 @@ public class Jpa extends KeycloakModelParameters {
|
|||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
// jpa-specific
|
||||
.add(LegacyDatastoreProviderFactory.class)
|
||||
|
||||
.add(DefaultJpaConnectionProviderFactory.class)
|
||||
.add(JPAAuthorizationStoreFactory.class)
|
||||
.add(JpaClientProviderFactory.class)
|
||||
|
@ -85,7 +91,7 @@ public class Jpa extends KeycloakModelParameters {
|
|||
|
||||
.build();
|
||||
|
||||
public Jpa() {
|
||||
public LegacyJpa() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
|
@ -37,12 +37,12 @@ import org.keycloak.testsuite.model.Config;
|
|||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class JpaFederation extends KeycloakModelParameters {
|
||||
public class LegacyJpaFederation extends KeycloakModelParameters {
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
static final Set<Class<? extends Spi>> ALLOWED_SPIS = ImmutableSet.<Class<? extends Spi>>builder()
|
||||
.addAll(Jpa.ALLOWED_SPIS)
|
||||
.addAll(LegacyJpa.ALLOWED_SPIS)
|
||||
.add(UserStorageProviderSpi.class)
|
||||
.add(UserFederatedStorageProviderSpi.class)
|
||||
.add(ClientScopeStorageProviderSpi.class)
|
||||
|
@ -50,12 +50,12 @@ public class JpaFederation extends KeycloakModelParameters {
|
|||
.build();
|
||||
|
||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||
.addAll(Jpa.ALLOWED_FACTORIES)
|
||||
.addAll(LegacyJpa.ALLOWED_FACTORIES)
|
||||
.add(JpaUserFederatedStorageProviderFactory.class)
|
||||
.add(ClientScopeStorageProviderFactory.class)
|
||||
.build();
|
||||
|
||||
public JpaFederation() {
|
||||
public LegacyJpaFederation() {
|
||||
super(ALLOWED_SPIS, ALLOWED_FACTORIES);
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,6 @@ public class JpaFederation extends KeycloakModelParameters {
|
|||
|
||||
@Override
|
||||
public void updateConfig(Config cf) {
|
||||
Jpa.updateConfigForJpa(cf);
|
||||
LegacyJpa.updateConfigForJpa(cf);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue