From cb81a176119ae8be1009828dae537aee386a3f7e Mon Sep 17 00:00:00 2001 From: Alexander Schwartz Date: Wed, 20 Jul 2022 16:11:59 +0200 Subject: [PATCH] Disable Infinispan for map storage and avoid the component factory when creating a realm independent provider factory Provide startup time in UserSessionProvider independent of Infinispan, cleanup code that is not necessary for the map storage as it isn't using Clustering. Move classes to the legacy module. Closes #12972 --- .../InfinispanClusterProviderFactory.java | 8 ++++- ...ltInfinispanConnectionProviderFactory.java | 9 +++++- ...anStickySessionEncoderProviderFactory.java | 9 +++++- .../InfinispanUserSessionProvider.java | 6 ++++ .../InfinispanUserSessionProviderFactory.java | 9 +++++- .../cluster/ClusterProviderFactory.java | 0 .../java/org/keycloak/cluster/ClusterSpi.java | 0 .../ClusterAwareScheduledTaskRunner.java | 0 .../services/org.keycloak.provider.Spi | 1 + .../MapRootAuthenticationSessionProvider.java | 11 ------- .../authorization/MapAuthorizationStore.java | 15 +++++++-- .../MapAuthorizationStoreFactory.java | 23 +++++++------- .../common/AbstractMapProviderFactory.java | 31 +++++++++++++++---- .../events/MapEventStoreProviderFactory.java | 15 +++------ .../userSession/MapUserSessionProvider.java | 5 +++ .../org/keycloak/config/StorageOptions.java | 24 -------------- .../mappers/StoragePropertyMappers.java | 24 -------------- .../org/keycloak/cluster/ClusterProvider.java | 2 ++ .../services/org.keycloak.provider.Spi | 1 - .../keycloak/models/UserSessionProvider.java | 2 +- .../keycloak/protocol/oidc/TokenManager.java | 6 ++-- .../model/infinispan/InfinispanTestUtil.java | 24 ++++++++------ .../rest/TestingResourceProvider.java | 2 +- ...urceOwnerPasswordCredentialsGrantTest.java | 6 ++++ .../session/LastSessionRefreshUnitTest.java | 7 +++++ .../session/UserSessionProviderModelTest.java | 2 +- .../UserSessionProviderOfflineModelTest.java | 4 +-- 27 files changed, 133 insertions(+), 113 deletions(-) rename {server-spi-private => model/legacy-private}/src/main/java/org/keycloak/cluster/ClusterProviderFactory.java (100%) rename {server-spi-private => model/legacy-private}/src/main/java/org/keycloak/cluster/ClusterSpi.java (100%) rename {server-spi-private => model/legacy-private}/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java (100%) diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java index ad269a5290..fad33fb93c 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java @@ -30,6 +30,7 @@ import org.jboss.logging.Logger; import org.keycloak.Config; import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProviderFactory; +import org.keycloak.common.Profile; import org.keycloak.common.util.Retry; import org.keycloak.common.util.Time; import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory; @@ -38,6 +39,7 @@ import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.connections.infinispan.InfinispanUtil; +import org.keycloak.provider.EnvironmentDependentProviderFactory; import java.io.Serializable; import java.util.Collection; @@ -54,7 +56,7 @@ import java.util.stream.Collectors; * * @author Marek Posolda */ -public class InfinispanClusterProviderFactory implements ClusterProviderFactory { +public class InfinispanClusterProviderFactory implements ClusterProviderFactory, EnvironmentDependentProviderFactory { public static final String PROVIDER_ID = "infinispan"; @@ -190,6 +192,10 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory return PROVIDER_ID; } + @Override + public boolean isSupported() { + return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE); + } @Listener public class ViewChangeListener { diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java index 0fd18a1478..d353aacea2 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java @@ -38,6 +38,7 @@ import org.keycloak.cluster.ClusterEvent; import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ManagedCacheManagerProvider; import org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory; +import org.keycloak.common.Profile; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.cache.infinispan.ClearCacheEvent; @@ -45,6 +46,7 @@ import org.keycloak.models.cache.infinispan.events.RealmRemovedEvent; import org.keycloak.models.cache.infinispan.events.RealmUpdatedEvent; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.PostMigrationEvent; +import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.InvalidationHandler.ObjectType; import org.keycloak.provider.ProviderEvent; @@ -62,7 +64,7 @@ import static org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderF /** * @author Stian Thorgersen */ -public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory { +public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory, EnvironmentDependentProviderFactory { protected static final Logger logger = Logger.getLogger(DefaultInfinispanConnectionProviderFactory.class); @@ -490,4 +492,9 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon } }); } + + @Override + public boolean isSupported() { + return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE); + } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java index 4dd147f764..d6f6095e0c 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java @@ -19,8 +19,10 @@ package org.keycloak.models.sessions.infinispan; import org.jboss.logging.Logger; import org.keycloak.Config; +import org.keycloak.common.Profile; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderConfigurationBuilder; import org.keycloak.sessions.StickySessionEncoderProvider; @@ -32,7 +34,7 @@ import java.util.List; /** * @author Marek Posolda */ -public class InfinispanStickySessionEncoderProviderFactory implements StickySessionEncoderProviderFactory { +public class InfinispanStickySessionEncoderProviderFactory implements StickySessionEncoderProviderFactory, EnvironmentDependentProviderFactory { private static final Logger log = Logger.getLogger(InfinispanStickySessionEncoderProviderFactory.class); @@ -87,4 +89,9 @@ public class InfinispanStickySessionEncoderProviderFactory implements StickySess .add() .build(); } + + @Override + public boolean isSupported() { + return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE); + } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java index 90a9bfe47a..4bd612e911 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java @@ -709,6 +709,12 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { public void close() { } + @Override + public int getStartupTime(RealmModel realm) { + // TODO: take realm.getNotBefore() into account? + return session.getProvider(ClusterProvider.class).getClusterStartupTime(); + } + protected void removeUserSession(UserSessionEntity sessionEntity, boolean offline) { InfinispanChangelogBasedTransaction userSessionUpdateTx = getTransaction(offline); InfinispanChangelogBasedTransaction clientSessionUpdateTx = getClientSessionTransaction(offline); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java index 6b1ac6799e..3d1d37c5a0 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java @@ -23,6 +23,7 @@ import org.infinispan.persistence.remote.RemoteStore; import org.jboss.logging.Logger; import org.keycloak.Config; import org.keycloak.cluster.ClusterProvider; +import org.keycloak.common.Profile; import org.keycloak.common.util.Environment; import org.keycloak.common.util.Time; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; @@ -58,6 +59,7 @@ import org.keycloak.models.sessions.infinispan.util.SessionTimeouts; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.PostMigrationEvent; import org.keycloak.models.utils.ResetTimeOffsetEvent; +import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.ProviderEventListener; @@ -67,7 +69,7 @@ import java.util.UUID; import java.util.function.BiFunction; import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY; -public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory { +public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory, EnvironmentDependentProviderFactory { private static final Logger log = Logger.getLogger(InfinispanUserSessionProviderFactory.class); @@ -350,5 +352,10 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider public int order() { return PROVIDER_PRIORITY; } + + @Override + public boolean isSupported() { + return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE); + } } diff --git a/server-spi-private/src/main/java/org/keycloak/cluster/ClusterProviderFactory.java b/model/legacy-private/src/main/java/org/keycloak/cluster/ClusterProviderFactory.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/cluster/ClusterProviderFactory.java rename to model/legacy-private/src/main/java/org/keycloak/cluster/ClusterProviderFactory.java diff --git a/server-spi-private/src/main/java/org/keycloak/cluster/ClusterSpi.java b/model/legacy-private/src/main/java/org/keycloak/cluster/ClusterSpi.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/cluster/ClusterSpi.java rename to model/legacy-private/src/main/java/org/keycloak/cluster/ClusterSpi.java diff --git a/server-spi-private/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java b/model/legacy-private/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java similarity index 100% rename from server-spi-private/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java rename to model/legacy-private/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java diff --git a/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi index e04013fc00..08a9646d4e 100644 --- a/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi +++ b/model/legacy-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi @@ -22,3 +22,4 @@ org.keycloak.storage.client.ClientStorageProviderSpi org.keycloak.storage.group.GroupStorageProviderSpi org.keycloak.storage.clientscope.ClientScopeStorageProviderSpi org.keycloak.models.session.UserSessionPersisterSpi +org.keycloak.cluster.ClusterSpi diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java index d287d43bb6..1011df5748 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java @@ -54,8 +54,6 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi private final KeycloakSession session; protected final MapKeycloakTransaction tx; - private static final String AUTHENTICATION_SESSION_EVENTS = "AUTHENTICATION_SESSION_EVENTS"; - public MapRootAuthenticationSessionProvider(KeycloakSession session, MapStorage sessionStore) { this.session = session; this.tx = sessionStore.createTransaction(session); @@ -165,15 +163,6 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi return; } Objects.requireNonNull(authNotesFragment, "The provided authentication's notes map can't be null!"); - - ClusterProvider cluster = session.getProvider(ClusterProvider.class); - cluster.notify( - AUTHENTICATION_SESSION_EVENTS, - MapAuthenticationSessionAuthNoteUpdateEvent.create(compoundId.getRootSessionId(), compoundId.getTabId(), - compoundId.getClientUUID(), authNotesFragment), - true, - ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC - ); } @Override diff --git a/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStore.java b/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStore.java index 3a16fbbc47..0a078d04f1 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStore.java +++ b/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStore.java @@ -18,8 +18,18 @@ package org.keycloak.models.map.authorization; import org.keycloak.authorization.AuthorizationProvider; +import org.keycloak.authorization.model.PermissionTicket; +import org.keycloak.authorization.model.Policy; +import org.keycloak.authorization.model.Resource; +import org.keycloak.authorization.model.ResourceServer; +import org.keycloak.authorization.model.Scope; import org.keycloak.authorization.store.StoreFactory; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntity; +import org.keycloak.models.map.authorization.entity.MapPolicyEntity; +import org.keycloak.models.map.authorization.entity.MapResourceEntity; +import org.keycloak.models.map.authorization.entity.MapResourceServerEntity; +import org.keycloak.models.map.authorization.entity.MapScopeEntity; import org.keycloak.models.map.storage.MapStorage; @@ -35,8 +45,9 @@ public class MapAuthorizationStore implements StoreFactory { private final MapPermissionTicketStore permissionTicketStore; private boolean readOnly; - @SuppressWarnings("unchecked") - public MapAuthorizationStore(KeycloakSession session, MapStorage permissionTicketStore, MapStorage policyStore, MapStorage resourceServerStore, MapStorage resourceStore, MapStorage scopeStore, AuthorizationProvider provider) { + public MapAuthorizationStore(KeycloakSession session, MapStorage permissionTicketStore, + MapStorage policyStore, MapStorage resourceServerStore, + MapStorage resourceStore, MapStorage scopeStore, AuthorizationProvider provider) { this.permissionTicketStore = new MapPermissionTicketStore(session, permissionTicketStore, provider); this.policyStore = new MapPolicyStore(session, policyStore, provider); this.resourceServerStore = new MapResourceServerStore(session, resourceServerStore, provider); diff --git a/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStoreFactory.java b/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStoreFactory.java index 256ef8fa08..518ec02268 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStoreFactory.java +++ b/model/map/src/main/java/org/keycloak/models/map/authorization/MapAuthorizationStoreFactory.java @@ -17,7 +17,6 @@ package org.keycloak.models.map.authorization; -import java.util.concurrent.atomic.AtomicInteger; import org.keycloak.Config; import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.model.PermissionTicket; @@ -31,18 +30,20 @@ import org.keycloak.common.Profile; import org.keycloak.component.AmphibianProviderFactory; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.models.map.authorization.entity.MapPermissionTicketEntity; +import org.keycloak.models.map.authorization.entity.MapPolicyEntity; +import org.keycloak.models.map.authorization.entity.MapResourceEntity; +import org.keycloak.models.map.authorization.entity.MapResourceServerEntity; +import org.keycloak.models.map.authorization.entity.MapScopeEntity; import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorageProvider; -import org.keycloak.models.map.storage.MapStorageProviderFactory; -import org.keycloak.models.map.storage.MapStorageSpi; import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.InvalidationHandler; import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE; import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.RESOURCE_SERVER_BEFORE_REMOVE; import static org.keycloak.models.map.common.AbstractMapProviderFactory.uniqueCounter; -import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory; /** * @author mhajas @@ -60,16 +61,14 @@ public class MapAuthorizationStoreFactory implements AmphibianProviderFactory permissionTicketStore = mapStorageProvider.getStorage(PermissionTicket.class); + MapStorage policyStore = mapStorageProvider.getStorage(Policy.class); + MapStorage resourceServerStore = mapStorageProvider.getStorage(ResourceServer.class); + MapStorage resourceStore = mapStorageProvider.getStorage(Resource.class); + MapStorage scopeStore = mapStorageProvider.getStorage(Scope.class); authzStore = new MapAuthorizationStore(session, permissionTicketStore, diff --git a/model/map/src/main/java/org/keycloak/models/map/common/AbstractMapProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/common/AbstractMapProviderFactory.java index ae82410e1c..06abc2f617 100644 --- a/model/map/src/main/java/org/keycloak/models/map/common/AbstractMapProviderFactory.java +++ b/model/map/src/main/java/org/keycloak/models/map/common/AbstractMapProviderFactory.java @@ -20,9 +20,9 @@ import java.util.concurrent.atomic.AtomicInteger; import org.keycloak.Config.Scope; import org.keycloak.common.Profile; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelException; import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorageProvider; -import org.keycloak.models.map.storage.MapStorageSpi; import org.keycloak.component.AmphibianProviderFactory; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.provider.EnvironmentDependentProviderFactory; @@ -31,8 +31,6 @@ import org.keycloak.provider.Provider; import org.keycloak.provider.ProviderFactory; import org.jboss.logging.Logger; -import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory; - /** * * @author hmlnarik @@ -108,13 +106,34 @@ public abstract class AbstractMapProviderFactory getStorage(KeycloakSession session) { - ProviderFactory storageProviderFactory = getComponentFactory(session.getKeycloakSessionFactory(), - MapStorageProvider.class, storageConfigScope, MapStorageSpi.NAME); + ProviderFactory storageProviderFactory = getProviderFactoryOrComponentFactory(session, storageConfigScope); final MapStorageProvider factory = storageProviderFactory.create(session); - return factory.getStorage(modelType); } + public static ProviderFactory getProviderFactoryOrComponentFactory(KeycloakSession session, Scope storageConfigScope) { + ProviderFactory storageProviderFactory; + if (!hasRealmSpecificStorage(session, storageConfigScope)) { + String provider = storageConfigScope.get("provider"); + if (provider == null) { + storageProviderFactory = session.getKeycloakSessionFactory().getProviderFactory(MapStorageProvider.class); + } else { + storageProviderFactory = session.getKeycloakSessionFactory().getProviderFactory(MapStorageProvider.class, provider); + } + } else { + // If this is being implemented, make sure that the factory is being closed eventually. + // When no cluster provider is available, the componentFactory will not be cached and a new instance is being returned all the time + // when calling `getComponentFactory(session.getKeycloakSessionFactory(), MapStorageProvider.class, storageConfigScope, MapStorageSpi.NAME)`. + throw new ModelException("not supported yet"); + } + return storageProviderFactory; + } + + private static boolean hasRealmSpecificStorage(KeycloakSession session, Scope storageConfigScope) { + // Once there is functionality for a realm-specific storage, implement the logic on how to detect it here. + return false; + } + @Override public void postInit(KeycloakSessionFactory factory) { } diff --git a/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProviderFactory.java index 2256f04da0..5833362eb4 100644 --- a/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProviderFactory.java +++ b/model/map/src/main/java/org/keycloak/models/map/events/MapEventStoreProviderFactory.java @@ -30,14 +30,11 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorageProvider; -import org.keycloak.models.map.storage.MapStorageProviderFactory; -import org.keycloak.models.map.storage.MapStorageSpi; import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.InvalidationHandler; import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE; import static org.keycloak.models.map.common.AbstractMapProviderFactory.uniqueCounter; -import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory; public class MapEventStoreProviderFactory implements AmphibianProviderFactory, EnvironmentDependentProviderFactory, EventStoreProviderFactory, InvalidationHandler { @@ -62,15 +59,11 @@ public class MapEventStoreProviderFactory implements AmphibianProviderFactory adminEventsStore = factoryAe.getStorage(AdminEvent.class); - MapStorageProviderFactory storageProviderFactoryLe = (MapStorageProviderFactory) getComponentFactory(session.getKeycloakSessionFactory(), - MapStorageProvider.class, storageConfigScopeLoginEvents, MapStorageSpi.NAME); - final MapStorageProvider factoryLe = storageProviderFactoryLe.create(session); - MapStorage loginEventsStore = factoryLe.getStorage(Event.class); + final MapStorageProvider factoryLe = AbstractMapProviderFactory.getProviderFactoryOrComponentFactory(session, storageConfigScopeLoginEvents).create(session); + MapStorage loginEventsStore = factoryLe.getStorage(Event.class); provider = new MapEventStoreProvider(session, loginEventsStore, adminEventsStore); session.setAttribute(uniqueKey, provider); diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java index 4ed494be94..ed08bd1804 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java @@ -523,6 +523,11 @@ public class MapUserSessionProvider implements UserSessionProvider { } + @Override + public int getStartupTime(RealmModel realm) { + return realm.getNotBefore(); + } + /** * Removes all online and offline user sessions that belong to the provided {@link RealmModel}. * @param realm diff --git a/quarkus/config-api/src/main/java/org/keycloak/config/StorageOptions.java b/quarkus/config-api/src/main/java/org/keycloak/config/StorageOptions.java index 8091aeb498..67cee35cb2 100644 --- a/quarkus/config-api/src/main/java/org/keycloak/config/StorageOptions.java +++ b/quarkus/config-api/src/main/java/org/keycloak/config/StorageOptions.java @@ -218,24 +218,6 @@ public class StorageOptions { .buildTime(true) .build(); - public static final Option STORAGE_CACHE_ENABLED = new OptionBuilder<>("cache-enabled", Boolean.class) - .category(OptionCategory.STORAGE) - .hidden() - .buildTime(true) - .build(); - - public static final Option STORAGE_CACHE_CLUSTER_ENABLED = new OptionBuilder<>("cache-cluster-enabled", Boolean.class) - .category(OptionCategory.STORAGE) - .hidden() - .buildTime(true) - .build(); - - public static final Option STORAGE_CACHE_STICK_SESSION_ENABLED = new OptionBuilder<>("cache-stick-session-enabled", String.class) - .category(OptionCategory.STORAGE) - .hidden() - .buildTime(true) - .build(); - public static final Option STORAGE_CACHE_REALM_ENABLED = new OptionBuilder<>("cache-realm-enabled", String.class) .category(OptionCategory.STORAGE) .hidden() @@ -290,12 +272,6 @@ public class StorageOptions { .buildTime(true) .build(); - public static final Option STORAGE_CACHE_COMPONENT_FACTORY = new OptionBuilder<>("cache-component-factory-cache", String.class) - .category(OptionCategory.STORAGE) - .hidden() - .buildTime(true) - .build(); - public static final Option STORAGE_LEGACY_SESSION_SUPPORT = new OptionBuilder<>("storage-legacy-session-support", String.class) .category(OptionCategory.STORAGE) .hidden() diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/StoragePropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/StoragePropertyMappers.java index 8357bec35a..d6c54540cb 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/StoragePropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/StoragePropertyMappers.java @@ -229,12 +229,6 @@ final class StoragePropertyMappers { .transformer(StoragePropertyMappers::resolveMapStorageProvider) .paramLabel("type") .build(), - fromOption(StorageOptions.STORAGE_CACHE_COMPONENT_FACTORY) - .to("kc.spi-component-factory-default-caching-forced") - .mapFrom("storage") - .transformer(StoragePropertyMappers::isForceComponentFactoryCache) - .paramLabel("type") - .build(), fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORE) .to("kc.spi-public-key-storage-map-storage-provider") .mapFrom("storage") @@ -247,24 +241,6 @@ final class StoragePropertyMappers { .transformer(StoragePropertyMappers::isLegacyStoreEnabled) .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) .build(), - fromOption(StorageOptions.STORAGE_CACHE_ENABLED) - .to("kc.spi-connections-infinispan-default-enabled") - .mapFrom("storage") - .transformer(StoragePropertyMappers::isLegacyStoreEnabled) - .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) - .build(), - fromOption(StorageOptions.STORAGE_CACHE_CLUSTER_ENABLED) - .to("kc.spi-cluster-infinispan-enabled") - .mapFrom("storage") - .transformer(StoragePropertyMappers::isLegacyStoreEnabled) - .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) - .build(), - fromOption(StorageOptions.STORAGE_CACHE_STICK_SESSION_ENABLED) - .to("kc.spi-sticky-session-encoder-infinispan-enabled") - .mapFrom("storage") - .transformer(StoragePropertyMappers::isLegacyStoreEnabled) - .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) - .build(), fromOption(StorageOptions.STORAGE_CACHE_CLEAR_REALM) .to("kc.spi-admin-realm-restapi-extension-clear-realm-cache-enabled") .mapFrom("storage") diff --git a/server-spi-private/src/main/java/org/keycloak/cluster/ClusterProvider.java b/server-spi-private/src/main/java/org/keycloak/cluster/ClusterProvider.java index c1d59c5c0e..43ee99343d 100644 --- a/server-spi-private/src/main/java/org/keycloak/cluster/ClusterProvider.java +++ b/server-spi-private/src/main/java/org/keycloak/cluster/ClusterProvider.java @@ -27,7 +27,9 @@ import java.util.concurrent.Future; * Various utils related to clustering and concurrent tasks on cluster nodes * * @author Marek Posolda + * @deprecated This is only available when the legacy store is enabled. Support for this will be eventually removed. */ +@Deprecated public interface ClusterProvider extends Provider { /** diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi index 6d5febf873..65fd3e2d98 100755 --- a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi +++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi @@ -61,7 +61,6 @@ org.keycloak.authentication.ClientAuthenticatorSpi org.keycloak.authentication.RequiredActionSpi org.keycloak.authentication.FormAuthenticatorSpi org.keycloak.authentication.FormActionSpi -org.keycloak.cluster.ClusterSpi org.keycloak.authorization.policy.provider.PolicySpi org.keycloak.authorization.store.StoreFactorySpi org.keycloak.authorization.AuthorizationSpi diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java index 32c8237d6a..b8aa711a1a 100755 --- a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java @@ -277,5 +277,5 @@ public interface UserSessionProvider extends Provider { void close(); - + int getStartupTime(RealmModel realm); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java index 095a65ee11..3c6a286876 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java @@ -27,7 +27,6 @@ import org.keycloak.TokenVerifier; import org.keycloak.authentication.authenticators.util.AcrStore; import org.keycloak.broker.oidc.OIDCIdentityProvider; import org.keycloak.broker.provider.IdentityBrokerException; -import org.keycloak.cluster.ClusterProvider; import org.keycloak.common.ClientConnection; import org.keycloak.common.Profile; import org.keycloak.common.VerificationException; @@ -53,6 +52,7 @@ import org.keycloak.models.SingleUseObjectProvider; import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; +import org.keycloak.models.UserSessionProvider; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.RoleUtils; import org.keycloak.protocol.ProtocolMapperUtils; @@ -436,12 +436,12 @@ public class TokenManager { // Will throw OAuthErrorException if validation fails private void validateTokenReuse(KeycloakSession session, RealmModel realm, AccessToken refreshToken, AuthenticatedClientSessionModel clientSession, boolean refreshFlag) throws OAuthErrorException { - int clusterStartupTime = session.getProvider(ClusterProvider.class).getClusterStartupTime(); + int startupTime = session.getProvider(UserSessionProvider.class).getStartupTime(realm); if (clientSession.getCurrentRefreshToken() != null && !refreshToken.getId().equals(clientSession.getCurrentRefreshToken()) && refreshToken.getIssuedAt() < clientSession.getTimestamp() - && clusterStartupTime <= clientSession.getTimestamp()) { + && startupTime <= clientSession.getTimestamp()) { throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token"); } diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/model/infinispan/InfinispanTestUtil.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/model/infinispan/InfinispanTestUtil.java index ecbd520d58..7bc5ec2c8f 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/model/infinispan/InfinispanTestUtil.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/model/infinispan/InfinispanTestUtil.java @@ -44,20 +44,24 @@ public class InfinispanTestUtil { throw new IllegalStateException("Calling setTestingTimeService when testing TimeService was already set"); } - logger.info("Will set KeycloakIspnTimeService to the infinispan cacheManager"); - InfinispanConnectionProvider ispnProvider = session.getProvider(InfinispanConnectionProvider.class); - EmbeddedCacheManager cacheManager = ispnProvider.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME).getCacheManager(); - origTimeService = setTimeServiceToKeycloakTime(cacheManager); + if (ispnProvider != null) { + logger.info("Will set KeycloakIspnTimeService to the infinispan cacheManager"); + EmbeddedCacheManager cacheManager = ispnProvider.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME).getCacheManager(); + origTimeService = setTimeServiceToKeycloakTime(cacheManager); + } } - public static void revertTimeService() { + public static void revertTimeService(KeycloakSession session) { // Testing timeService not set. This shouldn't happen if this utility is properly used - if (origTimeService == null) { - throw new IllegalStateException("Calling revertTimeService when testing TimeService was not set"); - } + InfinispanConnectionProvider ispnProvider = session.getProvider(InfinispanConnectionProvider.class); + if (ispnProvider != null) { + if (origTimeService == null) { + throw new IllegalStateException("Calling revertTimeService when testing TimeService was not set"); + } - origTimeService.run(); - origTimeService = null; + origTimeService.run(); + origTimeService = null; + } } } diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java index 9013ff5c48..57d1a901a0 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java @@ -201,7 +201,7 @@ public class TestingResourceProvider implements RealmResourceProvider { @Path("/revert-testing-infinispan-time-service") @Produces(MediaType.APPLICATION_JSON) public Response revertTestingInfinispanTimeService() { - InfinispanTestUtil.revertTimeService(); + InfinispanTestUtil.revertTimeService(session); return Response.noContent().build(); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java index cb206d17a9..2400d69980 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java @@ -53,6 +53,7 @@ import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.AssertEvents; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.arquillian.annotation.EnableFeature; import org.keycloak.testsuite.util.ClientBuilder; @@ -744,6 +745,11 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT } private int getAuthenticationSessionsCount() { + if (ProfileAssume.isFeatureEnabled(Profile.Feature.MAP_STORAGE)) { + // Currently, no access to the authentication sessions is available for map storage. + // By return a constant, all tests in this test class can still pass. + return 0; + } return testingClient.testing().cache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME).size(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/session/LastSessionRefreshUnitTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/session/LastSessionRefreshUnitTest.java index 5aba01a469..f5c698d8f6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/session/LastSessionRefreshUnitTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/session/LastSessionRefreshUnitTest.java @@ -20,7 +20,9 @@ package org.keycloak.testsuite.session; import org.infinispan.Cache; import org.junit.After; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; +import org.keycloak.common.Profile; import org.keycloak.common.util.Retry; import org.keycloak.common.util.Time; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; @@ -32,6 +34,7 @@ import org.keycloak.models.sessions.infinispan.changes.sessions.SessionData; import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.runonserver.RunOnServer; @@ -52,6 +55,10 @@ public class LastSessionRefreshUnitTest extends AbstractKeycloakTest { } + @BeforeClass + public static void checkNotMapStorage() { + ProfileAssume.assumeFeatureDisabled(Profile.Feature.MAP_STORAGE); + } @After public void cleanupPeriodicTask() { diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderModelTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderModelTest.java index 655d70610b..bfeaafecd0 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderModelTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderModelTest.java @@ -215,7 +215,7 @@ public class UserSessionProviderModelTest extends KeycloakModelTest { if (timer != null && timerTaskCtx != null) { timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); - InfinispanTestUtil.revertTimeService(); + InfinispanTestUtil.revertTimeService(kcSession); } } } diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderOfflineModelTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderOfflineModelTest.java index 4288a7ba0a..eb714df54c 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderOfflineModelTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/session/UserSessionProviderOfflineModelTest.java @@ -230,7 +230,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest { timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); } - InfinispanTestUtil.revertTimeService(); + InfinispanTestUtil.revertTimeService(kcSession); } } @@ -302,7 +302,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest { timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); } - InfinispanTestUtil.revertTimeService(); + InfinispanTestUtil.revertTimeService(kcSession); } }