8000 Remove offline session cache entry lifespan override options by ruchikajha95 · Pull Request #54644 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
8000
Diff view
13 changes: 13 additions & 0 deletions docs/documentation/upgrading/topics/changes/changes-27_0_0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -676,3 +676,16 @@ The default implementations of the following methods were removed, and the metho
The removed default implementations were not atomic, and a credential that was changed concurrently could be overwritten.
Custom implementations of these interfaces must implement the methods.
They must replace the credential only if the stored credential still has the content of `oldCred`, return `false` otherwise, and perform the comparison and the update atomically, for example by locking the stored credential.

=== Offline session cache entry lifespan override options removed
// https://github.com/keycloak/keycloak/issues/40981

The following configuration options have been removed:

* `--spi-user-sessions--infinispan--offline-session-cache-entry-lifespan-override`
* `--spi-user-sessions--infinispan--offline-client-session-cache-entry-lifespan-override`

These options were deprecated and were only relevant when using volatile user sessions (disabled persistent sessions).
With persistent user sessions enabled (the default since Keycloak 26), offline sessions are managed in the database and these lifespan override options have no effect.

If you have these options in your configuration, remove them before upgrading to Keycloak 27.
6 changes: 3 additions & 3 deletions docs/guides/server/caching.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ This is the foundation for the multi-cluster (v2) setup that is covered in more
In order to reduce memory usage, it's possible to place an upper bound on the number of entries which are stored in a given
cache. To specify an upper bound of on a cache, you must provide the following command line argument
`--cache-embedded-$\{CACHE_NAME}-max-count=`, with `$\{CACHE_NAME}` replaced with the name of the cache you would like to
apply the upper bound to. For example, to apply an upper-bound of `1000` to the `offlineSessions` cache you would configure
`--cache-embedded-offline-sessions-max-count=1000`. An upper bound can not be defined on the following caches:
apply the upper bound to. For example, to apply an upper-bound of `1000` to the `sessions` cache you would configure
`--cache-embedded-sessions-max-count=1000`. An upper bound can not be defined on the following caches:
`actionToken`, `authenticationSessions`, `loginFailures`, `work`.

Setting a maximum cache size for `sessions`, `clientSessions` is not supported when the deprecated volatile sessions mode is used.
When volatile user sessions are in use, limits on the `sessions` and `clientSessions` caches are ignored; only the offline session cache limits remain supported in that mode.

=== Specify your own cache configuration file

Expand Down
8000
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.infinispan.util.InfinispanUtils;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.UserSessionProviderFactory;
Expand Down Expand Up @@ -83,8 +81,6 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
public static final String REALM_REMOVED_SESSION_EVENT = "REALM_REMOVED_EVENT_SESSIONS";

public static final String REMOVE_USER_SESSIONS_EVENT = "REMOVE_USER_SESSIONS_EVENT";
public static final String CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE = "offlineSessionCacheEntryLifespanOverride";
public static final String CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE = "offlineClientSessionCacheEntryLifespanOverride";
public static final String CONFIG_USE_CACHES = "useCaches";
private static final boolean DEFAULT_USE_CACHES = true;
public static final String CONFIG_EXPIRATION_PERIOD = "sessionExpirationPeriod";
Expand All @@ -105,10 +101,6 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
private SessionResurrectionGuardListener<String, UserSessionEntity> offlineSessionResurrectionListener;
private ExpirationTask expirationTask;

private long offlineSessionCacheEntryLifespanOverride;

private long offlineClientSessionCacheEntryLifespanOverride;

private PersisterLastSessionRefreshStore persisterLastSessionRefreshStore;
private boolean useCaches;
private int expirationPeriodSeconds;
Expand All @@ -132,23 +124,13 @@ public UserSessionProvider create(KeycloakSession session) {
tx.offlineSessionTx,
tx.clientSessionTx,
tx.offlineClientSessionTx,
this::deriveOfflineSessionCacheEntryLifespanMs,
this::deriveOfflineClientSessionCacheEntryLifespanOverrideMs
SessionTimeouts::getOfflineSessionLifespanMs,
SessionTimeouts::getOfflineClientSessionLifespanMs
);
}

@Override
public void init(Config.Scope config) {
offlineSessionCacheEntryLifespanOverride = config.getInt(CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, -1);
if (offlineSessionCacheEntryLifespanOverride != -1) {
// to be removed in KC 27
log.warn("The option spi-user-sessions--infinispan--offline-session-cache-entry-lifespan-override is deprecated and will be removed in a future release");
}
offlineClientSessionCacheEntryLifespanOverride = config.getInt(CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, -1);
if (offlineClientSessionCacheEntryLifespanOverride != -1) {
// to be removed in KC 27
log.warn("The option spi-user-sessions--infinispan--offline-client-session-cache-entry-lifespan-override is deprecated and will be removed in a future release");
}
// Deprecated since 26.8: disabling persistent user sessions (volatile sessions) is deprecated.
if (!MultiSiteUtils.isPersistentSessionsEnabled()) {
log.warn("Disabling the persistent-user-sessions feature is deprecated since Keycloak 26.8 and will not be supported in a future release. Persistent user sessions will become the only supported mode.");
Expand Down Expand Up @@ -212,9 +194,9 @@ public void postInit(final KeycloakSessionFactory factory) {
} else {
try (var session = factory.create()) {
sessionCacheHolder = InfinispanChangesUtils.createWithCache(session, USER_SESSION_CACHE_NAME, SessionTimeouts::getUserSessionLifespanMs, SessionTimeouts::getUserSessionMaxIdleMs, SecretGenerator.SECURE_ID_GENERATOR);
offlineSessionCacheHolder = InfinispanChangesUtils.createWithCache(session, OFFLINE_USER_SESSION_CACHE_NAME, this::deriveOfflineSessionCacheEntryLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs, null, true);
offlineSessionCacheHolder = InfinispanChangesUtils.createWithCache(session, OFFLINE_USER_SESSION_CACHE_NAME, SessionTimeouts::getOfflineSessionLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs, null, true);
clientSessionCacheHolder = InfinispanChangesUtils.createWithCache(session, CLIENT_SESSION_CACHE_NAME, SessionTimeouts::getClientSessionLifespanMs, SessionTimeouts::getClientSessionMaxIdleMs);
offlineClientSessionCacheHolder = InfinispanChangesUtils.createWithCache(session, OFFLINE_CLIENT_SESSION_CACHE_NAME, this::deriveOfflineClientSessionCacheEntryLifespanOverrideMs, SessionTimeouts::getOfflineClientSessionMaxIdleMs);
offlineClientSessionCacheHolder = InfinispanChangesUtils.createWithCache(session, OFFLINE_CLIENT_SESSION_CACHE_NAME, SessionTimeouts::getOfflineClientSessionLifespanMs, SessionTimeouts::getOfflineClientSessionMaxIdleMs);
var blockingManager = session.getProvider(InfinispanConnectionProvider.class).getBlockingManager();
expirationListener = new EmbeddedUserSessionExpirationListener(session.getKeycloakSessionFactory(), blockingManager);
}
Expand Down Expand Up @@ -317,41 +299,6 @@ protected void eventReceived(UserSessionProvider provider, RemoveUserSessionsEve
log.debug("Registered cluster listeners");
}

protected Long deriveOfflineSessionCacheEntryLifespanMs(RealmModel realm, ClientModel client, UserSessionEntity entity) {

long configuredOfflineSessionLifespan = SessionTimeouts.getOfflineSessionLifespanMs(realm, client, entity);

if (offlineSessionCacheEntryLifespanOverride == -1) {
// override not configured -> take the value from realm settings
return configuredOfflineSessionLifespan;
}

if (configuredOfflineSessionLifespan == -1) {
// "Offline Session Max Limited" is "off"
return TimeUnit.SECONDS.toMillis(offlineSessionCacheEntryLifespanOverride);
}

// both values are configured, Offline Session Max could be smaller than the override, so we use the minimum of both
return Math.min(TimeUnit.SECONDS.toMillis(offlineSessionCacheEntryLifespanOverride), configuredOfflineSessionLifespan);
}

protected Long deriveOfflineClientSessionCacheEntryLifespanOverrideMs(RealmModel realm, ClientModel client, AuthenticatedClientSessionEntity entity) {

long configuredOfflineClientSessionLifespan = SessionTimeouts.getOfflineClientSessionLifespanMs(realm, client, entity);

if (offlineClientSessionCacheEntryLifespanOverride == -1) {
// override not configured -> take the value from realm settings
return configuredOfflineClientSessionLifespan;
}

if (configuredOfflineClientSessionLifespan == -1) {
// "Offline Session Max Limited" is "off"
return TimeUnit.SECONDS.toMillis(offlineClientSessionCacheEntryLifespanOverride);
}

// both values are configured, Offline Session Max could be smaller than the override, so we use the minimum of both
return Math.min(TimeUnit.SECONDS.toMillis(offlineClientSessionCacheEntryLifespanOverride), configuredOfflineClientSessionLifespan);
}

@Override
public void close() {
Expand Down Expand Up @@ -391,8 +338,6 @@ public boolean isSupported(Config.Scope config) {
@Override
public Map<String, String> getOperationalInfo() {
Map<String, String> info = new HashMap<>();
info.put(CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, Long.toString(offlineSessionCacheEntryLifespanOverride));
info.put(CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE, Long.toString(offlineClientSessionCacheEntryLifespanOverride));
info.put(CONFIG_USE_CACHES, Boolean.toString(useCaches));
info.put(CONFIG_EXPIRATION_PERIOD, Integer.toString(expirationPeriodSeconds));
return info;
Expand All @@ -402,18 +347,6 @@ public Map<String, String> getOperationalInfo() {
public List<ProviderConfigProperty> getConfigMetadata() {
ProviderConfigurationBuilder builder = ProviderConfigurationBuilder.create();

builder.property()
.name(CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE)
.type("int")
.helpText("Override how long offline client sessions should be kept in memory in seconds (deprecated, to be removed in Keycloak 27)")
.add();

builder.property()
.name(CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE)
.type("int")
.helpText("Override how long offline user sessions should be kept in memory in seconds (deprecated, to be removed in Keycloak 27)")
.add();

builder.property()
.name(CONFIG_USE_CACHES)
.type("boolean")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,7 @@ public void updateConfig(Config cf) {
.config("stalledTimeoutInSeconds", "10")
.spi(UserSessionSpi.NAME)
.provider(InfinispanUtils.EMBEDDED_PROVIDER_ID)
.config("sessionPreloadStalledTimeoutInSeconds", "10")
.config("offlineSessionCacheEntryLifespanOverride", "43200")
.config("offlineClientSessionCacheEntryLifespanOverride", "43200");
.config("sessionPreloadStalledTimeoutInSeconds", "10");
cf.spi(CacheEmbeddedConfigProviderSpi.SPI_NAME)
.provider(DefaultCacheEmbeddedConfigProviderFactory.PROVIDER_ID)
.config(DefaultCacheEmbeddedConfigProviderFactory.CONFIG, "test-ispn.xml")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,12 @@
import org.keycloak.timer.TimerProvider;

import org.hamcrest.Matchers;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeFalse;

/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
Expand Down Expand Up @@ -517,48 +514,6 @@ public void testLoadingOfflineClientSessionWhenCreatedBeforeSessionTime() {
return null;
});
}

@Test
public void testOfflineSessionLifespanOverride() {
// As offline session's timeout is not overriden when PERSISTENT_USER_SESSIONS is enabled
Assume.assumeFalse(MultiSiteUtils.isPersistentSessionsEnabled());
assumeFalse("Clusterless Feature enabled", Profile.isFeatureEnabled(Profile.Feature.CLUSTERLESS));

createOfflineSessions("user1", 2, new LinkedList<>(), new LinkedList<>());

reinitializeKeycloakSessionFactory();

withRealm(realmId, (session, realm) -> {
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);

// skip remote cache load as we are only interested in embedded caches
AdvancedCache<?, ?> offlineUSCache = provider.getCache(InfinispanConnectionProvider.OFFLINE_USER_SESSION_CACHE_NAME).getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD);
AdvancedCache<?, ?> offlineCSCache = provider.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME).getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD);

Assert.assertEquals(0, offlineUSCache.size());
Assert.assertEquals(0, offlineCSCache.size());

// lazy load offline user sessions from DB => this should also import user and client sessions to the caches
Assert.assertEquals(2, session.sessions().getOfflineUserSessionsStream(realm, session.users().getUserByUsername(realm, "user1")).count());

// check sessions were imported to the caches
Assert.assertEquals(2, offlineUSCache.size());
Assert.assertEquals(4, offlineCSCache.size());

// lifespan override set to 12h (43200s)
setTimeOffset(44000);

// check sessions were evicted from the caches
Assert.assertEquals(0, offlineUSCache.size());
Assert.assertEquals(0, offlineCSCache.size());

// sessions should still be in the DB
Assert.assertEquals(2, session.sessions().getOfflineUserSessionsStream(realm, session.users().getUserByUsername(realm, "user1")).count());

return null;
});
}

@Test
public void testExpirationTaskExists() {
// embedded + volatile sessions store offline sessions in the database, the task must be running in this case too.
Expand Down
Loading
0