diff --git a/common/src/main/java/org/keycloak/common/Profile.java b/common/src/main/java/org/keycloak/common/Profile.java index a6666cb536..6d646783d1 100755 --- a/common/src/main/java/org/keycloak/common/Profile.java +++ b/common/src/main/java/org/keycloak/common/Profile.java @@ -122,7 +122,7 @@ public class Profile { PASSKEYS("Passkeys", Type.PREVIEW), - REMOTE_STORE_CROSS_DC("Support for remote-store in embedded Infinispan caches", Type.DEPRECATED) + CACHE_EMBEDDED_REMOTE_STORE("Support for remote-store in embedded Infinispan caches", Type.EXPERIMENTAL), ; private final Type type; diff --git a/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc b/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc index 18031cbdf7..5d9fabfd5c 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc @@ -114,25 +114,24 @@ so you must configure the connection to the external {jdgserver_name} deployment or Keycloak CR as outlined in the blueprints. All `remote-store` configurations must be removed from the cache configuration file. . Review your current cache configurations in the external {jdgserver_name} and update them with those outlined in the latest version of the {project_name}'s documentation. +While previous versions of the cache configurations only logged warnings when the backup replication between sites failed, the new configurations ensure that the state in both sites stays in sync: When the transfer between the two sites fails, the caller will see an error. +Due to that, you need to set up monitoring to disconnect the two sites in case of a site failure. +The Keycloak High Availability Guide contains a blueprint on how to set this up. . While previous LoadBalancer configurations will continue to work with {project_name}, consider upgrading an existing Route53 configurations to avoid prolonged failover times due to client side DNS caching. -= Deprecating remote-store in embedded Infinispan caches +. If you have updated your cache configuration XML file with remote-store configurations, those will no longer work. +Instead, enable the `multi-site` feature and use the `cache-remove-*` options. -In {project_name} versions 24 to 25 to achieve a multi-site setup, a remote store in embedded Infinispan caches was configured. -Manual configurations for the cache XML for multi-site were discouraged as CLI options to configure the caches are available. -With the upgraded multi-site feature in 26, the same CLI options exist, but don't use embedded Infinispan caches anymore. += External {jdgserver_name} in a single-site setup -In the community, remote stores for embedded Infinispan caches were used in some setups to keep user sessions when the {project_name} cluster was shut down or upgraded. -This was never supported, documented or tested. -As a fully supported alternative, the persistent user sessions feature should be used instead. +If you are using an external {jdgserver_name} in a single-site setup, this was not supported in earlier versions of {project_name} and it is not supported in {project_name} 26. +To protect users from using it accidentally via a manual configuration in Keycloak's cache XML or via the CLI options, this is now guarded with a feature flag `cache-embedded-remote-store`. It is marked as experimental and is therefore not supported. {project_name} 26 will not start with such a configuration and show an error instead unless this experimental feature is enabled. -Due to this, using remote caches in embedded Infinispan caches is now marked as deprecated with the plan to remove it. -As it was never used outside multi-site setups that now achieve this by different means, it might be removed even in a future minor release. -To be able to use the deprecated feature, you need to enable the feature `remote-store-cross-dc` or {project_name} will not start. +If you have been using an external {jdgserver_name} to keep users logged in between restarts and upgrades, use the `persistent-user-sessions` feature instead which is enabled by default. The external {jdgserver_name} is then no longer necessary. -There is an experimental feature `remote-cache` which allows leveraging the new multi-site mechanisms to store session related data in an external {jdgserver_name} server also for single site setups. +The experimental feature `cache-embedded-remote-store` *will be removed in a future minor release*. = Admin Bootstrapping and Recovery diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java index 72452a072a..2edc5491e2 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java @@ -451,21 +451,21 @@ public class CacheManagerFactory { } private static void checkForRemoteStores(ConfigurationBuilderHolder builder) { - if (Profile.isFeatureEnabled(Profile.Feature.REMOTE_STORE_CROSS_DC) && Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)) { + if (Profile.isFeatureEnabled(Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE) && Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)) { logger.fatalf("Feature %s is now deprecated.%nFor multi-site (cross-dc) support, enable only %s.", - Profile.Feature.REMOTE_STORE_CROSS_DC.getKey(), Profile.Feature.MULTI_SITE.getKey()); - throw new RuntimeException("The features " + Profile.Feature.REMOTE_STORE_CROSS_DC.getKey() + " and " + Profile.Feature.MULTI_SITE.getKey() + " must not be enabled at the same time."); + Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE.getKey(), Profile.Feature.MULTI_SITE.getKey()); + throw new RuntimeException("The features " + Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE.getKey() + " and " + Profile.Feature.MULTI_SITE.getKey() + " must not be enabled at the same time."); } - if (Profile.isFeatureEnabled(Profile.Feature.REMOTE_STORE_CROSS_DC) && Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)) { + if (Profile.isFeatureEnabled(Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE) && Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)) { logger.fatalf("Feature %s is now deprecated.%nFor multi-site (cross-dc) support, enable only %s.", - Profile.Feature.REMOTE_STORE_CROSS_DC.getKey(), Profile.Feature.REMOTE_CACHE.getKey()); - throw new RuntimeException("The features " + Profile.Feature.REMOTE_STORE_CROSS_DC.getKey() + " and " + Profile.Feature.REMOTE_CACHE.getKey() + " must not be enabled at the same time."); + Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE.getKey(), Profile.Feature.REMOTE_CACHE.getKey()); + throw new RuntimeException("The features " + Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE.getKey() + " and " + Profile.Feature.REMOTE_CACHE.getKey() + " must not be enabled at the same time."); } - if (!Profile.isFeatureEnabled(Profile.Feature.REMOTE_STORE_CROSS_DC)) { + if (!Profile.isFeatureEnabled(Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE)) { if (builder.getNamedConfigurationBuilders().values().stream().anyMatch(CacheManagerFactory::hasRemoteStore)) { logger.fatalf("Remote stores are not supported for embedded caches as feature %s is not enabled. This feature is disabled by default as it is now deprecated.%nFor keeping user sessions across restarts, use feature %s which is enabled by default.%nFor multi-site (cross-dc) support, enable %s.", - Profile.Feature.REMOTE_STORE_CROSS_DC.getKey(), Profile.Feature.PERSISTENT_USER_SESSIONS.getKey(), Profile.Feature.MULTI_SITE.getKey()); - throw new RuntimeException("Remote store is not supported as feature " + Profile.Feature.REMOTE_STORE_CROSS_DC.getKey() + " is not enabled."); + Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE.getKey(), Profile.Feature.PERSISTENT_USER_SESSIONS.getKey(), Profile.Feature.MULTI_SITE.getKey()); + throw new RuntimeException("Remote store is not supported as feature " + Profile.Feature.CACHE_EMBEDDED_REMOTE_STORE.getKey() + " is not enabled."); } } }