Simplify configuration for MULTI_SITE

Closes #31807

Signed-off-by: Michal Hajas <mhajas@redhat.com>
This commit is contained in:
Michal Hajas 2024-08-06 18:14:33 +02:00 committed by GitHub
parent 3fbe26d2e1
commit 50c07c6e7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 151 additions and 96 deletions

View file

@ -103,6 +103,7 @@ public class Profile {
TRANSIENT_USERS("Transient users for brokering", Type.EXPERIMENTAL), TRANSIENT_USERS("Transient users for brokering", Type.EXPERIMENTAL),
MULTI_SITE("Multi-site support", Type.DISABLED_BY_DEFAULT), MULTI_SITE("Multi-site support", Type.DISABLED_BY_DEFAULT),
REMOTE_CACHE("Remote caches support. Requires Multi-site support to be enabled as well.", Type.EXPERIMENTAL), REMOTE_CACHE("Remote caches support. Requires Multi-site support to be enabled as well.", Type.EXPERIMENTAL),
CLIENT_TYPES("Client Types", Type.EXPERIMENTAL), CLIENT_TYPES("Client Types", Type.EXPERIMENTAL),

View file

@ -0,0 +1,34 @@
/*
* Copyright 2024 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.common.util;
import org.keycloak.common.Profile;
public class MultiSiteUtils {
public static boolean isMultiSiteEnabled() {
return Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE);
}
/**
* @return true when user sessions are stored in the database. In multi-site setup this is false when REMOTE_CACHE feature is enabled
*/
public static boolean isPersistentSessionsEnabled() {
return Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) || (isMultiSiteEnabled() && !Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE));
}
}

View file

@ -25,6 +25,7 @@ import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.util.concurrent.ActionSequencer; import org.infinispan.util.concurrent.ActionSequencer;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.health.LoadBalancerCheckProvider; import org.keycloak.health.LoadBalancerCheckProvider;
import org.keycloak.health.LoadBalancerCheckProviderFactory; import org.keycloak.health.LoadBalancerCheckProviderFactory;
@ -62,7 +63,7 @@ public class RemoteLoadBalancerCheckProviderFactory implements LoadBalancerCheck
@Override @Override
public boolean isSupported(Config.Scope config) { public boolean isSupported(Config.Scope config) {
return InfinispanUtils.isRemoteInfinispan(); return MultiSiteUtils.isMultiSiteEnabled();
} }
@Override @Override

View file

@ -18,9 +18,8 @@
package org.keycloak.infinispan.util; package org.keycloak.infinispan.util;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature; import org.keycloak.common.util.MultiSiteUtils;
import static org.keycloak.common.Profile.Feature.MULTI_SITE;
import static org.keycloak.common.Profile.Feature.REMOTE_CACHE; import static org.keycloak.common.Profile.Feature.REMOTE_CACHE;
public final class InfinispanUtils { public final class InfinispanUtils {
@ -39,11 +38,11 @@ public final class InfinispanUtils {
// true if running with external infinispan mode only // true if running with external infinispan mode only
public static boolean isRemoteInfinispan() { public static boolean isRemoteInfinispan() {
return Profile.isFeatureEnabled(Feature.MULTI_SITE) && Profile.isFeatureEnabled(REMOTE_CACHE); return MultiSiteUtils.isMultiSiteEnabled() || Profile.isFeatureEnabled(REMOTE_CACHE);
} }
// true if running with embedded caches. // true if running with embedded caches.
public static boolean isEmbeddedInfinispan() { public static boolean isEmbeddedInfinispan() {
return !Profile.isFeatureEnabled(MULTI_SITE) || !Profile.isFeatureEnabled(REMOTE_CACHE); return !isRemoteInfinispan();
} }
} }

View file

@ -32,8 +32,8 @@ import org.infinispan.persistence.remote.RemoteStore;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.common.util.Environment; import org.keycloak.common.util.Environment;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil; import org.keycloak.connections.infinispan.InfinispanUtil;
@ -77,8 +77,6 @@ import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener; import org.keycloak.provider.ProviderEventListener;
import org.keycloak.provider.ServerInfoAwareProviderFactory; import org.keycloak.provider.ServerInfoAwareProviderFactory;
import static org.keycloak.common.Profile.Feature.PERSISTENT_USER_SESSIONS;
public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory<UserSessionProvider>, ServerInfoAwareProviderFactory, EnvironmentDependentProviderFactory { public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory<UserSessionProvider>, ServerInfoAwareProviderFactory, EnvironmentDependentProviderFactory {
private static final Logger log = Logger.getLogger(InfinispanUserSessionProviderFactory.class); private static final Logger log = Logger.getLogger(InfinispanUserSessionProviderFactory.class);
@ -131,7 +129,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
offlineClientSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME); offlineClientSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME);
} }
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (MultiSiteUtils.isPersistentSessionsEnabled()) {
return new PersistentUserSessionProvider( return new PersistentUserSessionProvider(
session, session,
remoteCacheInvoker, remoteCacheInvoker,
@ -175,8 +173,9 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
offlineSessionCacheEntryLifespanOverride = config.getInt(CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, -1); offlineSessionCacheEntryLifespanOverride = config.getInt(CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, -1);
offlineClientSessionCacheEntryLifespanOverride = config.getInt(CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, -1); offlineClientSessionCacheEntryLifespanOverride = config.getInt(CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, -1);
maxBatchSize = config.getInt(CONFIG_MAX_BATCH_SIZE, DEFAULT_MAX_BATCH_SIZE); maxBatchSize = config.getInt(CONFIG_MAX_BATCH_SIZE, DEFAULT_MAX_BATCH_SIZE);
// Do not use caches for sessions if explicitly disabled or if embedded caches are not used
useCaches = config.getBoolean(CONFIG_USE_CACHES, DEFAULT_USE_CACHES) && InfinispanUtils.isEmbeddedInfinispan(); useCaches = config.getBoolean(CONFIG_USE_CACHES, DEFAULT_USE_CACHES) && InfinispanUtils.isEmbeddedInfinispan();
useBatches = config.getBoolean(CONFIG_USE_BATCHES, DEFAULT_USE_BATCHES) && Profile.isFeatureEnabled(PERSISTENT_USER_SESSIONS); useBatches = config.getBoolean(CONFIG_USE_BATCHES, DEFAULT_USE_BATCHES) && MultiSiteUtils.isPersistentSessionsEnabled();
if (useBatches) { if (useBatches) {
asyncQueuePersistentUpdate = new ArrayBlockingQueue<>(1000); asyncQueuePersistentUpdate = new ArrayBlockingQueue<>(1000);
} }
@ -204,7 +203,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
keyGenerator = new InfinispanKeyGenerator(); keyGenerator = new InfinispanKeyGenerator();
checkRemoteCaches(session); checkRemoteCaches(session);
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (!MultiSiteUtils.isPersistentSessionsEnabled()) {
initializeLastSessionRefreshStore(factory); initializeLastSessionRefreshStore(factory);
} }
registerClusterListeners(session); registerClusterListeners(session);
@ -237,7 +236,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
} }
} }
}); });
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) && useBatches) { if (MultiSiteUtils.isPersistentSessionsEnabled() && useBatches) {
persistentSessionsWorker = new PersistentSessionsWorker(factory, persistentSessionsWorker = new PersistentSessionsWorker(factory,
asyncQueuePersistentUpdate, asyncQueuePersistentUpdate,
maxBatchSize); maxBatchSize);
@ -367,7 +366,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache, maxIdleLoader); remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache, maxIdleLoader);
Runnable onFailover = null; Runnable onFailover = null;
if (useCaches && Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (useCaches && MultiSiteUtils.isPersistentSessionsEnabled()) {
// If persistent sessions are enabled, we want to clear the local caches when a failover of the listener on the remote store changes as we might have missed some of the remote store events // If persistent sessions are enabled, we want to clear the local caches when a failover of the listener on the remote store changes as we might have missed some of the remote store events
// which might have been triggered by another Keycloak site connected to the same remote Infinispan cluster. // which might have been triggered by another Keycloak site connected to the same remote Infinispan cluster.
// Due to this, we can be sure that we never have outdated information in our local cache. All entries will be re-loaded from the remote cache or the database as necessary lazily. // Due to this, we can be sure that we never have outdated information in our local cache. All entries will be re-loaded from the remote cache or the database as necessary lazily.
@ -465,7 +464,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
@Override @Override
public boolean isSupported(Config.Scope config) { public boolean isSupported(Config.Scope config) {
return InfinispanUtils.isEmbeddedInfinispan() || Profile.isFeatureEnabled(PERSISTENT_USER_SESSIONS); return InfinispanUtils.isEmbeddedInfinispan() || MultiSiteUtils.isPersistentSessionsEnabled();
} }
@Override @Override

View file

@ -48,6 +48,7 @@ import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterProvider; import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature; import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Retry; import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
@ -134,7 +135,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
SerializeExecutionsByKey<String> serializerOfflineSession, SerializeExecutionsByKey<String> serializerOfflineSession,
SerializeExecutionsByKey<UUID> serializerClientSession, SerializeExecutionsByKey<UUID> serializerClientSession,
SerializeExecutionsByKey<UUID> serializerOfflineClientSession) { SerializeExecutionsByKey<UUID> serializerOfflineClientSession) {
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (!MultiSiteUtils.isPersistentSessionsEnabled()) {
throw new IllegalStateException("Persistent user sessions are not enabled"); throw new IllegalStateException("Persistent user sessions are not enabled");
} }

View file

@ -17,7 +17,7 @@
package org.keycloak.models.sessions.infinispan; package org.keycloak.models.sessions.infinispan;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -231,7 +231,7 @@ public class UserSessionAdapter<T extends SessionRefreshStore & UserSessionProvi
return; return;
} }
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) && offline) { if (!MultiSiteUtils.isPersistentSessionsEnabled() && offline) {
// Received the message from the other DC that we should update the lastSessionRefresh in local cluster. Don't update DB in that case. // Received the message from the other DC that we should update the lastSessionRefresh in local cluster. Don't update DB in that case.
// The other DC already did. // The other DC already did.
Boolean ignoreRemoteCacheUpdate = (Boolean) session.getAttribute(CrossDCLastSessionRefreshListener.IGNORE_REMOTE_CACHE_UPDATE); Boolean ignoreRemoteCacheUpdate = (Boolean) session.getAttribute(CrossDCLastSessionRefreshListener.IGNORE_REMOTE_CACHE_UPDATE);

View file

@ -19,7 +19,7 @@ package org.keycloak.models.sessions.infinispan.entities;
import org.infinispan.api.annotations.indexing.Basic; import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.protostream.annotations.ProtoField; import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
/** /**
@ -71,14 +71,14 @@ public abstract class SessionEntity {
public abstract int hashCode(); public abstract int hashCode();
public boolean isOffline() { public boolean isOffline() {
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (!MultiSiteUtils.isPersistentSessionsEnabled()) {
throw new IllegalArgumentException("Offline flags are not supported in non-persistent-session environments."); throw new IllegalArgumentException("Offline flags are not supported in non-persistent-session environments.");
} }
return isOffline; return isOffline;
} }
public void setOffline(boolean offline) { public void setOffline(boolean offline) {
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (!MultiSiteUtils.isPersistentSessionsEnabled()) {
throw new IllegalArgumentException("Offline flags are not supported in non-persistent-session environments."); throw new IllegalArgumentException("Offline flags are not supported in non-persistent-session environments.");
} }
isOffline = offline; isOffline = offline;

View file

@ -5,7 +5,7 @@ import java.util.UUID;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.infinispan.util.InfinispanUtils; import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -69,7 +69,7 @@ public class RemoteUserSessionProviderFactory implements UserSessionProviderFact
@Override @Override
public boolean isSupported(Config.Scope config) { public boolean isSupported(Config.Scope config) {
return InfinispanUtils.isRemoteInfinispan() && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS); return InfinispanUtils.isRemoteInfinispan() && !MultiSiteUtils.isPersistentSessionsEnabled();
} }
@Override @Override

View file

@ -18,7 +18,7 @@
package org.keycloak.models.sessions.infinispan.remotestore; package org.keycloak.models.sessions.infinispan.remotestore;
import org.infinispan.client.hotrod.exceptions.HotRodClientException; import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Retry; import org.keycloak.common.util.Retry;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -152,7 +152,7 @@ public class RemoteCacheInvoker {
VersionedValue<SessionEntityWrapper<V>> versioned = remoteCache.getWithMetadata(key); VersionedValue<SessionEntityWrapper<V>> versioned = remoteCache.getWithMetadata(key);
if (versioned == null) { if (versioned == null) {
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) && if (MultiSiteUtils.isPersistentSessionsEnabled() &&
(remoteCache.getName().equals(USER_SESSION_CACHE_NAME) (remoteCache.getName().equals(USER_SESSION_CACHE_NAME)
|| remoteCache.getName().equals(CLIENT_SESSION_CACHE_NAME) || remoteCache.getName().equals(CLIENT_SESSION_CACHE_NAME)
|| remoteCache.getName().equals(OFFLINE_USER_SESSION_CACHE_NAME) || remoteCache.getName().equals(OFFLINE_USER_SESSION_CACHE_NAME)

View file

@ -18,7 +18,7 @@
package org.keycloak.models.jpa.session; package org.keycloak.models.jpa.session;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -253,7 +253,7 @@ public class JpaUserSessionPersisterProvider implements UserSessionPersisterProv
expire(realm, expiredClientOffline, expiredOffline, true); expire(realm, expiredClientOffline, expiredOffline, true);
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (MultiSiteUtils.isPersistentSessionsEnabled()) {
int expired = Time.currentTime() - Math.max(realm.getSsoSessionIdleTimeout(), realm.getSsoSessionIdleTimeoutRememberMe()) - SessionTimeoutHelper.PERIODIC_CLEANER_IDLE_TIMEOUT_WINDOW_SECONDS; int expired = Time.currentTime() - Math.max(realm.getSsoSessionIdleTimeout(), realm.getSsoSessionIdleTimeoutRememberMe()) - SessionTimeoutHelper.PERIODIC_CLEANER_IDLE_TIMEOUT_WINDOW_SECONDS;

View file

@ -18,7 +18,7 @@
package org.keycloak.models.session; package org.keycloak.models.session;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
@ -216,7 +216,7 @@ public class PersistentUserSessionAdapter implements OfflineUserSessionModel {
@Override @Override
public String getLoginUsername() { public String getLoginUsername() {
if (isOffline() || !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (isOffline() || !MultiSiteUtils.isPersistentSessionsEnabled()) {
return getUser().getUsername(); return getUser().getUsername();
} else { } else {
return getData().getLoginUsername(); return getData().getLoginUsername();

View file

@ -68,6 +68,7 @@ import org.keycloak.authorization.policy.provider.PolicySpi;
import org.keycloak.authorization.policy.provider.js.DeployedScriptPolicyFactory; import org.keycloak.authorization.policy.provider.js.DeployedScriptPolicyFactory;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.crypto.FipsMode; import org.keycloak.common.crypto.FipsMode;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.StreamUtil; import org.keycloak.common.util.StreamUtil;
import org.keycloak.config.DatabaseOptions; import org.keycloak.config.DatabaseOptions;
import org.keycloak.config.HealthOptions; import org.keycloak.config.HealthOptions;
@ -644,7 +645,7 @@ class KeycloakProcessor {
JsResource.class.getName())), false)); JsResource.class.getName())), false));
} }
if (!Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)) { if (!MultiSiteUtils.isMultiSiteEnabled()) {
buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple( buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple(
LoadBalancerResource.class.getName())), false)); LoadBalancerResource.class.getName())), false));
} }

View file

@ -58,6 +58,7 @@ import org.jgroups.protocols.UDP;
import org.jgroups.util.TLS; import org.jgroups.util.TLS;
import org.jgroups.util.TLSClientAuth; import org.jgroups.util.TLSClientAuth;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.config.CachingOptions; import org.keycloak.config.CachingOptions;
import org.keycloak.config.MetricsOptions; import org.keycloak.config.MetricsOptions;
import org.keycloak.infinispan.util.InfinispanUtils; import org.keycloak.infinispan.util.InfinispanUtils;
@ -297,7 +298,7 @@ public class CacheManagerFactory {
Arrays.stream(CLUSTERED_CACHE_NAMES).forEach(cacheName -> { Arrays.stream(CLUSTERED_CACHE_NAMES).forEach(cacheName -> {
if (cacheName.equals(USER_SESSION_CACHE_NAME) || cacheName.equals(CLIENT_SESSION_CACHE_NAME) || cacheName.equals(OFFLINE_USER_SESSION_CACHE_NAME) || cacheName.equals(OFFLINE_CLIENT_SESSION_CACHE_NAME)) { if (cacheName.equals(USER_SESSION_CACHE_NAME) || cacheName.equals(CLIENT_SESSION_CACHE_NAME) || cacheName.equals(OFFLINE_USER_SESSION_CACHE_NAME) || cacheName.equals(OFFLINE_CLIENT_SESSION_CACHE_NAME)) {
ConfigurationBuilder configurationBuilder = builder.getNamedConfigurationBuilders().get(cacheName); ConfigurationBuilder configurationBuilder = builder.getNamedConfigurationBuilders().get(cacheName);
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (MultiSiteUtils.isPersistentSessionsEnabled()) {
if (configurationBuilder.memory().maxCount() == -1) { if (configurationBuilder.memory().maxCount() == -1) {
logger.infof("Persistent user sessions enabled and no memory limit found in configuration. Setting max entries for %s to 10000 entries.", cacheName); logger.infof("Persistent user sessions enabled and no memory limit found in configuration. Setting max entries for %s to 10000 entries.", cacheName);
configurationBuilder.memory().maxCount(10000); configurationBuilder.memory().maxCount(10000);

View file

@ -122,13 +122,4 @@ public class HealthDistTest {
distribution.stop(); distribution.stop();
} }
} }
@Test
@Launch({ "start-dev", "--features=multi-site" })
void testLoadBalancerCheck(KeycloakDistribution distribution) {
distribution.setRequestPort(8080);
when().get("/lb-check").then()
.statusCode(200);
}
} }

View file

@ -34,8 +34,20 @@ import static io.restassured.RestAssured.when;
public class ExternalInfinispanTest { public class ExternalInfinispanTest {
@Test @Test
@Launch({ "start-dev", "--features=multi-site", "--cache=ispn", "--cache-config-file=../../../test-classes/ExternalInfinispan/kcb-infinispan-cache-remote-store-config.xml", "--spi-connections-infinispan-quarkus-site-name=ISPN" }) @Launch({
void testLoadBalancerCheckFailure() { "start-dev",
"--features=multi-site",
"--cache=ispn",
"--cache-remote-host=localhost",
"--cache-remote-username=keycloak",
"--cache-remote-password=Password1!",
"--cache-remote-tls-enabled=false",
"--spi-connections-infinispan-quarkus-site-name=ISPN",
"--spi-load-balancer-check-remote-poll-interval=500",
"-Dkc.cache-remote-create-caches=true",
"--verbose"
})
void testLoadBalancerCheckFailureWithMultiSite() {
runLoadBalancerCheckFailureTest(); runLoadBalancerCheckFailureTest();
} }
@ -47,9 +59,10 @@ public class ExternalInfinispanTest {
"--cache-remote-host=localhost", "--cache-remote-host=localhost",
"--cache-remote-username=keycloak", "--cache-remote-username=keycloak",
"--cache-remote-password=Password1!", "--cache-remote-password=Password1!",
"--cache-remote-tls-enabled=false",
"--spi-connections-infinispan-quarkus-site-name=ISPN", "--spi-connections-infinispan-quarkus-site-name=ISPN",
"--spi-load-balancer-check-remote-poll-interval=500", "--spi-load-balancer-check-remote-poll-interval=500",
"-Dkc.cache-remote-tls-enabled=false", "-Dkc.cache-remote-create-caches=true",
"--verbose" "--verbose"
}) })
void testLoadBalancerCheckFailureWithRemoteOnlyCaches() { void testLoadBalancerCheckFailureWithRemoteOnlyCaches() {
@ -71,7 +84,12 @@ public class ExternalInfinispanTest {
} }
@Test @Test
@Launch({ "start-dev", "--features=multi-site", "--cache=ispn", "--cache-config-file=../../../test-classes/ExternalInfinispan/kcb-infinispan-cache-remote-store-config.xml", "-Djboss.site.name=ISPN" }) @Launch({
"start-dev",
"--cache=ispn",
"-Djboss.site.name=ISPN",
"--verbose"
})
void testSiteNameAsSystemProperty(LaunchResult result) { void testSiteNameAsSystemProperty(LaunchResult result) {
((CLIResult) result).assertMessage("System property jboss.site.name is in use. Use --spi-connections-infinispan-quarkus-site-name config option instead"); ((CLIResult) result).assertMessage("System property jboss.site.name is in use. Use --spi-connections-infinispan-quarkus-site-name config option instead");
} }

View file

@ -21,15 +21,15 @@ import org.keycloak.Config;
/** /**
* A Service Provider Interface (SPI) that allows to plug-in an embedded or remote cache manager instance. * A Service Provider Interface (SPI) that allows to plug-in an embedded or remote cache manager instance.
* *
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public interface ManagedCacheManagerProvider { public interface ManagedCacheManagerProvider {
<C> C getEmbeddedCacheManager(Config.Scope config); <C> C getEmbeddedCacheManager(Config.Scope config);
/** /**
* @return A RemoteCacheManager if the feature {@link org.keycloak.common.Profile.Feature#REMOTE_CACHE} is enabled, {@code null} otherwise. * @return A RemoteCacheManager if the features {@link org.keycloak.common.Profile.Feature#REMOTE_CACHE} or {@link org.keycloak.common.Profile.Feature#MULTI_SITE} is enabled, {@code null} otherwise.
*/ */
<C> C getRemoteCacheManager(Config.Scope config); <C> C getRemoteCacheManager(Config.Scope config);
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.services.resteasy; package org.keycloak.services.resteasy;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.services.error.KcUnrecognizedPropertyExceptionHandler; import org.keycloak.services.error.KcUnrecognizedPropertyExceptionHandler;
@ -62,7 +63,7 @@ public class ResteasyKeycloakApplication extends KeycloakApplication {
singletons.add(new ObjectMapperResolver()); singletons.add(new ObjectMapperResolver());
classes.add(WelcomeResource.class); classes.add(WelcomeResource.class);
if (Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)) { if (MultiSiteUtils.isMultiSiteEnabled()) {
// If we are running in multi-site mode, we need to add a resource which to expose // If we are running in multi-site mode, we need to add a resource which to expose
// an endpoint for the load balancer to gather information whether this site should receive requests or not. // an endpoint for the load balancer to gather information whether this site should receive requests or not.
classes.add(LoadBalancerResource.class); classes.add(LoadBalancerResource.class);

View file

@ -212,7 +212,7 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
addFeaturesOption(commands); addFeaturesOption(commands);
var features = getDefaultFeatures(); var features = getDefaultFeatures();
if (features.contains("remote-cache") && features.contains("multi-site")) { if (features.contains("remote-cache") || features.contains("multi-site")) {
commands.add("--cache-remote-host=127.0.0.1"); commands.add("--cache-remote-host=127.0.0.1");
commands.add("--cache-remote-username=keycloak"); commands.add("--cache-remote-username=keycloak");
commands.add("--cache-remote-password=Password1!"); commands.add("--cache-remote-password=Password1!");

View file

@ -25,6 +25,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -214,7 +215,7 @@ public class AuthenticationSessionProviderTest extends AbstractTestRealmKeycloak
@Test @Test
@ModelTest @ModelTest
public void testExpiredAuthSessions(KeycloakSession session) { public void testExpiredAuthSessions(KeycloakSession session) {
assumeFalse(Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)); assumeFalse(InfinispanUtils.isRemoteInfinispan());
AtomicReference<String> authSessionID = new AtomicReference<>(); AtomicReference<String> authSessionID = new AtomicReference<>();
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), mainSession -> { KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), mainSession -> {

View file

@ -175,11 +175,11 @@ public class AccessTokenTest extends AbstractKeycloakTest {
testRealms.add(realm); testRealms.add(realm);
} }
@Test @Test
public void loginFormUsernameOrEmailLabel() throws Exception { public void loginFormUsernameOrEmailLabel() throws Exception {
oauth.openLoginForm(); oauth.openLoginForm();
assertEquals("Username or email", driver.findElement(By.xpath("//label[@for='username']")).getText()); assertEquals("Username or email", driver.findElement(By.xpath("//label[@for='username']")).getText());
} }
@ -389,6 +389,8 @@ public class AccessTokenTest extends AbstractKeycloakTest {
@Test @Test
public void accessTokenCodeExpired() { public void accessTokenCodeExpired() {
ProfileAssume.assumeFeatureDisabled(Profile.Feature.REMOTE_CACHE); ProfileAssume.assumeFeatureDisabled(Profile.Feature.REMOTE_CACHE);
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MULTI_SITE);
getTestingClient().testing().setTestingInfinispanTimeService(); getTestingClient().testing().setTestingInfinispanTimeService();
RealmManager.realm(adminClient.realm("test")).accessCodeLifeSpan(1); RealmManager.realm(adminClient.realm("test")).accessCodeLifeSpan(1);
oauth.doLogin("test-user@localhost", "password"); oauth.doLogin("test-user@localhost", "password");
@ -1323,7 +1325,7 @@ public class AccessTokenTest extends AbstractKeycloakTest {
public void accessTokenRequest_ClientEdDSA_RealmEdDSA() throws Exception { public void accessTokenRequest_ClientEdDSA_RealmEdDSA() throws Exception {
conductAccessTokenRequest(Constants.INTERNAL_SIGNATURE_ALGORITHM, Algorithm.EdDSA, Algorithm.EdDSA); conductAccessTokenRequest(Constants.INTERNAL_SIGNATURE_ALGORITHM, Algorithm.EdDSA, Algorithm.EdDSA);
} }
@Test @Test
public void validateECDSASignatures() { public void validateECDSASignatures() {
validateTokenECDSASignature(Algorithm.ES256); validateTokenECDSASignature(Algorithm.ES256);

View file

@ -66,6 +66,8 @@ public class LastSessionRefreshUnitTest extends AbstractKeycloakTest {
@Test @Test
public void testLastSessionRefreshCounters() { public void testLastSessionRefreshCounters() {
ProfileAssume.assumeFeatureDisabled(Profile.Feature.REMOTE_CACHE); ProfileAssume.assumeFeatureDisabled(Profile.Feature.REMOTE_CACHE);
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MULTI_SITE);
testingClient.server().run(new LastSessionRefreshServerCounterTest()); testingClient.server().run(new LastSessionRefreshServerCounterTest());
} }
@ -111,6 +113,8 @@ public class LastSessionRefreshUnitTest extends AbstractKeycloakTest {
@Test @Test
public void testLastSessionRefreshIntervals() { public void testLastSessionRefreshIntervals() {
ProfileAssume.assumeFeatureDisabled(Profile.Feature.REMOTE_CACHE); ProfileAssume.assumeFeatureDisabled(Profile.Feature.REMOTE_CACHE);
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MULTI_SITE);
testingClient.server().run(new LastSessionRefreshServerIntervalsTest()); testingClient.server().run(new LastSessionRefreshServerIntervalsTest());
} }

View file

@ -78,6 +78,12 @@
<groupId>org.keycloak.testsuite</groupId> <groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-tests-base</artifactId> <artifactId>integration-arquillian-tests-base</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-quarkus-server</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${jdbc.mvn.groupId}</groupId> <groupId>${jdbc.mvn.groupId}</groupId>
@ -118,6 +124,10 @@
<artifactId>infinispan-component-annotations</artifactId> <artifactId>infinispan-component-annotations</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-remote-query-server</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -286,12 +296,6 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<dependencies>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-remote-query-server</artifactId>
</dependency>
</dependencies>
</profile> </profile>
<profile> <profile>

View file

@ -1,13 +1,13 @@
/* /*
* Copyright 2020 Red Hat, Inc. and/or its affiliates * Copyright 2020 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags. * and other contributors as indicated by the @author tags.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -21,6 +21,8 @@ import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNoteUpdateEvent; import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNoteUpdateEvent;
import org.keycloak.testsuite.model.KeycloakModelTest; import org.keycloak.testsuite.model.KeycloakModelTest;
import org.keycloak.testsuite.model.RequireProvider; import org.keycloak.testsuite.model.RequireProvider;
@ -56,7 +58,7 @@ public class CacheExpirationTest extends KeycloakModelTest {
@Test @Test
public void testCacheExpiration() throws Exception { public void testCacheExpiration() throws Exception {
assumeFalse("Embedded caches not available for testing.", Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE) && Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)); assumeFalse("Embedded caches not available for testing.", InfinispanUtils.isRemoteInfinispan());
log.debugf("Number of previous instances of the class on the heap: %d", getNumberOfInstancesOfClass(AuthenticationSessionAuthNoteUpdateEvent.class)); log.debugf("Number of previous instances of the class on the heap: %d", getNumberOfInstancesOfClass(AuthenticationSessionAuthNoteUpdateEvent.class));

View file

@ -23,6 +23,7 @@ import java.util.function.Predicate;
import org.infinispan.commons.CacheConfigurationException; import org.infinispan.commons.CacheConfigurationException;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.infinispan.util.InfinispanUtils; import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.testsuite.model.KeycloakModelTest; import org.keycloak.testsuite.model.KeycloakModelTest;
@ -60,8 +61,7 @@ public class FeatureEnabledTest extends KeycloakModelTest {
@Test @Test
public void testRemoteCachesOnly() { public void testRemoteCachesOnly() {
assumeTrue("Remote-Cache Feature disabled", Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)); assumeTrue("Remote-Cache Feature disabled", Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE) || MultiSiteUtils.isMultiSiteEnabled());
assumeTrue("Multi-Site Feature disabled", Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE));
assertTrue(InfinispanUtils.isRemoteInfinispan()); assertTrue(InfinispanUtils.isRemoteInfinispan());
assertFalse(InfinispanUtils.isEmbeddedInfinispan()); assertFalse(InfinispanUtils.isEmbeddedInfinispan());
inComittedTransaction(session -> { inComittedTransaction(session -> {
@ -72,22 +72,9 @@ public class FeatureEnabledTest extends KeycloakModelTest {
}); });
} }
@Test
public void testRemoteAndEmbeddedCaches() {
assumeTrue("Multi-Site Feature disabled", Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE));
assumeFalse("Remote-Cache Feature enabled", Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE));
assertFalse(InfinispanUtils.isRemoteInfinispan());
assertTrue(InfinispanUtils.isEmbeddedInfinispan());
inComittedTransaction(session -> {
var clusterProvider = session.getProvider(InfinispanConnectionProvider.class);
Arrays.stream(CLUSTERED_CACHE_NAMES).forEach(s -> assertEmbeddedCacheExists(clusterProvider, s));
Arrays.stream(CLUSTERED_CACHE_NAMES).forEach(s -> assertRemoteCacheExists(clusterProvider, s));
});
}
@Test @Test
public void testEmbeddedCachesOnly() { public void testEmbeddedCachesOnly() {
assumeFalse("Multi-Site Feature enabled", Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)); assumeFalse("Multi-Site Feature enabled", MultiSiteUtils.isMultiSiteEnabled());
assumeFalse("Remote-Cache Feature enabled", Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)); assumeFalse("Remote-Cache Feature enabled", Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE));
assertFalse(InfinispanUtils.isRemoteInfinispan()); assertFalse(InfinispanUtils.isRemoteInfinispan());
assertTrue(InfinispanUtils.isEmbeddedInfinispan()); assertTrue(InfinispanUtils.isEmbeddedInfinispan());

View file

@ -25,6 +25,7 @@ import org.keycloak.testsuite.model.HotRodServerRule;
import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.testsuite.model.KeycloakModelParameters;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
@ -66,7 +67,7 @@ public class CrossDCInfinispan extends KeycloakModelParameters {
} }
public CrossDCInfinispan() { public CrossDCInfinispan() {
super(Infinispan.ALLOWED_SPIS, Infinispan.ALLOWED_FACTORIES); super(Infinispan.ALLOWED_SPIS, Stream.concat(Infinispan.ALLOWED_FACTORIES.stream(), RemoteInfinispan.ALLOWED_FACTORIES.stream()).collect(Collectors.toSet()));
} }
@Override @Override

View file

@ -37,6 +37,7 @@ import java.util.stream.Stream;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.infinispan.commons.CacheException; import org.infinispan.commons.CacheException;
import org.junit.Test; import org.junit.Test;
import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
@ -50,13 +51,13 @@ import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.session.UserSessionPersisterProvider; import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider; import org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider;
import org.keycloak.models.sessions.infinispan.PersistentUserSessionProvider; import org.keycloak.models.sessions.infinispan.PersistentUserSessionProvider;
import org.keycloak.models.sessions.infinispan.remote.RemoteUserSessionProvider;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.model.KeycloakModelTest; import org.keycloak.testsuite.model.KeycloakModelTest;
import org.keycloak.testsuite.model.RequireProvider; import org.keycloak.testsuite.model.RequireProvider;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assume.assumeTrue;
/** /**
* *
@ -252,6 +253,8 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
@Test @Test
@RequireProvider(UserSessionPersisterProvider.class) @RequireProvider(UserSessionPersisterProvider.class)
public void testOfflineSessionLoadingAfterCacheRemoval() { public void testOfflineSessionLoadingAfterCacheRemoval() {
assumeTrue("Run only if Embedded Infinispan is used for storing/caching sessions.", InfinispanUtils.isEmbeddedInfinispan());
List<String> offlineSessionIds = createOfflineSessions(realmId, userIds); List<String> offlineSessionIds = createOfflineSessions(realmId, userIds);
assertOfflineSessionsExist(realmId, offlineSessionIds); assertOfflineSessionsExist(realmId, offlineSessionIds);
@ -268,8 +271,6 @@ public class OfflineSessionPersistenceTest extends KeycloakModelTest {
((InfinispanUserSessionProvider) provider).removeLocalUserSessions(realm.getId(), true); ((InfinispanUserSessionProvider) provider).removeLocalUserSessions(realm.getId(), true);
} else if (provider instanceof PersistentUserSessionProvider) { } else if (provider instanceof PersistentUserSessionProvider) {
((PersistentUserSessionProvider) provider).removeLocalUserSessions(realm.getId(), true); ((PersistentUserSessionProvider) provider).removeLocalUserSessions(realm.getId(), true);
} else if (provider instanceof RemoteUserSessionProvider) {
//no-op, session not local
} else { } else {
throw new IllegalStateException("Unknown UserSessionProvider: " + provider); throw new IllegalStateException("Unknown UserSessionProvider: " + provider);
} }

View file

@ -26,7 +26,7 @@ import org.junit.FixMethodOrder;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TestRule; import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Retry; import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
@ -298,7 +298,7 @@ public class SessionTimeoutsTest extends KeycloakModelTest {
return null; return null;
}); });
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (MultiSiteUtils.isPersistentSessionsEnabled()) {
// The persistent session will write the update data asynchronously, wait for it to arrive. // The persistent session will write the update data asynchronously, wait for it to arrive.
Retry.executeWithBackoff(iteration -> { Retry.executeWithBackoff(iteration -> {
withRealm(realmId, (session, realm) -> { withRealm(realmId, (session, realm) -> {

View file

@ -28,6 +28,7 @@ import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCache;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.infinispan.util.InfinispanUtils; import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -48,6 +49,7 @@ import org.keycloak.testsuite.model.RequireProvider;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Every.everyItem; import static org.hamcrest.core.Every.everyItem;
import static org.hamcrest.core.Is.is; import static org.hamcrest.core.Is.is;
import static org.junit.Assume.assumeFalse;
import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.USER_SESSION_CACHE_NAME; import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.USER_SESSION_CACHE_NAME;
/** /**
@ -157,6 +159,7 @@ public class UserSessionInitializerTest extends KeycloakModelTest {
@Test @Test
public void testUserSessionPropagationBetweenSites() throws InterruptedException { public void testUserSessionPropagationBetweenSites() throws InterruptedException {
assumeFalse("Run only if Infinispan caches are used for storing/caching sessions", MultiSiteUtils.isMultiSiteEnabled() && MultiSiteUtils.isPersistentSessionsEnabled());
AtomicInteger index = new AtomicInteger(); AtomicInteger index = new AtomicInteger();
AtomicReference<String> userSessionId = new AtomicReference<>(); AtomicReference<String> userSessionId = new AtomicReference<>();
AtomicReference<List<Boolean>> containsSession = new AtomicReference<>(new LinkedList<>()); AtomicReference<List<Boolean>> containsSession = new AtomicReference<>(new LinkedList<>());

View file

@ -21,7 +21,7 @@ import org.junit.Assert;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.common.Profile; import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.infinispan.util.InfinispanUtils; import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
@ -151,7 +151,7 @@ public class UserSessionPersisterProviderTest extends KeycloakModelTest {
.forEach(userSessionLooper -> persistUserSession(session, userSessionLooper, true)); .forEach(userSessionLooper -> persistUserSession(session, userSessionLooper, true));
}); });
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (!MultiSiteUtils.isPersistentSessionsEnabled()) {
inComittedTransaction(session -> { inComittedTransaction(session -> {
// Persist 1 online session // Persist 1 online session
RealmModel realm = session.realms().getRealm(realmId); RealmModel realm = session.realms().getRealm(realmId);
@ -581,7 +581,8 @@ public class UserSessionPersisterProviderTest extends KeycloakModelTest {
@Test @Test
public void testMigrateSession() { public void testMigrateSession() {
Assume.assumeTrue(Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)); Assume.assumeTrue(MultiSiteUtils.isPersistentSessionsEnabled());
Assume.assumeTrue(InfinispanUtils.isEmbeddedInfinispan());
UserSessionModel[] sessions = inComittedTransaction(session -> { UserSessionModel[] sessions = inComittedTransaction(session -> {
// Create some sessions in infinispan // Create some sessions in infinispan

View file

@ -20,6 +20,7 @@ import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
@ -129,7 +130,7 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
// skip for persistent user sessions as the periodic task is not used there // skip for persistent user sessions as the periodic task is not used there
TimerProvider timer = kcSession.getProvider(TimerProvider.class); TimerProvider timer = kcSession.getProvider(TimerProvider.class);
TimerProvider.TimerTaskContext timerTaskCtx = null; TimerProvider.TimerTaskContext timerTaskCtx = null;
if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (timer != null && !MultiSiteUtils.isPersistentSessionsEnabled()) {
timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }
@ -181,7 +182,7 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
setTimeOffset(0); setTimeOffset(0);
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent()); kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
// Enable periodic task again, skip for persistent user sessions as the periodic task is not used there // Enable periodic task again, skip for persistent user sessions as the periodic task is not used there
if (timer != null && timerTaskCtx != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (timer != null && timerTaskCtx != null && !MultiSiteUtils.isPersistentSessionsEnabled()) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }

View file

@ -41,6 +41,7 @@ import org.junit.Assert;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.MultiSiteUtils;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.infinispan.util.InfinispanUtils; import org.keycloak.infinispan.util.InfinispanUtils;
@ -126,7 +127,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
// skip for persistent user sessions as the periodic task is not used there // skip for persistent user sessions as the periodic task is not used there
TimerProvider timer = kcSession.getProvider(TimerProvider.class); TimerProvider timer = kcSession.getProvider(TimerProvider.class);
TimerProvider.TimerTaskContext timerTaskCtx = null; TimerProvider.TimerTaskContext timerTaskCtx = null;
if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (timer != null && !MultiSiteUtils.isPersistentSessionsEnabled()) {
timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }
@ -245,7 +246,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
setTimeOffset(0); setTimeOffset(0);
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent()); kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
// Enable periodic task again, skip for persistent user sessions as the periodic task is not used there // Enable periodic task again, skip for persistent user sessions as the periodic task is not used there
if (timer != null && timerTaskCtx != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (timer != null && timerTaskCtx != null && !MultiSiteUtils.isPersistentSessionsEnabled()) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }
@ -259,7 +260,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
// skip for persistent user sessions as the periodic task is not used there // skip for persistent user sessions as the periodic task is not used there
TimerProvider timer = kcSession.getProvider(TimerProvider.class); TimerProvider timer = kcSession.getProvider(TimerProvider.class);
TimerProvider.TimerTaskContext timerTaskCtx = null; TimerProvider.TimerTaskContext timerTaskCtx = null;
if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (timer != null && !MultiSiteUtils.isPersistentSessionsEnabled()) {
timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timerTaskCtx = timer.cancelTask(PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); log.info("Cancelled periodic task " + PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }
@ -314,14 +315,14 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
session.sessions().createOfflineUserSession(userSession); session.sessions().createOfflineUserSession(userSession);
session.sessions().createOfflineUserSession(origSessions[0]); session.sessions().createOfflineUserSession(origSessions[0]);
if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) && InfinispanUtils.isEmbeddedInfinispan()) { if (!MultiSiteUtils.isPersistentSessionsEnabled() && InfinispanUtils.isEmbeddedInfinispan()) {
// This does not work with persistent user sessions because we currently have two transactions and the one that creates the offline user sessions is not committing the changes // This does not work with persistent user sessions because we currently have two transactions and the one that creates the offline user sessions is not committing the changes
// try to load user session from persister // try to load user session from persister
Assert.assertEquals(2, persister.loadUserSessionsStream(0, 10, true, "00000000-0000-0000-0000-000000000000").count()); Assert.assertEquals(2, persister.loadUserSessionsStream(0, 10, true, "00000000-0000-0000-0000-000000000000").count());
} }
}); });
if (Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) && InfinispanUtils.isEmbeddedInfinispan()) { if (MultiSiteUtils.isPersistentSessionsEnabled() && InfinispanUtils.isEmbeddedInfinispan()) {
inComittedTransaction(session -> { inComittedTransaction(session -> {
persister = session.getProvider(UserSessionPersisterProvider.class); persister = session.getProvider(UserSessionPersisterProvider.class);
Assert.assertEquals(2, persister.loadUserSessionsStream(0, 10, true, "00000000-0000-0000-0000-000000000000").count()); Assert.assertEquals(2, persister.loadUserSessionsStream(0, 10, true, "00000000-0000-0000-0000-000000000000").count());
@ -333,7 +334,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent()); kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
// Enable periodic task again, skip for persistent user sessions as the periodic task is not used there // Enable periodic task again, skip for persistent user sessions as the periodic task is not used there
if (timer != null && timerTaskCtx != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) { if (timer != null && timerTaskCtx != null && !MultiSiteUtils.isPersistentSessionsEnabled()) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }
@ -502,7 +503,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
// skip the test for CrossDC // skip the test for CrossDC
Assume.assumeFalse(Objects.equals(CONFIG.scope("connectionsInfinispan.default").get("remoteStoreEnabled"), "true")); Assume.assumeFalse(Objects.equals(CONFIG.scope("connectionsInfinispan.default").get("remoteStoreEnabled"), "true"));
// As offline session's timeout is not overriden when PERSISTENT_USER_SESSIONS is enabled // As offline session's timeout is not overriden when PERSISTENT_USER_SESSIONS is enabled
Assume.assumeFalse(Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)); Assume.assumeFalse(MultiSiteUtils.isPersistentSessionsEnabled());
createOfflineSessions("user1", 2, new LinkedList<>(), new LinkedList<>()); createOfflineSessions("user1", 2, new LinkedList<>(), new LinkedList<>());