Do not use LastSessionRefreshPersister with persistent user sessions enabled

Closes #29144

Signed-off-by: Michal Hajas <mhajas@redhat.com>
This commit is contained in:
Michal Hajas 2024-05-02 12:55:11 +02:00 committed by Alexander Schwartz
parent ba43a10a6d
commit 8b715d3a31
6 changed files with 28 additions and 24 deletions

View file

@ -126,7 +126,6 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
remoteCacheInvoker, remoteCacheInvoker,
lastSessionRefreshStore, lastSessionRefreshStore,
offlineLastSessionRefreshStore, offlineLastSessionRefreshStore,
persisterLastSessionRefreshStore,
keyGenerator, keyGenerator,
cache, cache,
offlineSessionsCache, offlineSessionsCache,
@ -178,7 +177,9 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
keyGenerator = new InfinispanKeyGenerator(); keyGenerator = new InfinispanKeyGenerator();
checkRemoteCaches(session); checkRemoteCaches(session);
loadPersistentSessions(factory, getMaxErrors(), getSessionsPerSegment()); if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) {
initializeLastSessionRefreshStore(factory);
}
registerClusterListeners(session); registerClusterListeners(session);
loadSessionsFromRemoteCaches(session); loadSessionsFromRemoteCaches(session);
@ -234,9 +235,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
return config.getInt("sessionPreloadStalledTimeoutInSeconds", defaultTimeout); return config.getInt("sessionPreloadStalledTimeoutInSeconds", defaultTimeout);
} }
@Override public void initializeLastSessionRefreshStore(final KeycloakSessionFactory sessionFactory) {
public void loadPersistentSessions(final KeycloakSessionFactory sessionFactory, final int maxErrors, final int sessionsPerSegment) {
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() { KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
@Override @Override
@ -244,10 +243,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
// Initialize persister for periodically doing bulk DB updates of lastSessionRefresh timestamps of refreshed sessions // Initialize persister for periodically doing bulk DB updates of lastSessionRefresh timestamps of refreshed sessions
persisterLastSessionRefreshStore = new PersisterLastSessionRefreshStoreFactory().createAndInit(session, true); persisterLastSessionRefreshStore = new PersisterLastSessionRefreshStoreFactory().createAndInit(session, true);
} }
}); });
} }

View file

@ -107,7 +107,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
protected final CrossDCLastSessionRefreshStore lastSessionRefreshStore; protected final CrossDCLastSessionRefreshStore lastSessionRefreshStore;
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore; protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
protected final PersisterLastSessionRefreshStore persisterLastSessionRefreshStore;
protected final RemoteCacheInvoker remoteCacheInvoker; protected final RemoteCacheInvoker remoteCacheInvoker;
protected final InfinispanKeyGenerator keyGenerator; protected final InfinispanKeyGenerator keyGenerator;
@ -116,7 +115,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
RemoteCacheInvoker remoteCacheInvoker, RemoteCacheInvoker remoteCacheInvoker,
CrossDCLastSessionRefreshStore lastSessionRefreshStore, CrossDCLastSessionRefreshStore lastSessionRefreshStore,
CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore, CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore,
PersisterLastSessionRefreshStore persisterLastSessionRefreshStore,
InfinispanKeyGenerator keyGenerator, InfinispanKeyGenerator keyGenerator,
Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionCache, Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionCache,
Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionCache, Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionCache,
@ -153,7 +151,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
this.lastSessionRefreshStore = lastSessionRefreshStore; this.lastSessionRefreshStore = lastSessionRefreshStore;
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore; this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
this.persisterLastSessionRefreshStore = persisterLastSessionRefreshStore;
this.remoteCacheInvoker = remoteCacheInvoker; this.remoteCacheInvoker = remoteCacheInvoker;
this.keyGenerator = keyGenerator; this.keyGenerator = keyGenerator;
@ -182,7 +179,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
@Override @Override
public PersisterLastSessionRefreshStore getPersisterLastSessionRefreshStore() { public PersisterLastSessionRefreshStore getPersisterLastSessionRefreshStore() {
return persisterLastSessionRefreshStore; throw new IllegalStateException("PersisterLastSessionRefreshStore is not supported in PersistentUserSessionProvider");
} }
@Override @Override

View file

@ -17,6 +17,7 @@
package org.keycloak.models.sessions.infinispan; package org.keycloak.models.sessions.infinispan;
import org.keycloak.common.Profile;
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;
@ -230,7 +231,7 @@ public class UserSessionAdapter<T extends SessionRefreshStore & UserSessionProvi
return; return;
} }
if (offline) { if (!Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS) && 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

@ -26,6 +26,8 @@ import org.keycloak.provider.ProviderFactory;
public interface UserSessionProviderFactory<T extends UserSessionProvider> extends ProviderFactory<T> { public interface UserSessionProviderFactory<T extends UserSessionProvider> extends ProviderFactory<T> {
// This is supposed to prefill all userSessions and clientSessions from userSessionPersister to the userSession infinispan/memory storage // This is supposed to prefill all userSessions and clientSessions from userSessionPersister to the userSession infinispan/memory storage
void loadPersistentSessions(KeycloakSessionFactory sessionFactory, final int maxErrors, final int sessionsPerSegment); // This method is no longer used as we don't have offline sessions preloading anymore
@Deprecated
default void loadPersistentSessions(KeycloakSessionFactory sessionFactory, final int maxErrors, final int sessionsPerSegment) {}
} }

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.model.session;
import org.hamcrest.Matchers; 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.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;
@ -119,15 +120,16 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
@Test @Test
public void testExpiredClientSessions() { public void testExpiredClientSessions() {
// Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider // Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider
// 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) { if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) {
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);
InfinispanTestUtil.setTestingTimeService(kcSession);
} }
InfinispanTestUtil.setTestingTimeService(kcSession);
try { try {
UserSessionModel[] origSessions = inComittedTransaction(session -> { UserSessionModel[] origSessions = inComittedTransaction(session -> {
// create some user and client sessions // create some user and client sessions
@ -172,11 +174,12 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
} finally { } finally {
setTimeOffset(0); setTimeOffset(0);
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent()); kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
if (timer != null && timerTaskCtx != null) { // 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)) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
InfinispanTestUtil.revertTimeService(kcSession);
} }
InfinispanTestUtil.revertTimeService(kcSession);
} }
} }

View file

@ -121,9 +121,10 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
@Test @Test
public void testExpired() { public void testExpired() {
// Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider // Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider
// 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) { if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) {
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);
} }
@ -236,7 +237,8 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
} finally { } finally {
setTimeOffset(0); setTimeOffset(0);
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent()); kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
if (timer != null) { // Enable periodic task again, skip for persistent user sessions as the periodic task is not used there
if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }
@ -247,9 +249,10 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
@Test @Test
public void testLoadUserSessionsWithNotDeletedOfflineClientSessions() { public void testLoadUserSessionsWithNotDeletedOfflineClientSessions() {
// Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider // Suspend periodic tasks to avoid race-conditions, which may cause missing updates of lastSessionRefresh times to UserSessionPersisterProvider
// 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) { if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) {
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);
} }
@ -318,7 +321,9 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
} finally { } finally {
setTimeOffset(0); setTimeOffset(0);
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent()); kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
if (timer != null) {
// Enable periodic task again, skip for persistent user sessions as the periodic task is not used there
if (timer != null && !Profile.isFeatureEnabled(Profile.Feature.PERSISTENT_USER_SESSIONS)) {
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME); timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
} }