From 6fc99cd7496be821f3f852eb4aa06c71fa522d77 Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 9 Aug 2018 15:01:54 +0200 Subject: [PATCH] KEYCLOAK-7594 Upgrade to Wildfly 13. Cross-DC: Upgrade to infinispan server 9.2.4 and JDG 7.2 Co-authored-by: Douglas Palmer Co-authored-by: stianst Co-authored-by: Hynek Mlnarik --- adapters/oidc/installed/pom.xml | 2 +- adapters/oidc/jaxrs-oauth-client/pom.xml | 2 +- authz/policy/drools/pom.xml | 2 +- .../demo-dist/src/main/xslt/standalone.xsl | 14 +- .../server-feature-pack/assembly.xml | 4 + .../feature-packs/server-feature-pack/pom.xml | 46 + .../configuration/domain/template.xml | 2 +- .../configuration/host/host-master.xml | 2 +- .../configuration/host/host-slave.xml | 2 +- .../resources/configuration/host/host.xml | 2 +- .../configuration/standalone/template.xml | 4 +- .../content/bin/migrate-domain-clustered.cli | 97 +- .../content/bin/migrate-domain-standalone.cli | 61 + .../content/bin/migrate-standalone-ha.cli | 98 +- .../content/bin/migrate-standalone.cli | 61 +- .../keycloak-model-infinispan/main/module.xml | 3 +- .../main/server-war/WEB-INF/web.xml | 2 +- .../keycloak-wildfly-adduser/main/module.xml | 4 +- distribution/server-dist/assembly.xml | 8 - distribution/server-dist/pom.xml | 11 - .../src/main/cli/keycloak-install-base.cli | 11 +- .../src/main/cli/keycloak-install-ha-base.cli | 27 +- distribution/server-provisioning-devel.xml | 3 - distribution/server-provisioning.xml | 3 - .../broker/twitter-authentication/pom.xml | 2 +- examples/providers/domain-extension/pom.xml | 2 +- examples/providers/rest/pom.xml | 2 +- integration/admin-client/pom.xml | 2 +- integration/client-cli/admin-cli/pom.xml | 2 +- .../InfinispanClusterProviderFactory.java | 8 +- .../DefaultInfinispanConnectionProvider.java | 17 +- ...ltInfinispanConnectionProviderFactory.java | 88 +- .../InfinispanConnectionProvider.java | 10 +- .../connections/infinispan/TopologyInfo.java | 202 +++ ...nfinispanStickySessionEncoderProvider.java | 24 +- ...anStickySessionEncoderProviderFactory.java | 10 +- .../InfinispanUserSessionProvider.java | 1 - .../InfinispanUserSessionProviderFactory.java | 8 +- .../changes/SessionEntityWrapper.java | 8 +- .../sessions/LastSessionRefreshListener.java | 20 +- .../changes/sessions/SessionData.java | 5 +- .../AuthenticatedClientSessionEntity.java | 8 +- .../entities/AuthenticationSessionEntity.java | 2 +- .../entities/UserSessionEntity.java | 8 +- .../AbstractUserSessionClusterListener.java | 6 +- .../events/SessionClusterEvent.java | 6 +- .../initializer/BaseCacheInitializer.java | 33 +- .../InfinispanCacheInitializer.java | 45 +- .../initializer/InitializerState.java | 32 +- .../OfflinePersistentUserSessionLoader.java | 30 +- ...inePersistentUserSessionLoaderContext.java | 66 + .../initializer/SessionInitializerWorker.java | 11 +- .../infinispan/initializer/SessionLoader.java | 29 +- .../SingleWorkerCacheInitializer.java | 51 - .../remotestore/RemoteCacheInvoker.java | 34 +- .../RemoteCacheSessionListener.java | 51 +- .../RemoteCacheSessionsLoader.java | 177 +-- .../RemoteCacheSessionsLoaderContext.java | 99 ++ .../sessions/infinispan/stream/Mappers.java | 1 - .../infinispan/util/InfinispanUtil.java | 31 +- .../infinispan/util/KeycloakMarshallUtil.java | 1 - ...t.java => ConcurrencyJDGCachePutTest.java} | 16 +- ...va => ConcurrencyJDGCacheReplaceTest.java} | 14 +- ...encyJDGRemoteCacheClientListenersTest.java | 23 +- .../RemoteCacheSessionsLoaderTest.java | 160 +++ .../infinispan/TestCacheManagerFactory.java | 3 + .../InfinispanKeyStorageProviderTest.java | 5 +- .../initializer/ConcurrencyLockingTest.java | 4 +- .../ConcurrencyVersioningTest.java | 4 +- .../DistributedCacheWriteSkewTest.java | 4 +- .../initializer/InitializerStateTest.java | 49 +- pom.xml | 40 +- services/pom.xml | 2 +- .../services/managers/AuthSessionId.java | 44 + .../AuthenticationSessionManager.java | 71 +- .../managers/UserSessionCrossDCManager.java | 10 +- .../integration-arquillian/HOW-TO-RUN.md | 11 + .../servers/app-server/jboss/common/io.xsl | 2 +- .../servers/app-server/tomcat/pom.xml | 2 +- .../jboss/common/ispn-cache-owners.xsl | 12 +- .../main/module.xml | 1 + .../jboss/common/add-keycloak-caches.xsl | 5 +- .../cache-server/jboss/infinispan/pom.xml | 1 + .../servers/cache-server/jboss/jdg/pom.xml | 3 +- .../servers/cache-server/jboss/pom.xml | 9 + .../integration-arquillian/servers/pom.xml | 4 +- .../photoz/photoz-restful-api/pom.xml | 2 +- .../test-apps/servlets/pom.xml | 2 +- .../AuthenticationSessionClusterTest.java | 2 +- .../crossdc/ActionTokenCrossDCTest.java | 10 +- .../crossdc/BruteForceCrossDCTest.java | 5 + .../crossdc/ConcurrentLoginCrossDCTest.java | 2 - .../crossdc/SessionExpirationCrossDCTest.java | 14 +- .../error/UncaughtErrorPageTest.java | 14 +- .../resources/META-INF/keycloak-server.json | 2 +- .../other/server-config-migration/README.md | 2 +- .../domain/domain-3.4.3.Final-redhat-2.xml | 1123 +++++++++++++++++ .../host-master-3.4.3.Final-redhat-2.xml | 185 +++ .../standalone-3.4.3.Final-redhat-2.xml | 573 +++++++++ .../standalone-ha-3.4.3.Final-redhat-2.xml | 631 +++++++++ .../integration-arquillian/tests/pom.xml | 2 +- testsuite/integration-deprecated/pom.xml | 2 +- testsuite/jetty/jetty92/pom.xml | 2 +- testsuite/jetty/jetty93/pom.xml | 2 +- testsuite/jetty/jetty94/pom.xml | 2 +- .../jboss-cli/add-remote-cache-stores.cli | 2 +- testsuite/performance/tests/pom.xml | 2 +- testsuite/proxy/pom.xml | 2 +- testsuite/tomcat7/pom.xml | 2 +- testsuite/tomcat8/pom.xml | 2 +- testsuite/utils/pom.xml | 2 +- .../resources/META-INF/keycloak-server.json | 8 +- wildfly/adduser/pom.xml | 6 +- .../org/keycloak/wildfly/adduser/AddUser.java | 73 +- .../default-server-subsys-config.properties | 2 +- .../cli/default-keycloak-subsys-config.cli | 2 +- .../keycloak-infinispan.xml | 56 +- .../subsystem-templates/keycloak-undertow.xml | 42 +- .../JsonConfigConverterTestCase.java | 4 +- 119 files changed, 4224 insertions(+), 660 deletions(-) create mode 100644 model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java create mode 100644 model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoaderContext.java delete mode 100644 model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SingleWorkerCacheInitializer.java create mode 100644 model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoaderContext.java rename model/infinispan/src/test/java/org/keycloak/cluster/infinispan/{ConcurrencyJDGRemoteCacheTest.java => ConcurrencyJDGCachePutTest.java} (93%) rename model/infinispan/src/test/java/org/keycloak/cluster/infinispan/{ConcurrencyJDGSessionsCacheTest.java => ConcurrencyJDGCacheReplaceTest.java} (97%) create mode 100644 model/infinispan/src/test/java/org/keycloak/cluster/infinispan/RemoteCacheSessionsLoaderTest.java create mode 100644 services/src/main/java/org/keycloak/services/managers/AuthSessionId.java create mode 100644 testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/domain-3.4.3.Final-redhat-2.xml create mode 100644 testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/host-master-3.4.3.Final-redhat-2.xml create mode 100644 testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-3.4.3.Final-redhat-2.xml create mode 100644 testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-ha-3.4.3.Final-redhat-2.xml diff --git a/adapters/oidc/installed/pom.xml b/adapters/oidc/installed/pom.xml index 0e89e2b676f..e07cc0e57a2 100755 --- a/adapters/oidc/installed/pom.xml +++ b/adapters/oidc/installed/pom.xml @@ -69,7 +69,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec diff --git a/adapters/oidc/jaxrs-oauth-client/pom.xml b/adapters/oidc/jaxrs-oauth-client/pom.xml index a8acfdaf795..472e5c8790e 100755 --- a/adapters/oidc/jaxrs-oauth-client/pom.xml +++ b/adapters/oidc/jaxrs-oauth-client/pom.xml @@ -33,7 +33,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec provided diff --git a/authz/policy/drools/pom.xml b/authz/policy/drools/pom.xml index b633e229a75..a8b20e23268 100644 --- a/authz/policy/drools/pom.xml +++ b/authz/policy/drools/pom.xml @@ -55,7 +55,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec provided diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl index 7f18d0df34b..3754763c1f7 100755 --- a/distribution/demo-dist/src/main/xslt/standalone.xsl +++ b/distribution/demo-dist/src/main/xslt/standalone.xsl @@ -17,7 +17,7 @@ - + - + - + @@ -95,12 +95,12 @@ - + - + @@ -114,4 +114,4 @@ - \ No newline at end of file + diff --git a/distribution/feature-packs/server-feature-pack/assembly.xml b/distribution/feature-packs/server-feature-pack/assembly.xml index c93393873df..7c64b1a9603 100644 --- a/distribution/feature-packs/server-feature-pack/assembly.xml +++ b/distribution/feature-packs/server-feature-pack/assembly.xml @@ -33,6 +33,10 @@ target/unpacked-themes/theme content/themes + + target/keycloak-client-tools/bin + content/bin + src/main/resources/identity/module diff --git a/distribution/feature-packs/server-feature-pack/pom.xml b/distribution/feature-packs/server-feature-pack/pom.xml index cceef6646f2..1d0ada966a6 100644 --- a/distribution/feature-packs/server-feature-pack/pom.xml +++ b/distribution/feature-packs/server-feature-pack/pom.xml @@ -612,6 +612,17 @@ + + org.keycloak + keycloak-client-cli-dist + zip + + + * + * + + + org.kie kie-api @@ -713,6 +724,16 @@ + + org.aesh + aesh + + + * + * + + + @@ -740,9 +761,34 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack-cli + validate + + unpack + + + + + org.keycloak + keycloak-client-cli-dist + zip + target/ + + + + + + + org.wildfly.build wildfly-feature-pack-build-maven-plugin + ${wildfly.build-tools.version} feature-pack-build diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml index 5774706ac94..47f05e5b1c2 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml @@ -17,7 +17,7 @@ ~ limitations under the License. --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml index 095fcc4cc5d..166e2207fb9 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml @@ -22,7 +22,7 @@ is also started by this host controller file. The other instance must be started via host-slave.xml --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml index 3b1812ea6b6..2cc9a3bc080 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml @@ -17,7 +17,7 @@ ~ limitations under the License. --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml index 6a4dba4ff15..07c65adc1e6 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml @@ -23,7 +23,7 @@ via host-slave.xml --> - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml index 7b13afe79ef..5c2cb0e6f33 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml @@ -1,6 +1,6 @@ - + @@ -87,4 +87,4 @@ - \ No newline at end of file + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-clustered.cli b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-clustered.cli index 21fe61b3fd0..9b9729cd83e 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-clustered.cli +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-clustered.cli @@ -115,8 +115,7 @@ if (result == undefined) of /profile=$clusteredProfile/subsystem=infinispan/cach /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=expiration/:write-attribute(name=max-idle,value=3600000) echo end-if - -if (outcome == failed) of /profile=$clusteredProfile/subsystem=keycloak-server/spi=publicKeyStorage/:read-resource +if (outcome == failed) of /profile=$clusteredProfile/subsystem=keycloak-server/spi=publicKeyStorage/:read-resource echo Adding spi=publicKeyStorage... /profile=$clusteredProfile/subsystem=keycloak-server/spi=publicKeyStorage/:add /profile=$clusteredProfile/subsystem=keycloak-server/spi=publicKeyStorage/provider=infinispan/:add(properties={minTimeBetweenRequests => "10"},enabled=true) @@ -447,4 +446,98 @@ if (outcome == failed) of /profile=$clusteredProfile/subsystem=keycloak-server/s echo end-if +# Migrate from 4.3.0 to 4.4.0 +if (outcome == failed) of /profile=$clusteredProfile/subsystem=elytron/permission-set=login-permission/:read-resource + echo Adding permission-set=login-permission to elytron + /profile=$clusteredProfile/subsystem=elytron/permission-set=login-permission:add(permissions=[{class-name=org.wildfly.security.auth.permission.LoginPermission}]) + /profile=$clusteredProfile/subsystem=elytron/permission-set=default-permissions/:add(permissions=[{class-name=org.wildfly.extension.batch.jberet.deployment.BatchPermission,module=org.wildfly.extension.batch.jberet,target-name=*},{class-name=org.wildfly.transaction.client.RemoteTransactionPermission,module=org.wildfly.transaction.client},{class-name=org.jboss.ejb.client.RemoteEJBPermission,module=org.jboss.ejb-client}]) + /profile=$clusteredProfile/subsystem=elytron/simple-permission-mapper=default-permission-mapper/:undefine-attribute(name=permission-mappings) + /profile=$clusteredProfile/subsystem=elytron/simple-permission-mapper=default-permission-mapper:write-attribute(name=permission-mappings,value=[{permission-sets=[{permission-set=login-permission},{permission-set=default-permissions}],match-all=true},{permission-sets=[{permission-set=default-permissions}],principals=[anonymous]}]) + echo +end-if + +if (result == org.hibernate.infinispan) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate:read-attribute(name=module) + echo Update hibernate cache module + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate:write-attribute(name=module, value=org.infinispan.hibernate-cache) + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate:read-attribute(name=default-cache) + echo Remove default cache from hibernate cache + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate:undefine-attribute(name=default-cache) + echo +end-if +if (result == ASYNC) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/replicated-cache=timestamps:read-attribute(name=mode) + echo Switching mode for timestamps cache from ASYNC to SYNC + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/replicated-cache=timestamps:write-attribute(name=mode, value=SYNC) + echo +end-if + +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:read-resource + echo Removing eviction from hibernate entity cache and replacing with object-memory + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:remove + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/local-cache=entity/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/distributed-cache=local-query/eviction=EVICTION:read-resource + echo Removing eviction from hibernate local-query cache and replacing with object-memory + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/local-cache=local-query/eviction=EVICTION:remove + /profile=$clusteredProfile/subsystem=infinispan/cache-container=hibernate/local-cache=local-query/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:read-resource + echo Removing eviction from keycloak realms cache and replacing with object-memory + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:remove + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:read-resource + echo Removing eviction from keycloak users cache and replacing with object-memory + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:remove + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:read-resource + echo Removing eviction from keycloak authorization cache and replacing with object-memory + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:remove + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:read-resource + echo Removing eviction from keycloak keys cache and replacing with object-memory + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:remove + /profile=$clusteredProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/memory=object:add(size=1000) + echo +end-if + +if (outcome == success) of /profile=$clusteredProfile/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:read-resource + echo Changing JNDI reference in connectionsInfinispan SPI + /profile=$clusteredProfile/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:undefine-attribute(name=properties) + /profile=$clusteredProfile/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:write-attribute(name=properties,value={cacheContainer=java:jboss/infinispan/container/keycloak}) + echo +end-if + +if (outcome == success) of /profile=$clusteredProfile/subsystem=jgroups/stack=tcp/protocol=FRAG2:read-resource + echo Upgrade jgroups protocol from FRAG2 to FRAG3 for tcp stack + /profile=$clusteredProfile/subsystem=jgroups/stack=tcp/protocol=FRAG2:remove + /profile=$clusteredProfile/subsystem=jgroups/stack=tcp/protocol=FRAG3:add() + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=jgroups/stack=udp/protocol=FRAG2:read-resource + echo Upgrade jgroups protocol from FRAG2 to FRAG3 for udp stack + /profile=$clusteredProfile/subsystem=jgroups/stack=udp/protocol=FRAG2:remove + /profile=$clusteredProfile/subsystem=jgroups/stack=udp/protocol=FRAG3:add() + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/subsystem=remoting/configuration=endpoint:read-resource + echo Remove endpoint from remoting configuration + /profile=$clusteredProfile/subsystem=remoting/configuration=endpoint:remove + echo +end-if +if (outcome == success) of /profile=$clusteredProfile/socket-binding-group=$clusteredProfile-sockets/socket-binding=jgroups-mping:read-attribute(name=port) + /profile=$clusteredProfile/socket-binding-group=$clusteredProfile-sockets/socket-binding=jgroups-mping:undefine-attribute(name=port) +end-if +if (outcome == success) of /socket-binding-group=$clusteredProfile-sockets/socket-binding=modcluster:read-attribute(name=port) + /profile=$clusteredProfile/socket-binding-group=$clusteredProfile-sockets/socket-binding=modcluster:undefine-attribute(name=port) +end-if + echo *** End Migration of /profile=$clusteredProfile *** \ No newline at end of file diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-standalone.cli b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-standalone.cli index 56b676c89ca..49de7ae400e 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-standalone.cli +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-domain-standalone.cli @@ -47,6 +47,7 @@ if (result == undefined) of /profile=$standaloneProfile/subsystem=infinispan/cac echo Updating authorization cache container.. /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:write-attribute(name=strategy,value=LRU) /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:write-attribute(name=max-entries,value=100) + echo end-if # Migrate from 2.0.0 to 2.1.0 @@ -347,6 +348,7 @@ if (outcome == success) of /profile=$standaloneProfile/subsystem=undertow/server /profile=$standaloneProfile/subsystem=undertow/server=default-server/host=default-host/filter-ref=x-powered-by-header/:remove /profile=$standaloneProfile/subsystem=undertow/configuration=filter/response-header=x-powered-by-header/:remove /profile=$standaloneProfile/subsystem=undertow/configuration=filter/response-header=server-header/:remove + echo end-if if (outcome == success) of /profile=$standaloneProfile/subsystem=jdr/:read-resource @@ -404,4 +406,63 @@ if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/ echo end-if +# Migrate from 4.3.0 to 4.4.0 +if (outcome == failed) of /profile=$standaloneProfile/subsystem=elytron/permission-set=login-permission/:read-resource + echo Adding permission-set=login-permission to elytron + /profile=$standaloneProfile/subsystem=elytron/permission-set=login-permission:add(permissions=[{class-name=org.wildfly.security.auth.permission.LoginPermission}]) + /profile=$standaloneProfile/subsystem=elytron/permission-set=default-permissions/:add(permissions=[{class-name=org.wildfly.extension.batch.jberet.deployment.BatchPermission,module=org.wildfly.extension.batch.jberet,target-name=*},{class-name=org.wildfly.transaction.client.RemoteTransactionPermission,module=org.wildfly.transaction.client},{class-name=org.jboss.ejb.client.RemoteEJBPermission,module=org.jboss.ejb-client}]) + /profile=$standaloneProfile/subsystem=elytron/simple-permission-mapper=default-permission-mapper/:undefine-attribute(name=permission-mappings) + /profile=$standaloneProfile/subsystem=elytron/simple-permission-mapper=default-permission-mapper:write-attribute(name=permission-mappings,value=[{permission-sets=[{permission-set=login-permission},{permission-set=default-permissions}],match-all=true},{permission-sets=[{permission-set=default-permissions}],principals=[anonymous]}]) + echo +end-if + +if (result == org.hibernate.infinispan) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate:read-attribute(name=module) + echo Update hibernate cache module + /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate:write-attribute(name=module, value=org.infinispan.hibernate-cache) + echo +end-if +if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:read-resource + echo Removing eviction from hibernate entity cache and replacing with object-memory + /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:remove + /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate/local-cache=entity/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate/local-cache=local-query/eviction=EVICTION:read-resource + echo Removing eviction from hibernate local-query cache and replacing with object-memory + /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate/local-cache=local-query/eviction=EVICTION:remove + /profile=$standaloneProfile/subsystem=infinispan/cache-container=hibernate/local-cache=local-query/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:read-resource + echo Removing eviction from keycloak realms cache and replacing with object-memory + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:remove + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:read-resource + echo Removing eviction from keycloak users cache and replacing with object-memory + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:remove + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:read-resource + echo Removing eviction from keycloak authorization cache and replacing with object-memory + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:remove + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:read-resource + echo Removing eviction from keycloak keys cache and replacing with object-memory + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:remove + /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/memory=object:add(size=1000) + echo +end-if + +if (outcome == success) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:read-resource + echo Changing JNDI reference in connectionsInfinispan SPI + /profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:undefine-attribute(name=properties) + /profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:write-attribute(name=properties,value={cacheContainer=java:jboss/infinispan/container/keycloak}) + echo +end-if + echo *** End Migration of /profile=$standaloneProfile *** \ No newline at end of file diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone-ha.cli b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone-ha.cli index 5b11647bdc0..e59194f0c02 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone-ha.cli +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone-ha.cli @@ -137,7 +137,7 @@ if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/invali echo end-if if (result == undefined) of /subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:read-attribute(name=strategy,include-defaults=false) - echo Updating eviction in local-cache=users... + echo Updating eviction in local-cache=users /subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:write-attribute(name=strategy,value=LRU) /subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:write-attribute(name=max-entries,value=10000) echo @@ -431,4 +431,100 @@ if (outcome == failed) of /subsystem=keycloak-server/spi=hostname/:read-resource echo end-if +# Migrate from 4.3.0 to 4.4.0 +if (outcome == failed) of /subsystem=elytron/permission-set=login-permission/:read-resource + echo Adding permission-set=login-permission to elytron + /subsystem=elytron/permission-set=login-permission:add(permissions=[{class-name=org.wildfly.security.auth.permission.LoginPermission}]) + /subsystem=elytron/permission-set=default-permissions/:add(permissions=[{class-name=org.wildfly.extension.batch.jberet.deployment.BatchPermission,module=org.wildfly.extension.batch.jberet,target-name=*},{class-name=org.wildfly.transaction.client.RemoteTransactionPermission,module=org.wildfly.transaction.client},{class-name=org.jboss.ejb.client.RemoteEJBPermission,module=org.jboss.ejb-client}]) + /subsystem=elytron/simple-permission-mapper=default-permission-mapper/:undefine-attribute(name=permission-mappings) + /subsystem=elytron/simple-permission-mapper=default-permission-mapper:write-attribute(name=permission-mappings,value=[{permission-sets=[{permission-set=login-permission},{permission-set=default-permissions}],match-all=true},{permission-sets=[{permission-set=default-permissions}],principals=[anonymous]}]) + echo +end-if + + +if (result == org.hibernate.infinispan) of /subsystem=infinispan/cache-container=hibernate:read-attribute(name=module) + echo Update hibernate cache module + /subsystem=infinispan/cache-container=hibernate:write-attribute(name=module, value=org.infinispan.hibernate-cache) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=hibernate:read-attribute(name=default-cache) + echo Remove default cache from hibernate cache + /subsystem=infinispan/cache-container=hibernate:undefine-attribute(name=default-cache) + echo +end-if +if (result == ASYNC) of /subsystem=infinispan/cache-container=hibernate/replicated-cache=timestamps:read-attribute(name=mode) + echo Switching mode for timestamps cache from ASYNC to SYNC + /subsystem=infinispan/cache-container=hibernate/replicated-cache=timestamps:write-attribute(name=mode, value=SYNC) + echo +end-if + +if (outcome == success) of /subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:read-resource + echo Removing eviction from hibernate entity cache and replacing with object-memory + /subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=hibernate/local-cache=entity/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=hibernate/distributed-cache=local-query/eviction=EVICTION:read-resource + echo Removing eviction from hibernate local-query cache and replacing with object-memory + /subsystem=infinispan/cache-container=hibernate/local-cache=local-query/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=hibernate/local-cache=local-query/memory=object:add(size=10000) + echo +end-if + +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:read-resource + echo Removing eviction from keycloak realms cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=realms/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:read-resource + echo Removing eviction from keycloak users cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=users/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:read-resource + echo Removing eviction from keycloak authorization cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=authorization/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:read-resource + echo Removing eviction from keycloak keys cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=keys/memory=object:add(size=1000) + echo +end-if + +if (outcome == success) of /subsystem=jgroups/stack=tcp/protocol=FRAG2:read-resource + echo Upgrade jgroups protocol from FRAG2 to FRAG3 for tcp stack + /subsystem=jgroups/stack=tcp/protocol=FRAG2:remove + /subsystem=jgroups/stack=tcp/protocol=FRAG3:add() + echo +end-if +if (outcome == success) of /subsystem=jgroups/stack=udp/protocol=FRAG2:read-resource + echo Upgrade jgroups protocol from FRAG2 to FRAG3 for udp stack + /subsystem=jgroups/stack=udp/protocol=FRAG2:remove + /subsystem=jgroups/stack=udp/protocol=FRAG3:add() + echo +end-if +if (outcome == success) of /subsystem=remoting/configuration=endpoint:read-resource + echo Remove endpoint from remoting configuration + /subsystem=remoting/configuration=endpoint:remove + echo +end-if +if (outcome == success) of /socket-binding-group=standard-sockets/socket-binding=jgroups-mping:read-attribute(name=port) + /socket-binding-group=standard-sockets/socket-binding=jgroups-mping:undefine-attribute(name=port) +end-if +if (outcome == success) of /socket-binding-group=standard-sockets/socket-binding=modcluster:read-attribute(name=port) + /socket-binding-group=standard-sockets/socket-binding=modcluster:undefine-attribute(name=port) +end-if + +if (outcome == success) of /subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:read-resource + echo Changing JNDI reference in connectionsInfinispan SPI + /subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:undefine-attribute(name=properties) + /subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:write-attribute(name=properties,value={cacheContainer=java:jboss/infinispan/container/keycloak}) + echo +end-if + echo *** End Migration *** \ No newline at end of file diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone.cli b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone.cli index 5194c450c95..479fc1a9d43 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone.cli +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/migrate-standalone.cli @@ -305,7 +305,7 @@ if (result == local-query) of /subsystem=infinispan/cache-container=hibernate/:r /subsystem=infinispan/cache-container=hibernate/:undefine-attribute(name=default-cache) echo end-if - + if (outcome == failed) of /subsystem=undertow/server=default-server/host=default-host/setting=http-invoker/:read-resource echo Adding http-invoker to default-host /subsystem=undertow/server=default-server/host=default-host/setting=http-invoker/:add(security-realm=ApplicationRealm) @@ -375,4 +375,63 @@ if (outcome == failed) of /subsystem=keycloak-server/spi=hostname/:read-resource echo end-if +# Migrate from 4.3.0 to 4.4.0 +if (outcome == failed) of /subsystem=elytron/permission-set=login-permission/:read-resource + echo Adding permission-set=login-permission to elytron + /subsystem=elytron/permission-set=login-permission:add(permissions=[{class-name=org.wildfly.security.auth.permission.LoginPermission}]) + /subsystem=elytron/permission-set=default-permissions/:add(permissions=[{class-name=org.wildfly.extension.batch.jberet.deployment.BatchPermission,module=org.wildfly.extension.batch.jberet,target-name=*},{class-name=org.wildfly.transaction.client.RemoteTransactionPermission,module=org.wildfly.transaction.client},{class-name=org.jboss.ejb.client.RemoteEJBPermission,module=org.jboss.ejb-client}]) + /subsystem=elytron/simple-permission-mapper=default-permission-mapper/:undefine-attribute(name=permission-mappings) + /subsystem=elytron/simple-permission-mapper=default-permission-mapper:write-attribute(name=permission-mappings,value=[{permission-sets=[{permission-set=login-permission},{permission-set=default-permissions}],match-all=true},{permission-sets=[{permission-set=default-permissions}],principals=[anonymous]}]) + echo +end-if + +if (result == org.hibernate.infinispan) of /subsystem=infinispan/cache-container=hibernate:read-attribute(name=module) + echo Update hibernate cache module + /subsystem=infinispan/cache-container=hibernate:write-attribute(name=module, value=org.infinispan.hibernate-cache) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:read-resource + echo Removing eviction from hibernate entity cache and replacing with object-memory + /subsystem=infinispan/cache-container=hibernate/local-cache=entity/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=hibernate/local-cache=entity/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=hibernate/local-cache=local-query/eviction=EVICTION:read-resource + echo Removing eviction from hibernate local-query cache and replacing with object-memory + /subsystem=infinispan/cache-container=hibernate/local-cache=local-query/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=hibernate/local-cache=local-query/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:read-resource + echo Removing eviction from keycloak realms cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=realms/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:read-resource + echo Removing eviction from keycloak users cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=users/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:read-resource + echo Removing eviction from keycloak authorization cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=authorization/memory=object:add(size=10000) + echo +end-if +if (outcome == success) of /subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:read-resource + echo Removing eviction from keycloak keys cache and replacing with object-memory + /subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:remove + /subsystem=infinispan/cache-container=keycloak/local-cache=keys/memory=object:add(size=1000) + echo +end-if + +if (outcome == success) of /subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:read-resource + echo Changing JNDI reference in connectionsInfinispan SPI + /subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:undefine-attribute(name=properties) + /subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:write-attribute(name=properties,value={cacheContainer=java:jboss/infinispan/container/keycloak}) + echo +end-if + echo *** End Migration *** \ No newline at end of file diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml index 4388f83dfca..9d93415978a 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml @@ -31,10 +31,11 @@ - + + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml index 6ad93e959ed..4a85d38417a 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml @@ -61,6 +61,6 @@ infinispan/Keycloak org.infinispan.manager.EmbeddedCacheManager - java:jboss/infinispan/Keycloak + java:jboss/infinispan/container/keycloak diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml index 88744aca57f..88548016561 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml @@ -15,7 +15,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + @@ -32,7 +32,7 @@ - + diff --git a/distribution/server-dist/assembly.xml b/distribution/server-dist/assembly.xml index c73d5c1a3b3..0f8af6f9b2e 100755 --- a/distribution/server-dist/assembly.xml +++ b/distribution/server-dist/assembly.xml @@ -102,14 +102,6 @@ layers.conf - - target/unpacked/keycloak-client-tools - - false - - **/* - - target/licenses/content/docs docs diff --git a/distribution/server-dist/pom.xml b/distribution/server-dist/pom.xml index 6a40e72f7cf..bbb589f80de 100755 --- a/distribution/server-dist/pom.xml +++ b/distribution/server-dist/pom.xml @@ -41,17 +41,6 @@ - - org.keycloak - keycloak-client-cli-dist - zip - - - * - * - - - diff --git a/distribution/server-overlay/src/main/cli/keycloak-install-base.cli b/distribution/server-overlay/src/main/cli/keycloak-install-base.cli index 2ea58e03638..888915667ec 100644 --- a/distribution/server-overlay/src/main/cli/keycloak-install-base.cli +++ b/distribution/server-overlay/src/main/cli/keycloak-install-base.cli @@ -1,10 +1,9 @@ embed-server --server-config=standalone.xml /subsystem=datasources/data-source=KeycloakDS/:add(connection-url="jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE",enabled=true,driver-name=h2,jndi-name=java:jboss/datasources/KeycloakDS,password=sa,user-name=sa,use-java-context=true) -/subsystem=infinispan/cache-container=keycloak:add(jndi-name="infinispan/Keycloak") /subsystem=infinispan/cache-container=keycloak/local-cache=realms:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:add(max-entries=10000,strategy=LRU) +/subsystem=infinispan/cache-container=keycloak/local-cache=realms/memory=object:add(size=10000) /subsystem=infinispan/cache-container=keycloak/local-cache=users:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:add(max-entries=10000,strategy=LRU) +/subsystem=infinispan/cache-container=keycloak/local-cache=users/memory=object:add(size=10000) /subsystem=infinispan/cache-container=keycloak/local-cache=sessions:add() /subsystem=infinispan/cache-container=keycloak/local-cache=authenticationSessions:add() /subsystem=infinispan/cache-container=keycloak/local-cache=offlineSessions:add() @@ -13,11 +12,11 @@ embed-server --server-config=standalone.xml /subsystem=infinispan/cache-container=keycloak/local-cache=loginFailures:add() /subsystem=infinispan/cache-container=keycloak/local-cache=work:add() /subsystem=infinispan/cache-container=keycloak/local-cache=authorization:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:add(max-entries=100,strategy=LRU) +/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/memory=object:add(size=10000) /subsystem=infinispan/cache-container=keycloak/local-cache=keys:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:add(max-entries=1000,strategy=LRU) +/subsystem=infinispan/cache-container=keycloak/local-cache=keys/memory=object:add(size=1000) /subsystem=infinispan/cache-container=keycloak/local-cache=keys/expiration=EXPIRATION:add(max-idle=3600000) /subsystem=infinispan/cache-container=keycloak/local-cache=actionTokens:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=actionTokens/eviction=EVICTION:add(max-entries=-1,strategy=NONE) +/subsystem=infinispan/cache-container=keycloak/local-cache=actionTokens/memory=object:add(size=-1) /subsystem=infinispan/cache-container=keycloak/local-cache=actionTokens/expiration=EXPIRATION:add(max-idle=-1,interval=300000) /extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem) diff --git a/distribution/server-overlay/src/main/cli/keycloak-install-ha-base.cli b/distribution/server-overlay/src/main/cli/keycloak-install-ha-base.cli index d4b02f86329..2c5488087bb 100644 --- a/distribution/server-overlay/src/main/cli/keycloak-install-ha-base.cli +++ b/distribution/server-overlay/src/main/cli/keycloak-install-ha-base.cli @@ -1,24 +1,23 @@ embed-server --server-config=standalone-ha.xml /subsystem=datasources/data-source=KeycloakDS/:add(connection-url="jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE",enabled=true,driver-name=h2,jndi-name=java:jboss/datasources/KeycloakDS,password=sa,user-name=sa,use-java-context=true) -/subsystem=infinispan/cache-container=keycloak:add(jndi-name="infinispan/Keycloak") /subsystem=infinispan/cache-container=keycloak/transport=TRANSPORT:add(lock-timeout=60000) /subsystem=infinispan/cache-container=keycloak/local-cache=realms:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=realms/eviction=EVICTION:add(max-entries=10000,strategy=LRU) +/subsystem=infinispan/cache-container=keycloak/local-cache=realms/memory=object:add(size=10000) /subsystem=infinispan/cache-container=keycloak/local-cache=users:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:add(max-entries=10000,strategy=LRU) -/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:add(mode="SYNC",owners="1") -/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:add(mode="SYNC",owners="1") -/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:add(mode="SYNC",owners="1") -/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:add(mode="SYNC",owners="1") -/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:add(mode="SYNC",owners="1") -/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:add(mode="SYNC",owners="1") +/subsystem=infinispan/cache-container=keycloak/local-cache=users/memory=object:add(size=10000) +/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:add(owners="1") +/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:add(owners="1") +/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:add(owners="1") +/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:add(owners="1") +/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:add(owners="1") +/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:add(owners="1") /subsystem=infinispan/cache-container=keycloak/local-cache=authorization:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:add(max-entries=10000,strategy=LRU) -/subsystem=infinispan/cache-container=keycloak/replicated-cache=work:add(mode="SYNC") +/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/memory=object:add(size=10000) +/subsystem=infinispan/cache-container=keycloak/replicated-cache=work:add() /subsystem=infinispan/cache-container=keycloak/local-cache=keys:add() -/subsystem=infinispan/cache-container=keycloak/local-cache=keys/eviction=EVICTION:add(max-entries=1000,strategy=LRU) +/subsystem=infinispan/cache-container=keycloak/local-cache=keys/memory=object:add(size=1000) /subsystem=infinispan/cache-container=keycloak/local-cache=keys/expiration=EXPIRATION:add(max-idle=3600000) -/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:add(indexing="NONE",mode="SYNC",owners="2") -/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/eviction=EVICTION:add(max-entries=-1,strategy=NONE) +/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:add(indexing="NONE",owners="2") +/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/memory=object:add(size=-1) /subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/expiration=EXPIRATION:add(max-idle=-1,interval=300000) /extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem) diff --git a/distribution/server-provisioning-devel.xml b/distribution/server-provisioning-devel.xml index 4fe832c04d1..2d6af4f113c 100644 --- a/distribution/server-provisioning-devel.xml +++ b/distribution/server-provisioning-devel.xml @@ -15,9 +15,6 @@ ~ limitations under the License. --> - - - diff --git a/distribution/server-provisioning.xml b/distribution/server-provisioning.xml index 6d4c4421b68..78b5a8374ce 100644 --- a/distribution/server-provisioning.xml +++ b/distribution/server-provisioning.xml @@ -15,9 +15,6 @@ ~ limitations under the License. --> - - - diff --git a/examples/broker/twitter-authentication/pom.xml b/examples/broker/twitter-authentication/pom.xml index 6e21b7bbebf..0dfc0726c93 100755 --- a/examples/broker/twitter-authentication/pom.xml +++ b/examples/broker/twitter-authentication/pom.xml @@ -66,7 +66,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec provided diff --git a/examples/providers/domain-extension/pom.xml b/examples/providers/domain-extension/pom.xml index 6e1607774d5..07ef60bf69f 100755 --- a/examples/providers/domain-extension/pom.xml +++ b/examples/providers/domain-extension/pom.xml @@ -58,7 +58,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec diff --git a/examples/providers/rest/pom.xml b/examples/providers/rest/pom.xml index c3cc1b6998d..388a54bc433 100755 --- a/examples/providers/rest/pom.xml +++ b/examples/providers/rest/pom.xml @@ -48,7 +48,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec diff --git a/integration/admin-client/pom.xml b/integration/admin-client/pom.xml index bbfd3605b00..193975094b4 100755 --- a/integration/admin-client/pom.xml +++ b/integration/admin-client/pom.xml @@ -47,7 +47,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec provided diff --git a/integration/client-cli/admin-cli/pom.xml b/integration/client-cli/admin-cli/pom.xml index 70a6e5452f3..66aa372352b 100755 --- a/integration/client-cli/admin-cli/pom.xml +++ b/integration/client-cli/admin-cli/pom.xml @@ -145,7 +145,7 @@ - org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.0_spec + org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec **/** diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java index 4334c299150..73fbb5a9cee 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java @@ -33,6 +33,7 @@ import org.keycloak.cluster.ClusterProviderFactory; import org.keycloak.common.util.Retry; import org.keycloak.common.util.Time; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; +import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.sessions.infinispan.util.InfinispanUtil; @@ -77,7 +78,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory @Override public ClusterProvider create(KeycloakSession session) { lazyInit(session); - String myAddress = InfinispanUtil.getMyAddress(session); + String myAddress = InfinispanUtil.getTopologyInfo(session).getMyNodeName(); return new InfinispanClusterProvider(clusterStartupTime, myAddress, crossDCAwareCacheFactory, notificationsManager, localExecutor); } @@ -96,8 +97,9 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory clusterStartupTime = initClusterStartupTime(session); - String myAddress = InfinispanUtil.getMyAddress(session); - String mySite = InfinispanUtil.getMySite(session); + TopologyInfo topologyInfo = InfinispanUtil.getTopologyInfo(session); + String myAddress = topologyInfo.getMyNodeName(); + String mySite = topologyInfo.getMySiteName(); notificationsManager = InfinispanNotificationsManager.create(session, workCache, myAddress, mySite, remoteStores); } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java index c1f891442bd..f796dfb1c72 100644 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java @@ -28,14 +28,12 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection private final EmbeddedCacheManager cacheManager; private final RemoteCacheProvider remoteCacheProvider; - private final String siteName; - private final String nodeName; + private final TopologyInfo topologyInfo; - public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager, RemoteCacheProvider remoteCacheProvider, String nodeName, String siteName) { + public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager, RemoteCacheProvider remoteCacheProvider, TopologyInfo topologyInfo) { this.cacheManager = cacheManager; this.remoteCacheProvider = remoteCacheProvider; - this.nodeName = nodeName; - this.siteName = siteName; + this.topologyInfo = topologyInfo; } @Override @@ -49,13 +47,8 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection } @Override - public String getNodeName() { - return nodeName; - } - - @Override - public String getSiteName() { - return siteName; + public TopologyInfo getTopologyInfo() { + return topologyInfo; } @Override diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java index 0053791d1ea..e3dfc3626d8 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java @@ -20,6 +20,7 @@ package org.keycloak.connections.infinispan; import java.security.SecureRandom; import java.util.concurrent.TimeUnit; +import org.infinispan.client.hotrod.ProtocolVersion; import org.infinispan.commons.util.FileLookup; import org.infinispan.commons.util.FileLookupFactory; import org.infinispan.configuration.cache.CacheMode; @@ -34,7 +35,7 @@ import org.infinispan.remoting.transport.Transport; import org.infinispan.remoting.transport.jgroups.JGroupsTransport; import org.infinispan.transaction.LockingMode; import org.infinispan.transaction.TransactionMode; -import org.infinispan.transaction.lookup.DummyTransactionManagerLookup; +import org.infinispan.transaction.lookup.EmbeddedTransactionManagerLookup; import org.jboss.logging.Logger; import org.jgroups.JChannel; import org.keycloak.Config; @@ -60,15 +61,13 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon protected boolean containerManaged; - private String nodeName; - - private String siteName; + private TopologyInfo topologyInfo; @Override public InfinispanConnectionProvider create(KeycloakSession session) { lazyInit(); - return new DefaultInfinispanConnectionProvider(cacheManager, remoteCacheProvider, nodeName, siteName); + return new DefaultInfinispanConnectionProvider(cacheManager, remoteCacheProvider, topologyInfo); } @Override @@ -108,7 +107,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon initEmbedded(); } - logger.infof("Node name: %s, Site name: %s", nodeName, siteName); + logger.infof(topologyInfo.toString()); remoteCacheProvider = new RemoteCacheProvider(config, cacheManager); } @@ -121,7 +120,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager = (EmbeddedCacheManager) new InitialContext().lookup(cacheContainerLookup); containerManaged = true; - long realmRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME).getCacheConfiguration().eviction().maxEntries(); + long realmRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME).getCacheConfiguration().memory().size(); realmRevisionsMaxEntries = realmRevisionsMaxEntries > 0 ? 2 * realmRevisionsMaxEntries : InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX; @@ -129,7 +128,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(realmRevisionsMaxEntries)); cacheManager.getCache(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, true); - long userRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().eviction().maxEntries(); + long userRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().memory().size(); userRevisionsMaxEntries = userRevisionsMaxEntries > 0 ? 2 * userRevisionsMaxEntries : InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX; @@ -141,7 +140,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true); cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true); - long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries(); + long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().memory().size(); authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0 ? 2 * authzRevisionsMaxEntries : InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX; @@ -149,20 +148,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries)); cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true); - Transport transport = cacheManager.getTransport(); - if (transport != null) { - this.nodeName = transport.getAddress().toString(); - this.siteName = cacheManager.getCacheManagerConfiguration().transport().siteId(); - if (this.siteName == null) { - this.siteName = System.getProperty(InfinispanConnectionProvider.JBOSS_SITE_NAME); - } - } else { - this.nodeName = System.getProperty(InfinispanConnectionProvider.JBOSS_NODE_NAME); - this.siteName = System.getProperty(InfinispanConnectionProvider.JBOSS_SITE_NAME); - } - if (this.nodeName == null || this.nodeName.equals("localhost")) { - this.nodeName = generateNodeName(); - } + this.topologyInfo = new TopologyInfo(cacheManager, config, false); logger.debugv("Using container managed Infinispan cache container, lookup={0}", cacheContainerLookup); } catch (Exception e) { @@ -180,25 +166,13 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon boolean async = config.getBoolean("async", false); boolean allowDuplicateJMXDomains = config.getBoolean("allowDuplicateJMXDomains", true); - this.nodeName = config.get("nodeName", System.getProperty(InfinispanConnectionProvider.JBOSS_NODE_NAME)); - if (this.nodeName != null && this.nodeName.isEmpty()) { - this.nodeName = null; - } - - this.siteName = config.get("siteName", System.getProperty(InfinispanConnectionProvider.JBOSS_SITE_NAME)); - if (this.siteName != null && this.siteName.isEmpty()) { - this.siteName = null; - } + this.topologyInfo = new TopologyInfo(cacheManager, config, true); if (clustered) { String jgroupsUdpMcastAddr = config.get("jgroupsUdpMcastAddr", System.getProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR)); - configureTransport(gcb, nodeName, siteName, jgroupsUdpMcastAddr); + configureTransport(gcb, topologyInfo.getMyNodeName(), topologyInfo.getMySiteName(), jgroupsUdpMcastAddr); gcb.globalJmxStatistics() - .jmxDomain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + nodeName); - } else { - if (nodeName == null) { - nodeName = generateNodeName(); - } + .jmxDomain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + topologyInfo.getMyNodeName()); } gcb.globalJmxStatistics() @@ -208,10 +182,6 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager = new DefaultCacheManager(gcb.build()); containerManaged = false; - if (cacheManager.getTransport() != null) { - nodeName = cacheManager.getTransport().getAddress().toString(); - } - logger.debug("Started embedded Infinispan cache container"); ConfigurationBuilder modelCacheConfigBuilder = new ConfigurationBuilder(); @@ -311,7 +281,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon Configuration replicationEvictionCacheConfiguration = replicationConfigBuilder.build(); cacheManager.defineConfiguration(InfinispanConnectionProvider.WORK_CACHE_NAME, replicationEvictionCacheConfiguration); - long realmRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME).getCacheConfiguration().eviction().maxEntries(); + long realmRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME).getCacheConfiguration().memory().size(); realmRevisionsMaxEntries = realmRevisionsMaxEntries > 0 ? 2 * realmRevisionsMaxEntries : InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX; @@ -319,7 +289,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(realmRevisionsMaxEntries)); cacheManager.getCache(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, true); - long userRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().eviction().maxEntries(); + long userRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().memory().size(); userRevisionsMaxEntries = userRevisionsMaxEntries > 0 ? 2 * userRevisionsMaxEntries : InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX; @@ -340,7 +310,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager.defineConfiguration(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, actionTokenCacheConfigBuilder.build()); cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true); - long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries(); + long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().memory().size(); authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0 ? 2 * authzRevisionsMaxEntries : InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX; @@ -349,20 +319,21 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true); } - protected String generateNodeName() { - return InfinispanConnectionProvider.NODE_PREFIX + new SecureRandom().nextInt(1000000); - } private Configuration getRevisionCacheConfig(long maxEntries) { ConfigurationBuilder cb = new ConfigurationBuilder(); cb.invocationBatching().enable().transaction().transactionMode(TransactionMode.TRANSACTIONAL); - // Use Dummy manager even in managed ( wildfly/eap ) environment. We don't want infinispan to participate in global transaction - cb.transaction().transactionManagerLookup(new DummyTransactionManagerLookup()); + // Use Embedded manager even in managed ( wildfly/eap ) environment. We don't want infinispan to participate in global transaction + cb.transaction().transactionManagerLookup(new EmbeddedTransactionManagerLookup()); cb.transaction().lockingMode(LockingMode.PESSIMISTIC); - cb.eviction().strategy(EvictionStrategy.LRU).type(EvictionType.COUNT).size(maxEntries); + cb.memory() + .evictionStrategy(EvictionStrategy.REMOVE) + .evictionType(EvictionType.COUNT) + .size(maxEntries); + return cb.build(); } @@ -383,6 +354,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon .rawValues(true) .forceReturnValues(false) .marshaller(KeycloakHotRodMarshallerFactory.class.getName()) + //.protocolVersion(ProtocolVersion.PROTOCOL_VERSION_26) .addServer() .host(jdgServer) .port(jdgPort) @@ -410,6 +382,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon .rawValues(true) .forceReturnValues(false) .marshaller(KeycloakHotRodMarshallerFactory.class.getName()) + //.protocolVersion(ProtocolVersion.PROTOCOL_VERSION_26) .addServer() .host(jdgServer) .port(jdgPort) @@ -420,7 +393,12 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon protected Configuration getKeysCacheConfig() { ConfigurationBuilder cb = new ConfigurationBuilder(); - cb.eviction().strategy(EvictionStrategy.LRU).type(EvictionType.COUNT).size(InfinispanConnectionProvider.KEYS_CACHE_DEFAULT_MAX); + + cb.memory() + .evictionStrategy(EvictionStrategy.REMOVE) + .evictionType(EvictionType.COUNT) + .size(InfinispanConnectionProvider.KEYS_CACHE_DEFAULT_MAX); + cb.expiration().maxIdle(InfinispanConnectionProvider.KEYS_CACHE_MAX_IDLE_SECONDS, TimeUnit.SECONDS); return cb.build(); } @@ -428,9 +406,9 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon private ConfigurationBuilder getActionTokenCacheConfig() { ConfigurationBuilder cb = new ConfigurationBuilder(); - cb.eviction() - .strategy(EvictionStrategy.NONE) - .type(EvictionType.COUNT) + cb.memory() + .evictionStrategy(EvictionStrategy.NONE) + .evictionType(EvictionType.COUNT) .size(InfinispanConnectionProvider.ACTION_TOKEN_CACHE_DEFAULT_MAX); cb.expiration() .maxIdle(InfinispanConnectionProvider.ACTION_TOKEN_MAX_IDLE_SECONDS, TimeUnit.SECONDS) diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java index cb23b6fd9f2..03e51d0031f 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java @@ -75,14 +75,8 @@ public interface InfinispanConnectionProvider extends Provider { RemoteCache getRemoteCache(String name); /** - * @return Address of current node in cluster. In non-cluster environment, it returns some other non-null value (eg. hostname with some random value like "host-123456" ) + * @return Information about cluster topology */ - String getNodeName(); - - /** - * - * @return siteName or null if we're not in environment with multiple sites (data centers) - */ - String getSiteName(); + TopologyInfo getTopologyInfo(); } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java new file mode 100644 index 00000000000..25a6ad1afde --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java @@ -0,0 +1,202 @@ +/* + * Copyright 2017 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.connections.infinispan; + +import java.net.InetSocketAddress; +import java.security.SecureRandom; +import java.util.Objects; +import java.util.Optional; + +import org.infinispan.Cache; +import org.infinispan.distribution.DistributionManager; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.remoting.transport.Address; +import org.infinispan.remoting.transport.LocalModeAddress; +import org.infinispan.remoting.transport.Transport; +import org.infinispan.remoting.transport.jgroups.JGroupsAddress; +import org.infinispan.remoting.transport.jgroups.JGroupsTransport; +import org.jboss.logging.Logger; +import org.jgroups.Event; +import org.jgroups.JChannel; +import org.jgroups.stack.IpAddress; +import org.jgroups.util.NameCache; +import org.keycloak.Config; + +/** + * @author Marek Posolda + */ +public class TopologyInfo { + + private static final Logger logger = Logger.getLogger(TopologyInfo.class); + + + // Node name used in clustered environment. This typically points to "jboss.node.name" . If "jboss.node.name" is not set, it is randomly generated + // name + private final String myNodeName; + + // Used just if "site" is configured (typically in cross-dc environment). Otherwise null + private final String mySiteName; + + private final boolean isGeneratedNodeName; + + + public TopologyInfo(EmbeddedCacheManager cacheManager, Config.Scope config, boolean embedded) { + String siteName; + String nodeName; + boolean isGeneratedNodeName = false; + + if (!embedded) { + Transport transport = cacheManager.getTransport(); + if (transport != null) { + nodeName = transport.getAddress().toString(); + siteName = cacheManager.getCacheManagerConfiguration().transport().siteId(); + if (siteName == null) { + siteName = System.getProperty(InfinispanConnectionProvider.JBOSS_SITE_NAME); + } + } else { + nodeName = System.getProperty(InfinispanConnectionProvider.JBOSS_NODE_NAME); + siteName = System.getProperty(InfinispanConnectionProvider.JBOSS_SITE_NAME); + } + if (nodeName == null || nodeName.equals("localhost")) { + isGeneratedNodeName = true; + nodeName = generateNodeName(); + } + } else { + boolean clustered = config.getBoolean("clustered", false); + + nodeName = config.get("nodeName", System.getProperty(InfinispanConnectionProvider.JBOSS_NODE_NAME)); + if (nodeName != null && nodeName.isEmpty()) { + nodeName = null; + } + + siteName = config.get("siteName", System.getProperty(InfinispanConnectionProvider.JBOSS_SITE_NAME)); + if (siteName != null && siteName.isEmpty()) { + siteName = null; + } + + if (nodeName == null) { + if (!clustered) { + isGeneratedNodeName = true; + nodeName = generateNodeName(); + } else { + throw new IllegalStateException("You must set jboss.node.name if you use clustered mode for InfinispanConnectionProvider"); + } + } + } + + this.myNodeName = nodeName; + this.mySiteName = siteName; + this.isGeneratedNodeName = isGeneratedNodeName; + } + + + private String generateNodeName() { + return InfinispanConnectionProvider.NODE_PREFIX + new SecureRandom().nextInt(1000000); + } + + + public String getMyNodeName() { + return myNodeName; + } + + public String getMySiteName() { + return mySiteName; + } + + + @Override + public String toString() { + return String.format("Node name: %s, Site name: %s", myNodeName, mySiteName); + } + + + /** + * True if I am primary owner of the key in case of distributed caches. In case of local caches, always return true + */ + public boolean amIOwner(Cache cache, Object key) { + Address myAddress = cache.getCacheManager().getAddress(); + Address objectOwnerAddress = getOwnerAddress(cache, key); + + // NOTE: For scattered caches, this will always return true, which may not be correct. Need to review this if we add support for scattered caches + return Objects.equals(myAddress, objectOwnerAddress); + } + + + /** + * Get route to be used as the identifier for sticky session. Return null if I am not able to find the appropriate route (or in case of local mode) + */ + public String getRouteName(Cache cache, Object key) { + if (cache.getCacheConfiguration().clustering().cacheMode().isClustered() && isGeneratedNodeName) { + logger.warn("Clustered configuration used, but node name is not properly set. Make sure to start server with jboss.node.name property identifying cluster node"); + } + + if (isGeneratedNodeName) { + return null; + } + + // Impl based on Wildfly sticky session algorithm for generating routes ( org.wildfly.clustering.web.infinispan.session.InfinispanRouteLocator ) + Address address = getOwnerAddress(cache, key); + + // Local mode + if (address == null || (address == LocalModeAddress.INSTANCE)) { + return myNodeName; + } + + org.jgroups.Address jgroupsAddress = toJGroupsAddress(address); + String name = NameCache.get(jgroupsAddress); + + // If no logical name exists, create one using physical address + if (name == null) { + + Transport transport = cache.getCacheManager().getTransport(); + JChannel jgroupsChannel = ((JGroupsTransport) transport).getChannel(); + + IpAddress ipAddress = (IpAddress) jgroupsChannel.down(new Event(Event.GET_PHYSICAL_ADDRESS, jgroupsAddress)); + // Physical address might be null if node is no longer a member of the cluster + InetSocketAddress socketAddress = (ipAddress != null) ? new InetSocketAddress(ipAddress.getIpAddress(), ipAddress.getPort()) : new InetSocketAddress(0); + name = String.format("%s:%s", socketAddress.getHostString(), socketAddress.getPort()); + + logger.debugf("Address not found in NameCache. Fallback to %s", name); + } + + return name; + } + + + private Address getOwnerAddress(Cache cache, Object key) { + DistributionManager dist = cache.getAdvancedCache().getDistributionManager(); + Address address = (dist != null) && !cache.getCacheConfiguration().clustering().cacheMode().isScattered() ? + dist.getCacheTopology().getDistribution(key).primary() : + cache.getCacheManager().getAddress(); + + return address; + } + + + // See org.wildfly.clustering.server.group.CacheGroup + private static org.jgroups.Address toJGroupsAddress(Address address) { + if ((address == null) || (address == LocalModeAddress.INSTANCE)) return null; + if (address instanceof JGroupsAddress) { + JGroupsAddress jgroupsAddress = (JGroupsAddress) address; + return jgroupsAddress.getJGroupsAddress(); + } + throw new IllegalArgumentException(address.toString()); + } + + +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java index 871525d03a9..f9086289d5d 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java @@ -22,6 +22,7 @@ import org.infinispan.distribution.DistributionManager; import org.infinispan.remoting.transport.Address; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.sessions.infinispan.util.InfinispanUtil; import org.keycloak.sessions.StickySessionEncoderProvider; /** @@ -30,12 +31,10 @@ import org.keycloak.sessions.StickySessionEncoderProvider; public class InfinispanStickySessionEncoderProvider implements StickySessionEncoderProvider { private final KeycloakSession session; - private final String myNodeName; private final boolean shouldAttachRoute; - public InfinispanStickySessionEncoderProvider(KeycloakSession session, String myNodeName, boolean shouldAttachRoute) { + public InfinispanStickySessionEncoderProvider(KeycloakSession session, boolean shouldAttachRoute) { this.session = session; - this.myNodeName = myNodeName; this.shouldAttachRoute = shouldAttachRoute; } @@ -45,9 +44,9 @@ public class InfinispanStickySessionEncoderProvider implements StickySessionEnco return sessionId; } - String nodeName = getNodeName(sessionId); - if (nodeName != null) { - return sessionId + '.' + nodeName; + String route = getRoute(sessionId); + if (route != null) { + return sessionId + '.' + route; } else { return sessionId; } @@ -71,19 +70,10 @@ public class InfinispanStickySessionEncoderProvider implements StickySessionEnco } - private String getNodeName(String sessionId) { + private String getRoute(String sessionId) { InfinispanConnectionProvider ispnProvider = session.getProvider(InfinispanConnectionProvider.class); Cache cache = ispnProvider.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME); - DistributionManager distManager = cache.getAdvancedCache().getDistributionManager(); - - if (distManager != null) { - // Sticky session to the node, who owns this authenticationSession - Address address = distManager.getPrimaryLocation(sessionId); - return address.toString(); - } else { - // Fallback to jbossNodeName if authSession cache is local - return myNodeName; - } + return InfinispanUtil.getTopologyInfo(session).getRouteName(cache, sessionId); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java index 001e295b478..5e87395e7be 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java @@ -38,15 +38,7 @@ public class InfinispanStickySessionEncoderProviderFactory implements StickySess @Override public StickySessionEncoderProvider create(KeycloakSession session) { - String myNodeName = InfinispanUtil.getMyAddress(session); - - if (myNodeName != null && myNodeName.startsWith(InfinispanConnectionProvider.NODE_PREFIX)) { - - // Node name was randomly generated. We won't use anything for sticky sessions in this case - myNodeName = null; - } - - return new InfinispanStickySessionEncoderProvider(session, myNodeName, shouldAttachRoute); + return new InfinispanStickySessionEncoderProvider(session, shouldAttachRoute); } @Override diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java index 22ef5b7976b..1e1670d11b7 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java @@ -21,7 +21,6 @@ import org.infinispan.Cache; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.context.Flag; import org.infinispan.stream.CacheCollectors; -import org.infinispan.stream.SerializableSupplier; import org.jboss.logging.Logger; import org.keycloak.cluster.ClusterProvider; import org.keycloak.common.util.Time; diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java index 9e47c415de7..15d8c254134 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java @@ -141,7 +141,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider // Count of sessions to be computed in each segment private int getSessionsPerSegment() { - return config.getInt("sessionsPerSegment", 100); + return config.getInt("sessionsPerSegment", 64); } private int getTimeoutForPreloadingSessionsSeconds() { @@ -161,7 +161,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class); Cache workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); - InfinispanCacheInitializer ispnInitializer = new InfinispanCacheInitializer(sessionFactory, workCache, new OfflinePersistentUserSessionLoader(), "offlineUserSessions", sessionsPerSegment, maxErrors); + InfinispanCacheInitializer ispnInitializer = new InfinispanCacheInitializer(sessionFactory, workCache, + new OfflinePersistentUserSessionLoader(sessionsPerSegment), "offlineUserSessions", sessionsPerSegment, maxErrors); // DB-lock to ensure that persistent sessions are loaded from DB just on one DC. The other DCs will load them from remote cache. CacheInitializer initializer = new DBLockBasedCacheInitializer(session, ispnInitializer); @@ -302,7 +303,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class); Cache workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); - InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache, new RemoteCacheSessionsLoader(cacheName), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors); + InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache, + new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors); initializer.initCache(); initializer.loadSessions(); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java index 3400782f315..fd6ebc03850 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java @@ -185,15 +185,17 @@ public class SessionEntityWrapper { if (forTransport) { final SessionEntity entity = (SessionEntity) input.readObject(); final SessionEntityWrapper res = new SessionEntityWrapper(entity); - if (log.isDebugEnabled()) { - log.debugf("Loaded entity from remote store: %s, version=%s, metadata=%s", entity, res.version, res.localMetadata); + if (log.isTraceEnabled()) { + log.tracef("Loaded entity from remote store: %s, version=%s, metadata=%s", entity, res.version, res.localMetadata); } return res; } else { UUID sessionVersion = new UUID(input.readLong(), input.readLong()); HashMap map = MarshallUtil.unmarshallMap(input, HashMap::new); final SessionEntity entity = (SessionEntity) input.readObject(); - log.debugf("Found entity locally: entity=%s, version=%s, metadata=%s", entity, sessionVersion, map); + if (log.isTraceEnabled()) { + log.tracef("Found entity locally: entity=%s, version=%s, metadata=%s", entity, sessionVersion, map); + } return new SessionEntityWrapper(sessionVersion, map, entity); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshListener.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshListener.java index 00b499e9748..a18443884c0 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshListener.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshListener.java @@ -23,6 +23,7 @@ import org.infinispan.Cache; import org.jboss.logging.Logger; import org.keycloak.cluster.ClusterEvent; import org.keycloak.cluster.ClusterListener; +import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; @@ -45,20 +46,14 @@ public class LastSessionRefreshListener implements ClusterListener { private final KeycloakSessionFactory sessionFactory; private final Cache> cache; - private final boolean distributed; - private final String myAddress; + private final TopologyInfo topologyInfo; public LastSessionRefreshListener(KeycloakSession session, Cache> cache, boolean offline) { this.sessionFactory = session.getKeycloakSessionFactory(); this.cache = cache; this.offline = offline; - this.distributed = InfinispanUtil.isDistributedCache(cache); - if (this.distributed) { - this.myAddress = InfinispanUtil.getMyAddress(session); - } else { - this.myAddress = null; - } + this.topologyInfo = InfinispanUtil.getTopologyInfo(session); } @Override @@ -81,7 +76,7 @@ public class LastSessionRefreshListener implements ClusterListener { RealmModel realm = kcSession.realms().getRealm(realmId); UserSessionModel userSession = offline ? kcSession.sessions().getOfflineUserSession(realm, sessionId) : kcSession.sessions().getUserSession(realm, sessionId); if (userSession == null) { - logger.debugf("User session '%s' not available on node '%s' offline '%b'", sessionId, myAddress, offline); + logger.debugf("User session '%s' not available on node '%s' offline '%b'", sessionId, topologyInfo.getMyNodeName(), offline); } else { // Update just if lastSessionRefresh from event is bigger than ours if (lastSessionRefresh > userSession.getLastSessionRefresh()) { @@ -101,11 +96,6 @@ public class LastSessionRefreshListener implements ClusterListener { // For distributed caches, ensure that local modification is executed just on owner protected boolean shouldUpdateLocalCache(String key) { - if (!distributed) { - return true; - } else { - String keyAddress = InfinispanUtil.getKeyPrimaryOwnerAddress(cache, key); - return myAddress.equals(keyAddress); - } + return topologyInfo.amIOwner(cache, key); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java index 5f78eda3261..c2e6c86f870 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java @@ -24,6 +24,7 @@ import java.io.ObjectOutput; import org.infinispan.commons.marshall.Externalizer; import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.commons.marshall.SerializeWith; +import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil; /** * @author Marek Posolda @@ -58,14 +59,14 @@ public class SessionData { @Override public void writeObject(ObjectOutput output, SessionData obj) throws IOException { MarshallUtil.marshallString(obj.realmId, output); - MarshallUtil.marshallInt(output, obj.lastSessionRefresh); + KeycloakMarshallUtil.marshall(obj.lastSessionRefresh, output); } @Override public SessionData readObject(ObjectInput input) throws IOException, ClassNotFoundException { String realmId = MarshallUtil.unmarshallString(input); - int lastSessionRefresh = MarshallUtil.unmarshallInt(input); + int lastSessionRefresh = KeycloakMarshallUtil.unmarshallInteger(input); return new SessionData(realmId, lastSessionRefresh); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java index 635f0e63e2b..0e2e6157f34 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java @@ -174,14 +174,14 @@ public class AuthenticatedClientSessionEntity extends SessionEntity { MarshallUtil.marshallString(session.getRealmId(), output); MarshallUtil.marshallString(session.getAuthMethod(), output); MarshallUtil.marshallString(session.getRedirectUri(), output); - MarshallUtil.marshallInt(output, session.getTimestamp()); + KeycloakMarshallUtil.marshall(session.getTimestamp(), output); MarshallUtil.marshallString(session.getAction(), output); Map notes = session.getNotes(); KeycloakMarshallUtil.writeMap(notes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output); MarshallUtil.marshallString(session.getCurrentRefreshToken(), output); - MarshallUtil.marshallInt(output, session.getCurrentRefreshTokenUseCount()); + KeycloakMarshallUtil.marshall(session.getCurrentRefreshTokenUseCount(), output); } @@ -193,7 +193,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity { sessionEntity.setAuthMethod(MarshallUtil.unmarshallString(input)); sessionEntity.setRedirectUri(MarshallUtil.unmarshallString(input)); - sessionEntity.setTimestamp(MarshallUtil.unmarshallInt(input)); + sessionEntity.setTimestamp(KeycloakMarshallUtil.unmarshallInteger(input)); sessionEntity.setAction(MarshallUtil.unmarshallString(input)); Map notes = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, @@ -201,7 +201,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity { sessionEntity.setNotes(notes); sessionEntity.setCurrentRefreshToken(MarshallUtil.unmarshallString(input)); - sessionEntity.setCurrentRefreshTokenUseCount(MarshallUtil.unmarshallInt(input)); + sessionEntity.setCurrentRefreshTokenUseCount(KeycloakMarshallUtil.unmarshallInteger(input)); return sessionEntity; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java index cf51796e185..dfaa3aa7991 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java @@ -23,7 +23,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.infinispan.util.concurrent.ConcurrentHashSet; +import org.infinispan.commons.util.concurrent.ConcurrentHashSet; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.CommonClientSessionModel.ExecutionStatus; import java.io.IOException; diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java index fafd1561b8a..40b1e1024d2 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java @@ -254,8 +254,8 @@ public class UserSessionEntity extends SessionEntity { MarshallUtil.marshallString(session.getRealmId(), output); MarshallUtil.marshallString(session.getUser(), output); - MarshallUtil.marshallInt(output, session.getLastSessionRefresh()); - MarshallUtil.marshallInt(output, session.getStarted()); + KeycloakMarshallUtil.marshall(session.getLastSessionRefresh(), output); + KeycloakMarshallUtil.marshall(session.getStarted(), output); output.writeBoolean(session.isRememberMe()); int state = session.getState() == null ? 0 : STATE_TO_ID.get(session.getState()); @@ -291,8 +291,8 @@ public class UserSessionEntity extends SessionEntity { sessionEntity.setRealmId(MarshallUtil.unmarshallString(input)); sessionEntity.setUser(MarshallUtil.unmarshallString(input)); - sessionEntity.setLastSessionRefresh(MarshallUtil.unmarshallInt(input)); - sessionEntity.setStarted(MarshallUtil.unmarshallInt(input)); + sessionEntity.setLastSessionRefresh(KeycloakMarshallUtil.unmarshallInteger(input)); + sessionEntity.setStarted(KeycloakMarshallUtil.unmarshallInteger(input)); sessionEntity.setRememberMe(input.readBoolean()); sessionEntity.setState(ID_TO_STATE.get(input.readInt())); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/AbstractUserSessionClusterListener.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/AbstractUserSessionClusterListener.java index 71d826836a5..1c83f0cf1ef 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/AbstractUserSessionClusterListener.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/AbstractUserSessionClusterListener.java @@ -21,6 +21,7 @@ import org.jboss.logging.Logger; import org.keycloak.cluster.ClusterEvent; import org.keycloak.cluster.ClusterListener; import org.keycloak.cluster.ClusterProvider; +import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.UserSessionProvider; @@ -73,8 +74,9 @@ public abstract class AbstractUserSessionClusterListener> futures = new LinkedList<>(); for (Integer segment : segments) { SessionInitializerWorker worker = new SessionInitializerWorker(); - worker.setWorkerEnvironment(segment, sessionsPerSegment, sessionLoader); + worker.setWorkerEnvironment(segment, ctx, sessionLoader); if (!distributed) { worker.setEnvironment(workCache, null); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java index 930b24e5d34..0fc9cfe2e51 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java @@ -42,33 +42,25 @@ public class InitializerState extends SessionEntity { private static final Logger log = Logger.getLogger(InitializerState.class); - private final int sessionsCount; private final int segmentsCount; private final BitSet segments; private int lowestUnfinishedSegment = 0; - public InitializerState(int sessionsCount, int sessionsPerSegment) { - this.sessionsCount = sessionsCount; + public InitializerState(int segmentsCount) { + this.segmentsCount = segmentsCount; + this.segments = new BitSet(segmentsCount); - int segmentsCountLocal = sessionsCount / sessionsPerSegment; - if (sessionsPerSegment * segmentsCountLocal < sessionsCount) { - segmentsCountLocal = segmentsCountLocal + 1; - } - this.segmentsCount = segmentsCountLocal; - this.segments = new BitSet(segmentsCountLocal); - - log.debugf("sessionsCount: %d, sessionsPerSegment: %d, segmentsCount: %d", sessionsCount, sessionsPerSegment, segmentsCountLocal); + log.debugf("segmentsCount: %d", segmentsCount); updateLowestUnfinishedSegment(); } - private InitializerState(String realmId, int sessionsCount, int segmentsCount, BitSet segments) { + private InitializerState(String realmId, int segmentsCount, BitSet segments) { super(realmId); - this.sessionsCount = sessionsCount; this.segmentsCount = segmentsCount; this.segments = segments; - log.debugf("sessionsCount: %d, segmentsCount: %d", sessionsCount, segmentsCount); + log.debugf("segmentsCount: %d", segmentsCount); updateLowestUnfinishedSegment(); } @@ -116,18 +108,15 @@ public class InitializerState extends SessionEntity { @Override public String toString() { int finished = segments.cardinality(); - int nonFinished = this.segmentsCount; + int nonFinished = segmentsCount - finished; - return "sessionsCount: " - + sessionsCount - + (", finished segments count: " + finished) + return "finished segments count: " + finished + (", non-finished segments count: " + nonFinished); } @Override public int hashCode() { int hash = 3; - hash = 97 * hash + this.sessionsCount; hash = 97 * hash + this.segmentsCount; hash = 97 * hash + Objects.hashCode(this.segments); hash = 97 * hash + this.lowestUnfinishedSegment; @@ -146,9 +135,6 @@ public class InitializerState extends SessionEntity { return false; } final InitializerState other = (InitializerState) obj; - if (this.sessionsCount != other.sessionsCount) { - return false; - } if (this.segmentsCount != other.segmentsCount) { return false; } @@ -170,7 +156,6 @@ public class InitializerState extends SessionEntity { output.writeByte(VERSION_1); MarshallUtil.marshallString(value.getRealmId(), output); - output.writeInt(value.sessionsCount); output.writeInt(value.segmentsCount); MarshallUtil.marshallByteArray(value.segments.toByteArray(), output); } @@ -189,7 +174,6 @@ public class InitializerState extends SessionEntity { return new InitializerState( MarshallUtil.unmarshallString(input), input.readInt(), - input.readInt(), BitSet.valueOf(MarshallUtil.unmarshallByteArray(input)) ); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoader.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoader.java index 7b60dcb39d5..cf62230bce7 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoader.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoader.java @@ -29,12 +29,11 @@ import org.keycloak.models.session.UserSessionPersisterProvider; import java.io.Serializable; import java.util.List; -import java.util.concurrent.TimeUnit; /** * @author Marek Posolda */ -public class OfflinePersistentUserSessionLoader implements SessionLoader, Serializable { +public class OfflinePersistentUserSessionLoader implements SessionLoader, Serializable { private static final Logger log = Logger.getLogger(OfflinePersistentUserSessionLoader.class); @@ -45,6 +44,13 @@ public class OfflinePersistentUserSessionLoader implements SessionLoader, Serial public static final String PERSISTENT_SESSIONS_LOADED_IN_CURRENT_DC = "PERSISTENT_SESSIONS_LOADED_IN_CURRENT_DC"; + private final int sessionsPerSegment; + + public OfflinePersistentUserSessionLoader(int sessionsPerSegment) { + this.sessionsPerSegment = sessionsPerSegment; + } + + @Override public void init(KeycloakSession session) { UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); @@ -60,14 +66,19 @@ public class OfflinePersistentUserSessionLoader implements SessionLoader, Serial @Override - public int getSessionsCount(KeycloakSession session) { + public OfflinePersistentUserSessionLoaderContext computeLoaderContext(KeycloakSession session) { UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); - return persister.getUserSessionsCount(true); + int sessionsCount = persister.getUserSessionsCount(true); + + return new OfflinePersistentUserSessionLoaderContext(sessionsCount, sessionsPerSegment); } @Override - public boolean loadSessions(KeycloakSession session, int first, int max) { + public boolean loadSessions(KeycloakSession session, OfflinePersistentUserSessionLoaderContext ctx, int segment) { + int first = ctx.getSessionsPerSegment() * segment; + int max = sessionsPerSegment; + if (log.isTraceEnabled()) { log.tracef("Loading sessions - first: %d, max: %d", first, max); } @@ -132,4 +143,13 @@ public class OfflinePersistentUserSessionLoader implements SessionLoader, Serial log.debugf("Persistent sessions loaded successfully!"); } + + @Override + public String toString() { + return new StringBuilder("OfflinePersistentUserSessionLoader [ ") + .append("sessionsPerSegment: ").append(sessionsPerSegment) + .append(" ]") + .toString(); + } + } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoaderContext.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoaderContext.java new file mode 100644 index 00000000000..491239b397e --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/OfflinePersistentUserSessionLoaderContext.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 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.models.sessions.infinispan.initializer; + +import java.io.Serializable; + +/** + * @author Marek Posolda + */ +public class OfflinePersistentUserSessionLoaderContext implements SessionLoader.LoaderContext, Serializable { + + private final int sessionsTotal; + private final int segmentsCount; + private final int sessionsPerSegment; + + public OfflinePersistentUserSessionLoaderContext(int sessionsTotal, int sessionsPerSegment) { + this.sessionsTotal = sessionsTotal; + this.sessionsPerSegment = sessionsPerSegment; + + int segmentsCount = sessionsTotal / sessionsPerSegment; + if (sessionsTotal % sessionsPerSegment >= 1) { + segmentsCount = segmentsCount + 1; + } + this.segmentsCount = segmentsCount; + } + + + public int getSessionsTotal() { + return sessionsTotal; + } + + @Override + public int getSegmentsCount() { + return segmentsCount; + } + + public int getSessionsPerSegment() { + return sessionsPerSegment; + } + + + @Override + public String toString() { + return new StringBuilder("OfflinePersistentUserSessionLoaderContext [ ") + .append(" sessionsTotal: ").append(sessionsTotal) + .append(", sessionsPerSegment: ").append(sessionsPerSegment) + .append(", segmentsCount: ").append(segmentsCount) + .append(" ]") + .toString(); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java index ec647afdbe0..7df94bf04bf 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java @@ -36,14 +36,14 @@ public class SessionInitializerWorker implements DistributedCallable workCache; - public void setWorkerEnvironment(int segment, int sessionsPerSegment, SessionLoader sessionLoader) { + public void setWorkerEnvironment(int segment, SessionLoader.LoaderContext ctx, SessionLoader sessionLoader) { this.segment = segment; - this.sessionsPerSegment = sessionsPerSegment; + this.ctx = ctx; this.sessionLoader = sessionLoader; } @@ -64,14 +64,11 @@ public class SessionInitializerWorker implements DistributedCallableMarek Posolda */ -public interface SessionLoader { +public interface SessionLoader extends Serializable { /** * Will be triggered just once on cluster coordinator node to perform some generic initialization tasks (Eg. update DB before starting load). @@ -35,23 +37,27 @@ public interface SessionLoader { /** - * Will be triggered just once on cluster coordinator node to count the number of sessions + * + * Will be triggered just once on cluster coordinator node to count the number of segments and other context data specific to the worker task. + * Each segment will be then later computed in one "worker" task + * + * This method could be expensive to call, so the "computed" loaderContext object is passed among workers/loaders and needs to be serializable * * @param session * @return */ - int getSessionsCount(KeycloakSession session); + LOADER_CONTEXT computeLoaderContext(KeycloakSession session); /** * Will be called on all cluster nodes to load the specified page. * * @param session - * @param first - * @param max + * @param loaderContext loaderContext object, which was already computed before + * @param segment to be computed * @return */ - boolean loadSessions(KeycloakSession session, int first, int max); + boolean loadSessions(KeycloakSession session, LOADER_CONTEXT loaderContext, int segment); /** @@ -69,4 +75,15 @@ public interface SessionLoader { * @param initializer */ void afterAllSessionsLoaded(BaseCacheInitializer initializer); + + + /** + * Object, which contains some context data to be used by SessionLoader implementation. It's computed just once and then passed + * to each {@link SessionLoader}. It needs to be {@link Serializable} + */ + interface LoaderContext extends Serializable { + + int getSegmentsCount(); + + } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SingleWorkerCacheInitializer.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SingleWorkerCacheInitializer.java deleted file mode 100644 index a60b4b9ac31..00000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SingleWorkerCacheInitializer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2016 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.models.sessions.infinispan.initializer; - -import java.io.Serializable; - -import org.infinispan.Cache; -import org.keycloak.models.KeycloakSession; - -/** - * This impl is able to run the non-paginatable loader task and hence will be executed just on single node. - * - * @author Marek Posolda - */ -public class SingleWorkerCacheInitializer extends BaseCacheInitializer { - - private final KeycloakSession session; - - public SingleWorkerCacheInitializer(KeycloakSession session, Cache workCache, SessionLoader sessionLoader, String stateKeySuffix) { - super(session.getKeycloakSessionFactory(), workCache, sessionLoader, stateKeySuffix, Integer.MAX_VALUE); - this.session = session; - } - - @Override - protected void startLoading() { - InitializerState state = getOrCreateInitializerState(); - while (!state.isFinished()) { - sessionLoader.loadSessions(session, -1, -1); - state.markSegmentFinished(0); - saveStateToCache(state); - } - - // Loader callback after the task is finished - this.sessionLoader.afterAllSessionsLoaded(this); - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheInvoker.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheInvoker.java index 15c9e4f06b5..6dcfb703c5e 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheInvoker.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheInvoker.java @@ -29,6 +29,7 @@ import org.infinispan.client.hotrod.Flag; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.VersionedValue; import org.jboss.logging.Logger; +import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; @@ -83,10 +84,12 @@ public class RemoteCacheInvoker { logger.tracef("Running task '%s' on remote cache '%s' . Key is '%s'", operation, cacheName, key); } + TopologyInfo topology = InfinispanUtil.getTopologyInfo(kcSession); + Retry.executeWithBackoff((int iteration) -> { try { - runOnRemoteCache(context.remoteCache, maxIdleTimeMs, key, task, sessionWrapper); + runOnRemoteCache(topology, context.remoteCache, maxIdleTimeMs, key, task, sessionWrapper); } catch (HotRodClientException re) { if (logger.isDebugEnabled()) { logger.debugf(re, "Failed running task '%s' on remote cache '%s' . Key: '%s', iteration '%s'. Will try to retry the task", @@ -101,7 +104,7 @@ public class RemoteCacheInvoker { } - private void runOnRemoteCache(RemoteCache> remoteCache, long maxIdleMs, K key, SessionUpdateTask task, SessionEntityWrapper sessionWrapper) { + private void runOnRemoteCache(TopologyInfo topology, RemoteCache> remoteCache, long maxIdleMs, K key, SessionUpdateTask task, SessionEntityWrapper sessionWrapper) { final V session = sessionWrapper.getEntity(); SessionUpdateTask.CacheOperation operation = task.getOperation(session); @@ -119,11 +122,11 @@ public class RemoteCacheInvoker { if (existing != null) { logger.debugf("Existing entity in remote cache for key: %s . Will update it", key); - replace(remoteCache, task.getLifespanMs(), maxIdleMs, key, task); + replace(topology, remoteCache, task.getLifespanMs(), maxIdleMs, key, task); } break; case REPLACE: - replace(remoteCache, task.getLifespanMs(), maxIdleMs, key, task); + replace(topology, remoteCache, task.getLifespanMs(), maxIdleMs, key, task); break; default: throw new IllegalStateException("Unsupported state " + operation); @@ -131,14 +134,13 @@ public class RemoteCacheInvoker { } - private void replace(RemoteCache> remoteCache, long lifespanMs, long maxIdleMs, K key, SessionUpdateTask task) { + private void replace(TopologyInfo topology, RemoteCache> remoteCache, long lifespanMs, long maxIdleMs, K key, SessionUpdateTask task) { boolean replaced = false; - int iteration = 0; + int replaceIteration = 0; + while (!replaced && replaceIteration < InfinispanUtil.MAXIMUM_REPLACE_RETRIES) { + replaceIteration++; - while (!replaced && iteration < InfinispanUtil.MAXIMUM_REPLACE_RETRIES) { - iteration++; - - VersionedValue> versioned = remoteCache.getVersioned(key); + VersionedValue> versioned = remoteCache.getWithMetadata(key); if (versioned == null) { logger.warnf("Not found entity to replace for key '%s'", key); return; @@ -151,16 +153,17 @@ public class RemoteCacheInvoker { task.runUpdate(session); if (logger.isTraceEnabled()) { - logger.tracef("Before replaceWithVersion. Entity to write version %d: %s", versioned.getVersion(), session); + logger.tracef("%s: Before replaceWithVersion. Entity to write version %d: %s", logTopologyData(topology, replaceIteration), + versioned.getVersion(), session); } replaced = remoteCache.replaceWithVersion(key, SessionEntityWrapper.forTransport(session), versioned.getVersion(), lifespanMs, TimeUnit.MILLISECONDS, maxIdleMs, TimeUnit.MILLISECONDS); if (!replaced) { - logger.debugf("Failed to replace entity '%s' version %d. Will retry again", key, versioned.getVersion()); + logger.debugf("%s: Failed to replace entity '%s' version %d. Will retry again", logTopologyData(topology, replaceIteration), key, versioned.getVersion()); } else { if (logger.isTraceEnabled()) { - logger.tracef("Replaced entity version %d in remote cache: %s", versioned.getVersion(), session); + logger.tracef("%s: Replaced entity version %d in remote cache: %s", logTopologyData(topology, replaceIteration), versioned.getVersion(), session); } } } @@ -171,6 +174,11 @@ public class RemoteCacheInvoker { } + private String logTopologyData(TopologyInfo topology, int iteration) { + return topology.toString() + ", replaceIteration: " + iteration; + } + + private class RemoteCacheContext { private final RemoteCache remoteCache; diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionListener.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionListener.java index 1639c785993..477a01ed457 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionListener.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionListener.java @@ -29,6 +29,7 @@ import org.infinispan.client.hotrod.event.ClientCacheEntryRemovedEvent; import org.infinispan.client.hotrod.event.ClientEvent; import org.infinispan.context.Flag; import org.jboss.logging.Logger; +import org.keycloak.connections.infinispan.TopologyInfo; import org.keycloak.executors.ExecutorsProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; @@ -46,10 +47,11 @@ public class RemoteCacheSessionListener { protected static final Logger logger = Logger.getLogger(RemoteCacheSessionListener.class); + private static final int MAXIMUM_REPLACE_RETRIES = 10; + private Cache> cache; private RemoteCache> remoteCache; - private boolean distributed; - private String myAddress; + private TopologyInfo topologyInfo; private ClientListenerExecutorDecorator executor; @@ -61,12 +63,7 @@ public class RemoteCacheSessionListener { this.cache = cache; this.remoteCache = remoteCache; - this.distributed = InfinispanUtil.isDistributedCache(cache); - if (this.distributed) { - this.myAddress = InfinispanUtil.getMyAddress(session); - } else { - this.myAddress = null; - } + this.topologyInfo = InfinispanUtil.getTopologyInfo(session); ExecutorService executor = session.getProvider(ExecutorsProvider.class).getExecutor("client-listener-" + cache.getName()); this.executor = new ClientListenerExecutorDecorator<>(executor); @@ -80,8 +77,10 @@ public class RemoteCacheSessionListener { if (shouldUpdateLocalCache(event.getType(), key, event.isCommandRetried())) { this.executor.submit(event, () -> { - // Should load it from remoteStore - cache.get(key); + // Doesn't work due https://issues.jboss.org/browse/ISPN-9323. Needs to explicitly retrieve and create it + //cache.get(key); + + createRemoteEntityInCache(key, event.getVersion()); }); } @@ -102,9 +101,30 @@ public class RemoteCacheSessionListener { } } - private static final int MAXIMUM_REPLACE_RETRIES = 10; - private void replaceRemoteEntityInCache(K key, long eventVersion) { + protected void createRemoteEntityInCache(K key, long eventVersion) { + VersionedValue> remoteSessionVersioned = remoteCache.getWithMetadata(key); + + // Maybe can happen under some circumstances that remoteCache doesn't yet contain the value sent in the event (maybe just theoretically...) + if (remoteSessionVersioned == null || remoteSessionVersioned.getValue() == null) { + logger.debugf("Entity '%s' not present in remoteCache. Ignoring create", + key.toString()); + return; + } + + + V remoteSession = remoteSessionVersioned.getValue().getEntity(); + SessionEntityWrapper newWrapper = new SessionEntityWrapper<>(remoteSession); + + logger.debugf("Read session entity wrapper from the remote cache: %s", remoteSession.toString()); + + // Using putIfAbsent. Theoretic possibility that entity was already put to cache by someone else + cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD, Flag.IGNORE_RETURN_VALUES) + .putIfAbsent(key, newWrapper); + } + + + protected void replaceRemoteEntityInCache(K key, long eventVersion) { // TODO can be optimized and remoteSession sent in the event itself? boolean replaced = false; int replaceRetries = 0; @@ -113,7 +133,7 @@ public class RemoteCacheSessionListener { replaceRetries++; SessionEntityWrapper localEntityWrapper = cache.get(key); - VersionedValue> remoteSessionVersioned = remoteCache.getVersioned(key); + VersionedValue> remoteSessionVersioned = remoteCache.getWithMetadata(key); // Probably already removed if (remoteSessionVersioned == null || remoteSessionVersioned.getValue() == null) { @@ -177,11 +197,10 @@ public class RemoteCacheSessionListener { return false; } - if (!distributed || commandRetried) { + if (commandRetried) { result = true; } else { - String keyAddress = InfinispanUtil.getKeyPrimaryOwnerAddress(cache, key); - result = myAddress.equals(keyAddress); + result = topologyInfo.amIOwner(cache, key); } logger.debugf("Received event from remote store. Event '%s', key '%s', skip '%b'", type.toString(), key, !result); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java index 53b294c523f..0ff1a901c22 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java @@ -19,127 +19,138 @@ package org.keycloak.models.sessions.infinispan.remotestore; import java.io.Serializable; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.infinispan.Cache; import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.client.hotrod.impl.RemoteCacheImpl; +import org.infinispan.client.hotrod.impl.operations.IterationStartOperation; +import org.infinispan.client.hotrod.impl.operations.IterationStartResponse; +import org.infinispan.client.hotrod.impl.operations.OperationsFactory; import org.infinispan.commons.marshall.Marshaller; +import org.infinispan.commons.util.CloseableIterator; import org.infinispan.context.Flag; import org.jboss.logging.Logger; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.RemoteCacheProvider; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.initializer.BaseCacheInitializer; import org.keycloak.models.sessions.infinispan.initializer.OfflinePersistentUserSessionLoader; import org.keycloak.models.sessions.infinispan.initializer.SessionLoader; +import static org.infinispan.client.hotrod.impl.Util.await; + /** * @author Marek Posolda */ -public class RemoteCacheSessionsLoader implements SessionLoader { +public class RemoteCacheSessionsLoader implements SessionLoader, Serializable { private static final Logger log = Logger.getLogger(RemoteCacheSessionsLoader.class); - - // Javascript to be executed on remote infinispan server. - // Flag CACHE_MODE_LOCAL is optimization used just when remoteCache is replicated as all the entries are available locally. For distributed caches, it can't be used - private static final String REMOTE_SCRIPT_FOR_LOAD_SESSIONS = - "function loadSessions() {" + - " var flagClazz = cache.getClass().getClassLoader().loadClass(\"org.infinispan.context.Flag\"); \n" + - " var localFlag = java.lang.Enum.valueOf(flagClazz, \"CACHE_MODE_LOCAL\"); \n" + - " var cacheMode = cache.getCacheConfiguration().clustering().cacheMode(); \n" + - " var canUseLocalFlag = !cacheMode.isClustered() || cacheMode.isReplicated(); \n" + - - " var cacheStream; \n" + - " if (canUseLocalFlag) { \n" + - " cacheStream = cache.getAdvancedCache().withFlags([ localFlag ]).entrySet().stream();\n" + - " } else { \n" + - " cacheStream = cache.getAdvancedCache().withFlags([ ]).entrySet().stream();\n" + - " }; \n" + - - " var result = cacheStream.skip(first).limit(max).collect(java.util.stream.Collectors.toMap(\n" + - " new java.util.function.Function() {\n" + - " apply: function(entry) {\n" + - " return entry.getKey();\n" + - " }\n" + - " },\n" + - " new java.util.function.Function() {\n" + - " apply: function(entry) {\n" + - " return entry.getValue();\n" + - " }\n" + - " }\n" + - " ));\n" + - "\n" + - " cacheStream.close();\n" + - " return result;\n" + - "};\n" + - "\n" + - "loadSessions();"; - - - private final String cacheName; + private final int sessionsPerSegment; - public RemoteCacheSessionsLoader(String cacheName) { + public RemoteCacheSessionsLoader(String cacheName, int sessionsPerSegment) { this.cacheName = cacheName; + this.sessionsPerSegment = sessionsPerSegment; } + @Override public void init(KeycloakSession session) { + } + + + @Override + public RemoteCacheSessionsLoaderContext computeLoaderContext(KeycloakSession session) { RemoteCache remoteCache = getRemoteCache(session); + int sessionsTotal = remoteCache.size(); + int ispnSegments = getIspnSegmentsCount(remoteCache); - RemoteCache scriptCache = remoteCache.getRemoteCacheManager().getCache(RemoteCacheProvider.SCRIPT_CACHE_NAME); + return new RemoteCacheSessionsLoaderContext(ispnSegments, sessionsPerSegment, sessionsTotal); - if (!scriptCache.containsKey("load-sessions.js")) { - scriptCache.put("load-sessions.js", - "// mode=local,language=javascript\n" + - REMOTE_SCRIPT_FOR_LOAD_SESSIONS); + } + + + protected int getIspnSegmentsCount(RemoteCache remoteCache) { + OperationsFactory operationsFactory = ((RemoteCacheImpl) remoteCache).getOperationsFactory(); + + // Same like RemoteCloseableIterator.startInternal + IterationStartOperation iterationStartOperation = operationsFactory.newIterationStartOperation(null, null, null, sessionsPerSegment, false); + IterationStartResponse startResponse = await(iterationStartOperation.execute()); + + try { + // Could happen for non-clustered caches + if (startResponse.getSegmentConsistentHash() == null) { + return -1; + } else { + return startResponse.getSegmentConsistentHash().getNumSegments(); + } + } finally { + startResponse.getChannel().close(); } } - @Override - public int getSessionsCount(KeycloakSession session) { - RemoteCache remoteCache = getRemoteCache(session); - return remoteCache.size(); - } @Override - public boolean loadSessions(KeycloakSession session, int first, int max) { + public boolean loadSessions(KeycloakSession session, RemoteCacheSessionsLoaderContext context, int segment) { Cache cache = getCache(session); Cache decoratedCache = cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD, Flag.SKIP_CACHE_STORE, Flag.IGNORE_RETURN_VALUES); + RemoteCache remoteCache = getRemoteCache(session); - RemoteCache remoteCache = getRemoteCache(session); + Set myIspnSegments = getMyIspnSegments(segment, context); - log.debugf("Will do bulk load of sessions from remote cache '%s' . First: %d, max: %d", cache.getName(), first, max); + log.debugf("Will do bulk load of sessions from remote cache '%s' . Segment: %d", cache.getName(), segment); - Map remoteParams = new HashMap<>(); - remoteParams.put("first", first); - remoteParams.put("max", max); - Map remoteObjects = remoteCache.execute("load-sessions.js", remoteParams); - - log.debugf("Successfully finished loading sessions '%s' . First: %d, max: %d", cache.getName(), first, max); - - Marshaller marshaller = remoteCache.getRemoteCacheManager().getMarshaller(); - - for (Map.Entry entry : remoteObjects.entrySet()) { - try { - Object key = marshaller.objectFromByteBuffer(entry.getKey()); - SessionEntityWrapper entityWrapper = (SessionEntityWrapper) marshaller.objectFromByteBuffer(entry.getValue()); - - decoratedCache.putAsync(key, entityWrapper); - } catch (Exception e) { - log.warn("Error loading session from remote cache", e); + CloseableIterator iterator = null; + int countLoaded = 0; + try { + iterator = remoteCache.retrieveEntries(null, myIspnSegments, context.getSessionsPerSegment()); + while (iterator.hasNext()) { + countLoaded++; + Map.Entry entry = iterator.next(); + decoratedCache.putAsync(entry.getKey(), entry.getValue()); + } + } catch (RuntimeException e) { + log.warnf(e, "Error loading sessions from remote cache '%s' for segment '%d'", remoteCache.getName(), segment); + throw e; + } finally { + if (iterator != null) { + iterator.close(); } } + log.debugf("Successfully finished loading sessions from cache '%s' . Segment: %d, Count of sessions loaded: %d", cache.getName(), segment, countLoaded); + return true; } - private Cache getCache(KeycloakSession session) { - InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class); - return ispn.getCache(cacheName); + // Compute set of ISPN segments into 1 "worker" segment + protected Set getMyIspnSegments(int segment, RemoteCacheSessionsLoaderContext ctx) { + // Remote cache is non-clustered + if (ctx.getIspnSegmentsCount() < 0) { + return null; + } + + if (ctx.getIspnSegmentsCount() % ctx.getSegmentsCount() > 0) { + throw new IllegalStateException("Illegal state. IspnSegmentsCount: " + ctx.getIspnSegmentsCount() + ", segmentsCount: " + ctx.getSegmentsCount()); + } + + int countPerSegment = ctx.getIspnSegmentsCount() / ctx.getSegmentsCount(); + int first = segment * countPerSegment; + int last = first + countPerSegment - 1; + + Set myIspnSegments = new HashSet<>(); + for (int i=first ; i<=last ; i++) { + myIspnSegments.add(i); + } + return myIspnSegments; + } @@ -165,12 +176,28 @@ public class RemoteCacheSessionsLoader implements SessionLoader { @Override public void afterAllSessionsLoaded(BaseCacheInitializer initializer) { - } + + protected Cache getCache(KeycloakSession session) { + InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class); + return ispn.getCache(cacheName); + } + + // Get remoteCache, which may be secured - private RemoteCache getRemoteCache(KeycloakSession session) { + protected RemoteCache getRemoteCache(KeycloakSession session) { InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class); return ispn.getRemoteCache(cacheName); } + + + @Override + public String toString() { + return new StringBuilder("RemoteCacheSessionsLoader [ ") + .append("cacheName: ").append(cacheName) + .append(", sessionsPerSegment: ").append(sessionsPerSegment) + .append(" ]") + .toString(); + } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoaderContext.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoaderContext.java new file mode 100644 index 00000000000..ec74871b14c --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoaderContext.java @@ -0,0 +1,99 @@ +/* + * Copyright 2017 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.models.sessions.infinispan.remotestore; + +import java.io.Serializable; + +import org.keycloak.models.sessions.infinispan.initializer.SessionLoader; + +/** + * + * @author Marek Posolda + */ +public class RemoteCacheSessionsLoaderContext implements SessionLoader.LoaderContext, Serializable { + + // Count of hash segments for remote infinispan cache. It's by default 256 for distributed/replicated caches + private final int ispnSegmentsCount; + + // Count of segments (worker iterations for distributedExecutionService executions on KC side). Each segment will be 1 worker iteration. + // Count of segments could be lower than "ispnSegmentsCount" and depends on the size of the cache. For example if we have cache with just 500 items, + // we don't need 256 segments and send 256 requests to remoteCache to preload thing. Instead, we will have lower number of segments (EG. 8) + // and we will map more ispnSegments into 1 worker segment (In this case 256 / 8 = 32. So 32 ISPN segments mapped to each worker segment) + private final int segmentsCount; + + private final int sessionsPerSegment; + private final int sessionsTotal; + + + public RemoteCacheSessionsLoaderContext(int ispnSegmentsCount, int sessionsPerSegment, int sessionsTotal) { + this.ispnSegmentsCount = ispnSegmentsCount; + this.sessionsPerSegment = sessionsPerSegment; + this.sessionsTotal = sessionsTotal; + this.segmentsCount = computeSegmentsCount(sessionsTotal, sessionsPerSegment, ispnSegmentsCount); + } + + + private int computeSegmentsCount(int sessionsTotal, int sessionsPerSegment, int ispnSegments) { + // No support by remote ISPN cache for segments. This can happen if remoteCache is local (non-clustered) + if (ispnSegments < 0) { + return 1; + } + + int seg = sessionsTotal / sessionsPerSegment; + if (sessionsTotal % sessionsPerSegment > 0) { + seg = seg + 1; + } + + int seg2 = 1; + while (seg2 implements MarshallUtil.MapBuilder> { @Override diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGCachePutTest.java similarity index 93% rename from model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheTest.java rename to model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGCachePutTest.java index 95133f5a0e0..bd8efd07cc5 100644 --- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheTest.java +++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGCachePutTest.java @@ -44,7 +44,7 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider; * * @author Marek Posolda */ -public class ConcurrencyJDGRemoteCacheTest { +public class ConcurrencyJDGCachePutTest { private static Map state = new HashMap<>(); @@ -54,7 +54,7 @@ public class ConcurrencyJDGRemoteCacheTest { public static void main(String[] args) throws Exception { // Init map somehow - for (int i=0 ; i<3000 ; i++) { + for (int i=0 ; i<1000 ; i++) { String key = "key-" + i; state.put(key, new EntryInfo()); } @@ -74,12 +74,24 @@ public class ConcurrencyJDGRemoteCacheTest { long took = System.currentTimeMillis() - start; + Map failedState = new HashMap<>(); + // Output for (Map.Entry entry : state.entrySet()) { System.out.println(entry.getKey() + ":::" + entry.getValue()); + + if (entry.getValue().th1.get() != entry.getValue().th2.get()) { + failedState.put(entry.getKey(), entry.getValue()); + } + worker1.cache.remove(entry.getKey()); } + System.out.println("\nFAILED ENTRIES. SIZE: " + failedState.size() + "\n"); + for (Map.Entry entry : failedState.entrySet()) { + System.out.println(entry.getKey() + ":::" + entry.getValue()); + } + System.out.println("Took: " + took + " ms"); // Finish JVM diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGCacheReplaceTest.java similarity index 97% rename from model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java rename to model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGCacheReplaceTest.java index 7cf38adda68..e086fdfc0b7 100644 --- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java +++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGCacheReplaceTest.java @@ -51,9 +51,9 @@ import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationB * * @author Marek Posolda */ -public class ConcurrencyJDGSessionsCacheTest { +public class ConcurrencyJDGCacheReplaceTest { - protected static final Logger logger = Logger.getLogger(ConcurrencyJDGSessionsCacheTest.class); + protected static final Logger logger = Logger.getLogger(ConcurrencyJDGCacheReplaceTest.class); private static final int ITERATION_PER_WORKER = 1000; @@ -152,6 +152,8 @@ public class ConcurrencyJDGSessionsCacheTest { InfinispanUtil.getRemoteCache(cache2).replace("123", session); // Create caches, listeners and finally worker threads + remoteCache1 = InfinispanUtil.getRemoteCache(cache1); + remoteCache2 = InfinispanUtil.getRemoteCache(cache2); Thread worker1 = createWorker(cache1, 1); Thread worker2 = createWorker(cache2, 2); @@ -256,7 +258,7 @@ public class ConcurrencyJDGSessionsCacheTest { executor.submit(() -> { // TODO: can be optimized - object sent in the event - VersionedValue versionedVal = remoteCache.getVersioned(cacheKey); + VersionedValue versionedVal = remoteCache.getWithMetadata(cacheKey); for (int i = 0; i < 10; i++) { if (versionedVal.getVersion() < event.getVersion()) { @@ -267,7 +269,7 @@ public class ConcurrencyJDGSessionsCacheTest { throw new RuntimeException(ie); } - versionedVal = remoteCache.getVersioned(cacheKey); + versionedVal = remoteCache.getWithMetadata(cacheKey); } else { break; } @@ -316,7 +318,7 @@ public class ConcurrencyJDGSessionsCacheTest { ReplaceStatus replaced = ReplaceStatus.NOT_REPLACED; while (replaced != ReplaceStatus.REPLACED) { - VersionedValue versioned = remoteCache.getVersioned("123"); + VersionedValue versioned = remoteCache.getWithMetadata("123"); UserSessionEntity oldSession = versioned.getValue(); //UserSessionEntity clone = DistributedCacheConcurrentWritesTest.cloneSession(oldSession); UserSessionEntity clone = oldSession; @@ -340,7 +342,7 @@ public class ConcurrencyJDGSessionsCacheTest { // Try to see if remoteCache on 2nd DC is immediatelly seeing our change RemoteCache secondDCRemoteCache = myThreadId == 1 ? remoteCache2 : remoteCache1; - UserSessionEntity thatSession = (UserSessionEntity) secondDCRemoteCache.get("123"); + //UserSessionEntity thatSession = (UserSessionEntity) secondDCRemoteCache.get("123"); //Assert.assertEquals("someVal", thatSession.getNotes().get(noteKey)); //System.out.println("Passed"); diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheClientListenersTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheClientListenersTest.java index 80894a7e8f7..b662578b207 100644 --- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheClientListenersTest.java +++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoteCacheClientListenersTest.java @@ -19,6 +19,8 @@ package org.keycloak.cluster.infinispan; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import org.infinispan.Cache; @@ -41,7 +43,7 @@ import org.keycloak.models.sessions.infinispan.util.InfinispanUtil; * Test that hotrod ClientListeners are correctly executed as expected * * STEPS TO REPRODUCE: - * - Unzip infinispan-server-8.2.6.Final to some locations ISPN1 and ISPN2 + * - Unzip infinispan-server-9.2.4.Final to some locations ISPN1 and ISPN2 * * - Edit both ISPN1/standalone/configuration/clustered.xml and ISPN2/standalone/configuration/clustered.xml . Configure cache in container "clustered" * @@ -55,7 +57,7 @@ import org.keycloak.models.sessions.infinispan.util.InfinispanUtil; ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true -Djboss.socket.binding.port-offset=1010 -Djboss.default.multicast.address=234.56.78.99 -Djboss.node.name=cache-server - Run server2 - ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true -Djboss.socket.binding.port-offset=2010 -Djboss.default.multicast.address=234.56.78.99 -Djboss.node.name=cache-server-dc-2 + ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true -Djboss.socket.binding.port-offset=2010 -Djboss.default.multicast.address=234.56.78.100 -Djboss.node.name=cache-server-dc-2 - Run this test as main class from IDE * @@ -145,10 +147,12 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest { private final RemoteCache remoteCache; private final int threadId; + private Executor executor; public HotRodListener(Cache cache, int threadId) { this.remoteCache = InfinispanUtil.getRemoteCache(cache); this.threadId = threadId; + this.executor = Executors.newCachedThreadPool(); } //private AtomicInteger listenerCount = new AtomicInteger(0); @@ -156,7 +160,12 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest { @ClientCacheEntryCreated public void created(ClientCacheEntryCreatedEvent event) { String cacheKey = (String) event.getKey(); - event(cacheKey, event.getVersion(), true); + + executor.execute(() -> { + + event(cacheKey, event.getVersion(), true); + + }); } @@ -164,7 +173,11 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest { @ClientCacheEntryModified public void updated(ClientCacheEntryModifiedEvent event) { String cacheKey = (String) event.getKey(); - event(cacheKey, event.getVersion(), false); + executor.execute(() -> { + + event(cacheKey, event.getVersion(), false); + + }); } @@ -174,7 +187,7 @@ public class ConcurrencyJDGRemoteCacheClientListenersTest { totalListenerCalls.incrementAndGet(); - VersionedValue versionedVal = remoteCache.getVersioned(cacheKey); + VersionedValue versionedVal = remoteCache.getWithMetadata(cacheKey); if (versionedVal.getVersion() < version) { System.err.println("INCOMPATIBLE VERSION. event version: " + version + ", entity version: " + versionedVal.getVersion()); diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/RemoteCacheSessionsLoaderTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/RemoteCacheSessionsLoaderTest.java new file mode 100644 index 00000000000..950a4c03c56 --- /dev/null +++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/RemoteCacheSessionsLoaderTest.java @@ -0,0 +1,160 @@ +/* + * Copyright 2017 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.cluster.infinispan; + +import java.util.HashSet; +import java.util.Set; + +import org.infinispan.Cache; +import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationBuilder; +import org.jboss.logging.Logger; +import org.junit.Assert; +import org.keycloak.common.util.Time; +import org.keycloak.connections.infinispan.InfinispanConnectionProvider; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; +import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity; +import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader; +import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoaderContext; +import org.keycloak.models.sessions.infinispan.util.InfinispanUtil; + +/** + * @author Marek Posolda + */ +public class RemoteCacheSessionsLoaderTest { + + protected static final Logger logger = Logger.getLogger(RemoteCacheSessionsLoaderTest.class); + + private static final int COUNT = 10000; + + public static void main(String[] args) throws Exception { + String cacheName = InfinispanConnectionProvider.USER_SESSION_CACHE_NAME; + Cache cache1 = createManager(1, cacheName).getCache(cacheName); + Cache cache2 = cache1.getCacheManager().getCache("local"); + RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache1); + cache1.clear(); + cache2.clear(); + remoteCache.clear(); + + try { + + for (int i=0 ; i wrappedSession = new SessionEntityWrapper<>(session); + + // Create caches, listeners and finally worker threads + remoteCache.put("loader-key-" + i, wrappedSession); + Assert.assertFalse(cache2.containsKey("loader-key-" + i)); + + if (i % 1000 == 0) { + logger.infof("%d sessions added", i); + } + } + + +// RemoteCacheSessionsLoader loader = new RemoteCacheSessionsLoader(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME, 64) { +// +// @Override +// protected Cache getCache(KeycloakSession session) { +// return cache2; +// } +// +// @Override +// protected RemoteCache getRemoteCache(KeycloakSession session) { +// return remoteCache; +// } +// +// }; + + // Just to be able to test serializability + RemoteCacheSessionsLoader loader = new CustomLoader(cacheName, 64, cache2, remoteCache); + + loader.init(null); + RemoteCacheSessionsLoaderContext ctx = loader.computeLoaderContext(null); + Assert.assertEquals(ctx.getSessionsTotal(), COUNT); + Assert.assertEquals(ctx.getIspnSegmentsCount(), 256); + //Assert.assertEquals(ctx.getSegmentsCount(), 16); + Assert.assertEquals(ctx.getSessionsPerSegment(), 64); + + int totalCount = 0; + logger.infof("segmentsCount: %d", ctx.getSegmentsCount()); + + Set visitedKeys = new HashSet<>(); + for (int currentSegment=0 ; currentSegment segments = state.getUnfinishedSegments(3); diff --git a/pom.xml b/pom.xml index 7e64720034b..3ed606ba141 100755 --- a/pom.xml +++ b/pom.xml @@ -44,16 +44,18 @@ 1.7 1.7 - 11.0.0.Final - 1.2.2.Final - 7.1.4.GA-redhat-1 - 1.2.2.Final - 3.0.10.Final + 13.0.0.Final + 1.2.10.Final + 7.2.0.CD13-redhat-4 + 1.2.10.Final + 5.0.0.Final 2.0.10.Final 7.2.0.Final - 0.66.19 + 0.66.19 + 1.4 + 1.7 4.5.2 4.4.4 0.6 @@ -65,30 +67,30 @@ 1.4.193 5.1.15.Final 1.0.0.Final - 8.2.11.Final + 9.2.4.Final 2.8.11 2.8.11.1 1.5.6 3.3.1.Final 2.1.0.Final 1.2.0.Final - 1.0.0.Final + 1.0.0.Final 1.0.1.Final 1.0.4.Final 1.2.17 - 3.0.26.Final + 3.5.1.Final 20180219.1 1.7.22 2.21 2.2.11 20140925 - 1.4.18.Final - 1.1.10.Final + 2.0.9.Final + 1.3.3.Final 1.0.1.Final 5.0.3 2.0.9 1.0.4 - 1.2.0.Final + 1.4.0.Final 6.5.0.Final @@ -261,8 +263,8 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec - ${jboss-jaxrs-api_2.0_spec} + jboss-jaxrs-api_2.1_spec + ${jboss-jaxrs-api_2.1_spec} org.jboss.resteasy @@ -711,8 +713,18 @@ org.jboss.aesh aesh + ${jboss.aesh.version} + + + org.aesh + aesh ${aesh.version} + + org.aesh + aesh-readline + ${aesh.readline.version} + diff --git a/services/pom.xml b/services/pom.xml index b26cb45f427..a5a6d8b5884 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -126,7 +126,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.spec.javax.transaction diff --git a/services/src/main/java/org/keycloak/services/managers/AuthSessionId.java b/services/src/main/java/org/keycloak/services/managers/AuthSessionId.java new file mode 100644 index 00000000000..db5aa7d58ef --- /dev/null +++ b/services/src/main/java/org/keycloak/services/managers/AuthSessionId.java @@ -0,0 +1,44 @@ +/* + * Copyright 2017 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.services.managers; + +/** + * @author Marek Posolda + */ +class AuthSessionId { + + // Decoded ID of authenticationSession WITHOUT route attached (EG. "5e161e00-d426-4ea6-98e9-52eb9844e2d7") + private final String decodedId; + + // Encoded ID of authenticationSession WITH route attached (EG. "5e161e00-d426-4ea6-98e9-52eb9844e2d7.node1") + private final String encodedId; + + AuthSessionId(String decodedId, String encodedId) { + this.decodedId = decodedId; + this.encodedId = encodedId; + } + + + public String getDecodedId() { + return decodedId; + } + + public String getEncodedId() { + return encodedId; + } +} diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java index 696315367a1..6f6f5f0ecd4 100644 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java @@ -71,17 +71,18 @@ public class AuthenticationSessionManager { return rootAuthSession; } - public RootAuthenticationSessionModel getCurrentRootAuthenticationSession(RealmModel realm) { - List authSessionIds = getAuthSessionCookieIds(realm); - return authSessionIds.stream().map(id -> { - SimpleEntry entry = decodeAuthSessionId(id); - String sessionId = entry.getKey(); + public RootAuthenticationSessionModel getCurrentRootAuthenticationSession(RealmModel realm) { + List authSessionCookies = getAuthSessionCookies(realm); + + return authSessionCookies.stream().map(oldEncodedId -> { + AuthSessionId authSessionId = decodeAuthSessionId(oldEncodedId); + String sessionId = authSessionId.getDecodedId(); RootAuthenticationSessionModel rootAuthSession = session.authenticationSessions().getRootAuthenticationSession(realm, sessionId); if (rootAuthSession != null) { - reencodeAuthSessionCookie(sessionId, entry.getValue(), realm); + reencodeAuthSessionCookie(oldEncodedId, authSessionId, realm); return rootAuthSession; } @@ -89,17 +90,18 @@ public class AuthenticationSessionManager { }).filter(authSession -> Objects.nonNull(authSession)).findFirst().orElse(null); } - public UserSessionModel getUserSessionFromAuthCookie(RealmModel realm) { - List authSessionIds = getAuthSessionCookieIds(realm); - return authSessionIds.stream().map(id -> { - SimpleEntry entry = decodeAuthSessionId(id); - String sessionId = entry.getKey(); + public UserSessionModel getUserSessionFromAuthCookie(RealmModel realm) { + List authSessionCookies = getAuthSessionCookies(realm); + + return authSessionCookies.stream().map(oldEncodedId -> { + AuthSessionId authSessionId = decodeAuthSessionId(oldEncodedId); + String sessionId = authSessionId.getDecodedId(); UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId); if (userSession != null) { - reencodeAuthSessionCookie(sessionId, entry.getValue(), realm); + reencodeAuthSessionCookie(oldEncodedId, authSessionId, realm); return userSession; } @@ -114,16 +116,16 @@ public class AuthenticationSessionManager { * @return */ public AuthenticationSessionModel getCurrentAuthenticationSession(RealmModel realm, ClientModel client, String tabId) { - List authSessionIds = getAuthSessionCookieIds(realm); + List authSessionCookies = getAuthSessionCookies(realm); - return authSessionIds.stream().map(id -> { - SimpleEntry entry = decodeAuthSessionId(id); - String sessionId = entry.getKey(); + return authSessionCookies.stream().map(oldEncodedId -> { + AuthSessionId authSessionId = decodeAuthSessionId(oldEncodedId); + String sessionId = authSessionId.getDecodedId(); AuthenticationSessionModel authSession = getAuthenticationSessionByIdAndClient(realm, sessionId, client, tabId); if (authSession != null) { - reencodeAuthSessionCookie(sessionId, entry.getValue(), realm); + reencodeAuthSessionCookie(oldEncodedId, authSessionId, realm); return authSession; } @@ -132,6 +134,10 @@ public class AuthenticationSessionManager { } + /** + * @param authSessionId decoded authSessionId (without route info attached) + * @param realm + */ public void setAuthSessionCookie(String authSessionId, RealmModel realm) { UriInfo uriInfo = session.getContext().getUri(); String cookiePath = AuthenticationManager.getRealmCookiePath(realm, uriInfo); @@ -146,23 +152,36 @@ public class AuthenticationSessionManager { log.debugf("Set AUTH_SESSION_ID cookie with value %s", encodedAuthSessionId); } - public SimpleEntry decodeAuthSessionId(String authSessionId) { - log.debugf("Found AUTH_SESSION_ID cookie with value %s", authSessionId); + + /** + * + * @param encodedAuthSessionId encoded ID with attached route in cluster environment (EG. "5e161e00-d426-4ea6-98e9-52eb9844e2d7.node1" ) + * @return object with decoded and actually encoded authSessionId + */ + AuthSessionId decodeAuthSessionId(String encodedAuthSessionId) { + log.debugf("Found AUTH_SESSION_ID cookie with value %s", encodedAuthSessionId); StickySessionEncoderProvider encoder = session.getProvider(StickySessionEncoderProvider.class); - String decodedAuthSessionId = encoder.decodeSessionId(authSessionId); + String decodedAuthSessionId = encoder.decodeSessionId(encodedAuthSessionId); String reencoded = encoder.encodeSessionId(decodedAuthSessionId); - return new SimpleEntry(decodedAuthSessionId, reencoded); + return new AuthSessionId(decodedAuthSessionId, reencoded); } - public void reencodeAuthSessionCookie(String decodedAuthSessionId, String reencodedAuthSessionId, RealmModel realm) { - if (!decodedAuthSessionId.equals(reencodedAuthSessionId)) { - log.debugf("Route changed. Will update authentication session cookie"); - setAuthSessionCookie(decodedAuthSessionId, realm); + + void reencodeAuthSessionCookie(String oldEncodedAuthSessionId, AuthSessionId newAuthSessionId, RealmModel realm) { + if (!oldEncodedAuthSessionId.equals(newAuthSessionId.getEncodedId())) { + log.debugf("Route changed. Will update authentication session cookie. Old: '%s', New: '%s'", oldEncodedAuthSessionId, + newAuthSessionId.getEncodedId()); + setAuthSessionCookie(newAuthSessionId.getDecodedId(), realm); } } - public List getAuthSessionCookieIds(RealmModel realm) { + + /** + * @param realm + * @return list of the values of AUTH_SESSION_ID cookies. It is assumed that values could be encoded with route added (EG. "5e161e00-d426-4ea6-98e9-52eb9844e2d7.node1" ) + */ + List getAuthSessionCookies(RealmModel realm) { Set cookiesVal = CookieHelper.getCookieValue(AUTH_SESSION_ID); if (cookiesVal.size() > 1) { diff --git a/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java b/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java index bd564008093..e8736b3418f 100644 --- a/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java +++ b/services/src/main/java/org/keycloak/services/managers/UserSessionCrossDCManager.java @@ -62,11 +62,11 @@ public class UserSessionCrossDCManager { // Just check if userSession also exists on remoteCache. It can happen that logout happened on 2nd DC and userSession is already removed on remoteCache and this DC wasn't yet notified public UserSessionModel getUserSessionIfExistsRemotely(AuthenticationSessionManager asm, RealmModel realm) { - List sessionIds = asm.getAuthSessionCookieIds(realm); + List sessionCookies = asm.getAuthSessionCookies(realm); - return sessionIds.stream().map(id -> { - SimpleEntry entry = asm.decodeAuthSessionId(id); - String sessionId = entry.getKey(); + return sessionCookies.stream().map(oldEncodedId -> { + AuthSessionId authSessionId = asm.decodeAuthSessionId(oldEncodedId); + String sessionId = authSessionId.getDecodedId(); // This will remove userSession "locally" if it doesn't exists on remoteCache kcSession.sessions().getUserSessionWithPredicate(realm, sessionId, false, (UserSessionModel userSession2) -> userSession2 == null); @@ -74,7 +74,7 @@ public class UserSessionCrossDCManager { UserSessionModel userSession = kcSession.sessions().getUserSession(realm, sessionId); if (userSession != null) { - asm.reencodeAuthSessionCookie(sessionId, entry.getValue(), realm); + asm.reencodeAuthSessionCookie(oldEncodedId, authSessionId, realm); return userSession; } diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md index 347ff20c241..81eb5cb838f 100644 --- a/testsuite/integration-arquillian/HOW-TO-RUN.md +++ b/testsuite/integration-arquillian/HOW-TO-RUN.md @@ -287,6 +287,17 @@ This will start latest Keycloak and import the realm JSON file, which was previo -Dmigrated.auth.server.version=1.9.8.Final +## Server configuration migration test +This will compare if Wildfly configuration files (standalone.xml, standalone-ha.xml, domain.xml) +are correctly migrated from previous version + + mvn -f testsuite/integration-arquillian/tests/other/server-config-migration/pom.xml \ + clean install \ + -Dmigrated.version=1.9.8.Final-redhat-1 + +For the available versions, take a look at the directory [tests/other/server-config-migration/src/test/resources/standalone](tests/other/server-config-migration/src/test/resources/standalone) + + ## Admin Console UI tests The UI tests are real-life, UI focused integration tests. Hence they do not support the default HtmlUnit browser. Only the following real-life browsers are supported: Mozilla Firefox, Google Chrome and Internet Explorer. For details on how to run the tests with these browsers, please refer to [Different Browsers](#different-browsers) chapter. diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/common/io.xsl b/testsuite/integration-arquillian/servers/app-server/jboss/common/io.xsl index 03d518a13ef..cceb8e27c3b 100644 --- a/testsuite/integration-arquillian/servers/app-server/jboss/common/io.xsl +++ b/testsuite/integration-arquillian/servers/app-server/jboss/common/io.xsl @@ -25,7 +25,7 @@ - + diff --git a/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml b/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml index 40762db0673..d7cadd868a0 100644 --- a/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml +++ b/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml @@ -112,7 +112,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/ispn-cache-owners.xsl b/testsuite/integration-arquillian/servers/auth-server/jboss/common/ispn-cache-owners.xsl index 46c6f7c66ad..bac11414585 100644 --- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/ispn-cache-owners.xsl +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/ispn-cache-owners.xsl @@ -1,6 +1,6 @@ @@ -23,11 +23,21 @@ + + + + + + + + + + diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml index 9d818c38c57..abf6faea722 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml @@ -35,6 +35,7 @@ + diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/common/add-keycloak-caches.xsl b/testsuite/integration-arquillian/servers/cache-server/jboss/common/add-keycloak-caches.xsl index 7b48a9613ad..08090032953 100644 --- a/testsuite/integration-arquillian/servers/cache-server/jboss/common/add-keycloak-caches.xsl +++ b/testsuite/integration-arquillian/servers/cache-server/jboss/common/add-keycloak-caches.xsl @@ -25,6 +25,7 @@ + @@ -36,7 +37,9 @@ - + + + diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml index 4eebe36ca82..57aa4e34b04 100644 --- a/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml +++ b/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml @@ -35,6 +35,7 @@ ${containers.home}/${cache.server.container} true + false org.infinispan.server infinispan-server ${infinispan.version} diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml index c498e99ee02..88f81d2d2ec 100644 --- a/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml +++ b/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml @@ -34,7 +34,8 @@ cache-server-${cache.server} ${containers.home}/${cache.server.container} - false + true + true org.infinispan.server infinispan-server ${jdg.version} diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml index 7540bb0c03a..f3474d8f885 100644 --- a/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml +++ b/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml @@ -34,6 +34,7 @@ ${project.parent.basedir}/assembly.xml ${containers.home}/${cache.server.jboss.unpacked.folder.name} true + true security.xsl @@ -126,6 +127,10 @@ remote.site dc-1 + + transactions.enabled + ${cache.server.jboss.jdg-transactions-enabled} + ${cache.server.jboss.home}/standalone/configuration @@ -152,6 +157,10 @@ remote.site dc-0 + + transactions.enabled + ${cache.server.jboss.jdg-transactions-enabled} + ${cache.server.jboss.home}/standalone/configuration diff --git a/testsuite/integration-arquillian/servers/pom.xml b/testsuite/integration-arquillian/servers/pom.xml index 96588c81b81..fb63271242b 100644 --- a/testsuite/integration-arquillian/servers/pom.xml +++ b/testsuite/integration-arquillian/servers/pom.xml @@ -47,8 +47,8 @@ 6.2.1.redhat-084 - - 8.4.0.Final-redhat-2 + + 8.5.0.Final-redhat-9 16 128 diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml index 47e31d28bab..bb0119f3925 100755 --- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml +++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml @@ -19,7 +19,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec provided diff --git a/testsuite/integration-arquillian/test-apps/servlets/pom.xml b/testsuite/integration-arquillian/test-apps/servlets/pom.xml index ec91b9c2a20..20cede5e6f3 100644 --- a/testsuite/integration-arquillian/test-apps/servlets/pom.xml +++ b/testsuite/integration-arquillian/test-apps/servlets/pom.xml @@ -32,7 +32,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.keycloak diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java index 684b13d8cb4..d54ca85721a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java @@ -146,7 +146,7 @@ public class AuthenticationSessionClusterTest extends AbstractClusterTest { // Check that route owner is always node1 getTestingClientFor(backendNode(0)).server().run(session -> { Cache authSessionCache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME); - String keyOwner = InfinispanUtil.getKeyPrimaryOwnerAddress(authSessionCache, authSessionCookie); + String keyOwner = InfinispanUtil.getTopologyInfo(session).getRouteName(authSessionCache, authSessionCookie); Assert.assertEquals("node1", keyOwner); }); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ActionTokenCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ActionTokenCrossDCTest.java index 5a866651a7b..d88785bd719 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ActionTokenCrossDCTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ActionTokenCrossDCTest.java @@ -92,7 +92,7 @@ public class ActionTokenCrossDCTest extends AbstractAdminCrossDCTest { cacheDc0Node1Statistics.waitToBecomeAvailable(10, TimeUnit.SECONDS); - Comparable originalNumberOfEntries = cacheDc0Node0Statistics.getSingleStatistics(Constants.STAT_CACHE_NUMBER_OF_ENTRIES); + Comparable originalNumberOfEntries = cacheDc0Node0Statistics.getSingleStatistics(Constants.STAT_CACHE_NUMBER_OF_ENTRIES_IN_MEMORY); UserRepresentation userRep = new UserRepresentation(); userRep.setEnabled(true); @@ -112,7 +112,7 @@ public class ActionTokenCrossDCTest extends AbstractAdminCrossDCTest { String link = MailUtils.getPasswordResetEmailLink(message); - assertSingleStatistics(cacheDc0Node0Statistics, Constants.STAT_CACHE_NUMBER_OF_ENTRIES, + assertSingleStatistics(cacheDc0Node0Statistics, Constants.STAT_CACHE_NUMBER_OF_ENTRIES_IN_MEMORY, () -> driver.navigate().to(link), Matchers::is ); @@ -141,13 +141,15 @@ public class ActionTokenCrossDCTest extends AbstractAdminCrossDCTest { assertThat(PageUtils.getPageTitle(driver), containsString("Your account has been updated.")); // Verify that there was an action token added in the node which was targetted by the link - assertThat(cacheDc0Node0Statistics.getSingleStatistics(Constants.STAT_CACHE_NUMBER_OF_ENTRIES), greaterThan(originalNumberOfEntries)); + assertThat(cacheDc0Node0Statistics.getSingleStatistics(Constants.STAT_CACHE_NUMBER_OF_ENTRIES_IN_MEMORY), greaterThan(originalNumberOfEntries)); disableDcOnLoadBalancer(DC.FIRST); enableDcOnLoadBalancer(DC.SECOND); // Make sure that after going to the link, the invalidated action token has been retrieved from Infinispan server cluster in the other DC - assertSingleStatistics(cacheDc1Node0Statistics, Constants.STAT_CACHE_NUMBER_OF_ENTRIES, + // NOTE: Using STAT_CACHE_NUMBER_OF_ENTRIES_IN_MEMORY as it doesn't contain the items from cacheLoader (remoteCache) until they are really loaded into the cache memory. That's the + // statistic, which is actually increased on dc1-node0 once the used actionToken is loaded to the cache (memory) from remoteCache + assertSingleStatistics(cacheDc1Node0Statistics, Constants.STAT_CACHE_NUMBER_OF_ENTRIES_IN_MEMORY, () -> driver.navigate().to(link), Matchers::greaterThan ); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/BruteForceCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/BruteForceCrossDCTest.java index aea8b2a69f2..afcfe202056 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/BruteForceCrossDCTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/BruteForceCrossDCTest.java @@ -168,6 +168,9 @@ public class BruteForceCrossDCTest extends AbstractAdminCrossDCTest { enableDcOnLoadBalancer(DC.FIRST); enableDcOnLoadBalancer(DC.SECOND); +// log.infof("Sleeping"); +// Thread.sleep(3600000); + // Clear all adminClient.realms().realm(REALM_NAME).attackDetection().clearAllBruteForce(); assertStatistics("After brute force cleared", 0, 0, 0); @@ -222,6 +225,8 @@ public class BruteForceCrossDCTest extends AbstractAdminCrossDCTest { @Test public void testBruteForceConcurrentUpdate() throws Exception { + //Thread.sleep(120000); + // Enable 1st node on each DC only enableDcOnLoadBalancer(DC.FIRST); enableDcOnLoadBalancer(DC.SECOND); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ConcurrentLoginCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ConcurrentLoginCrossDCTest.java index 33deb9b8a32..ed87fcfc83b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ConcurrentLoginCrossDCTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/ConcurrentLoginCrossDCTest.java @@ -20,12 +20,10 @@ package org.keycloak.testsuite.crossdc; import java.util.ArrayList; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.RealmResource; -import java.util.List; import org.jboss.arquillian.container.test.api.ContainerController; import org.jboss.arquillian.test.api.ArquillianResource; import org.keycloak.testsuite.admin.concurrency.ConcurrentLoginTest; -import org.keycloak.testsuite.arquillian.ContainerInfo; import org.keycloak.testsuite.arquillian.LoadBalancerController; import org.keycloak.testsuite.arquillian.annotation.LoadBalancer; import java.util.Arrays; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java index 643bb4b674e..95cdd49dea5 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java @@ -192,7 +192,8 @@ public class SessionExpirationCrossDCTest extends AbstractAdminCrossDCTest { int clientSessions2 = getTestingClientForStartedNodeInDc(1).testing().cache(clientSessionsCacheName).size(); int remoteSessions1 = (Integer) cacheDc1Statistics.getSingleStatistics(InfinispanStatistics.Constants.STAT_CACHE_NUMBER_OF_ENTRIES); int remoteSessions2 = (Integer) cacheDc2Statistics.getSingleStatistics(InfinispanStatistics.Constants.STAT_CACHE_NUMBER_OF_ENTRIES); - long messagesCount = (Long) channelStatisticsCrossDc.getSingleStatistics(InfinispanStatistics.Constants.STAT_CHANNEL_SENT_MESSAGES); + // Needs to use "received_messages" on Infinispan 9.2.4.Final. Stats for "sent_messages" is always null + long messagesCount = (Long) channelStatisticsCrossDc.getSingleStatistics(InfinispanStatistics.Constants.STAT_CHANNEL_RECEIVED_MESSAGES); log.infof(messagePrefix + ": sessions1: %d, sessions2: %d, remoteSessions1: %d, remoteSessions2: %d, sentMessages: %d", sessions1, sessions2, remoteSessions1, remoteSessions2, messagesCount); Assert.assertEquals(sessions1, sessions1Expected); @@ -432,6 +433,15 @@ public class SessionExpirationCrossDCTest extends AbstractAdminCrossDCTest { // Kill node2 now. Around 10 sessions (half of SESSIONS_COUNT) will be lost on Keycloak side. But not on infinispan side CrossDCTestEnricher.stopAuthServerBackendNode(DC.FIRST, 1); + // Assert it's still possible to refresh tokens. UserSessions, which were cleared from the Keycloak node, should be downloaded from remoteStore + int i1 = 0; + for (OAuthClient.AccessTokenResponse response : responses) { + i1++; + OAuthClient.AccessTokenResponse refreshTokenResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); + Assert.assertNotNull("Failed in iteration " + i1, refreshTokenResponse.getRefreshToken()); + Assert.assertNull("Failed in iteration " + i1, refreshTokenResponse.getError()); + } + channelStatisticsCrossDc.reset(); // Increase offset a bit to ensure logout happens later then token issued time @@ -662,7 +672,7 @@ public class SessionExpirationCrossDCTest extends AbstractAdminCrossDCTest { Retry.execute(() -> { int authSessions1 = getTestingClientForStartedNodeInDc(0).testing().cache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME).size(); int authSessions2 = getTestingClientForStartedNodeInDc(1).testing().cache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME).size(); - long messagesCount = (Long) channelStatisticsCrossDc.getSingleStatistics(InfinispanStatistics.Constants.STAT_CHANNEL_SENT_MESSAGES); + long messagesCount = (Long) channelStatisticsCrossDc.getSingleStatistics(InfinispanStatistics.Constants.STAT_CHANNEL_RECEIVED_MESSAGES); log.infof(messagePrefix + ": authSessions1: %d, authSessions2: %d, sentMessages: %d", authSessions1, authSessions2, messagesCount); int diff1 = authSessions1 - authSessions01; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java index 4bdb9ec091f..24145999656 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java @@ -1,16 +1,22 @@ package org.keycloak.testsuite.error; import org.jboss.arquillian.graphene.page.Page; +import org.junit.Assert; import org.junit.Test; import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.common.util.StreamUtil; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.pages.ErrorPage; import javax.ws.rs.core.Response; + +import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Array; import java.net.MalformedURLException; import java.net.URI; +import java.nio.charset.Charset; import java.util.Collections; import java.util.List; @@ -43,10 +49,14 @@ public class UncaughtErrorPageTest extends AbstractKeycloakTest { } @Test - public void uncaughtErrorJson() { + public void uncaughtErrorJson() throws IOException { Response response = testingClient.testing().uncaughtError(); - assertNull(response.getEntity()); assertEquals(500, response.getStatus()); + + InputStream is = (InputStream) response.getEntity(); + String responseString = StreamUtil.readString(is, Charset.forName("UTF-8")); + + Assert.assertTrue(responseString.contains("An internal server error has occurred")); } @Test diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json index bc06479015f..e1e7dcaa4ee 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json @@ -126,7 +126,7 @@ "sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:1}", "l1Lifespan": "${keycloak.connectionsInfinispan.l1Lifespan:600000}", "remoteStoreEnabled": "${keycloak.connectionsInfinispan.remoteStoreEnabled:false}", - "remoteStoreServer": "${keycloak.connectionsInfinispan.remoteStoreServer:localhost}", + "remoteStoreHost": "${keycloak.connectionsInfinispan.remoteStoreServer:localhost}", "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}" } }, diff --git a/testsuite/integration-arquillian/tests/other/server-config-migration/README.md b/testsuite/integration-arquillian/tests/other/server-config-migration/README.md index 83b832b998e..921517cd6f4 100644 --- a/testsuite/integration-arquillian/tests/other/server-config-migration/README.md +++ b/testsuite/integration-arquillian/tests/other/server-config-migration/README.md @@ -27,7 +27,7 @@ Migration scripts are applied using **offline mode**. Temporary data are removed `maven-exec-plugin` is used to read migrated configs and saves the output to `${project.build.directory}/migrated-${config.name}.txt` ### `default-test` -`org.keycloak.test.config.migrationConfigMigrationTest` is executed. It compares generated outputs from ${project.build.directory} +`org.keycloak.test.config.migration.ConfigMigrationTest` is executed. It compares generated outputs from ${project.build.directory} If config outputs don't equal to each other, **by default** the test will compare outputs more deeply to get more readable output. It fails on first found difference. diff --git a/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/domain-3.4.3.Final-redhat-2.xml b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/domain-3.4.3.Final-redhat-2.xml new file mode 100644 index 00000000000..3855f81bf02 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/domain-3.4.3.Final-redhat-2.xml @@ -0,0 +1,1123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + h2 + + sa + sa + + + + jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE + h2 + + sa + sa + + + + + org.h2.jdbcx.JdbcDataSource + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auth + + classpath:${jboss.home.dir}/providers/* + + master + 900 + + 2592000 + true + true + ${jboss.home.dir}/themes + + + + + + + + + + + + + jpa + + + basic + + + + + + + + + + + + + + + + + + + default + + + + + + + + ${keycloak.jta.lookup.provider:jboss} + + + + + + + + + + + ${keycloak.x509cert.lookup.provider:default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + h2 + + sa + sa + + + + jdbc:h2:${jboss.server.data.dir}/../../shared-database/keycloak;AUTO_SERVER=TRUE + h2 + + sa + sa + + + + + org.h2.jdbcx.JdbcDataSource + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auth + + classpath:${jboss.home.dir}/providers/* + + master + 900 + + 2592000 + true + true + ${jboss.home.dir}/themes + + + + + + + + + + + + + jpa + + + basic + + + + + + + + + + + + + + + + + + + default + + + + + + + + ${keycloak.jta.lookup.provider:jboss} + + + + + + + + + + + ${keycloak.x509cert.lookup.provider:default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/host-master-3.4.3.Final-redhat-2.xml b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/host-master-3.4.3.Final-redhat-2.xml new file mode 100644 index 00000000000..7963f3d6e92 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/domain/host-master-3.4.3.Final-redhat-2.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-3.4.3.Final-redhat-2.xml b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-3.4.3.Final-redhat-2.xml new file mode 100644 index 00000000000..3f90433d453 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-3.4.3.Final-redhat-2.xml @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + h2 + + sa + sa + + + + jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE + h2 + + sa + sa + + + + + org.h2.jdbcx.JdbcDataSource + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auth + + classpath:${jboss.home.dir}/providers/* + + master + 900 + + 2592000 + true + true + ${jboss.home.dir}/themes + + + + + + + + + + + + + jpa + + + basic + + + + + + + + + + + + + + + + + + + default + + + + + + + + ${keycloak.jta.lookup.provider:jboss} + + + + + + + + + + + ${keycloak.x509cert.lookup.provider:default} + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-ha-3.4.3.Final-redhat-2.xml b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-ha-3.4.3.Final-redhat-2.xml new file mode 100644 index 00000000000..d4c2884f8f5 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/server-config-migration/src/test/resources/standalone/standalone-ha-3.4.3.Final-redhat-2.xml @@ -0,0 +1,631 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + h2 + + sa + sa + + + + jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE + h2 + + sa + sa + + + + + org.h2.jdbcx.JdbcDataSource + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auth + + classpath:${jboss.home.dir}/providers/* + + master + 900 + + 2592000 + true + true + ${jboss.home.dir}/themes + + + + + + + + + + + + + jpa + + + basic + + + + + + + + + + + + + + + + + + + default + + + + + + + + ${keycloak.jta.lookup.provider:jboss} + + + + + + + + + + + ${keycloak.x509cert.lookup.provider:default} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index 8bfbce3ce21..56fb88235c7 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -950,7 +950,7 @@ true ${cache.server.home}/standalone/configuration %d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n - true + false diff --git a/testsuite/integration-deprecated/pom.xml b/testsuite/integration-deprecated/pom.xml index 20e7d18d091..0be943c9d6c 100755 --- a/testsuite/integration-deprecated/pom.xml +++ b/testsuite/integration-deprecated/pom.xml @@ -66,7 +66,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.spec.javax.transaction diff --git a/testsuite/jetty/jetty92/pom.xml b/testsuite/jetty/jetty92/pom.xml index 7a37a58941c..a3a3cfebde2 100755 --- a/testsuite/jetty/jetty92/pom.xml +++ b/testsuite/jetty/jetty92/pom.xml @@ -67,7 +67,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/jetty/jetty93/pom.xml b/testsuite/jetty/jetty93/pom.xml index 8e2cde0d41f..5f5192d3faf 100644 --- a/testsuite/jetty/jetty93/pom.xml +++ b/testsuite/jetty/jetty93/pom.xml @@ -67,7 +67,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/jetty/jetty94/pom.xml b/testsuite/jetty/jetty94/pom.xml index d6a6aa674fd..d579071a5a2 100644 --- a/testsuite/jetty/jetty94/pom.xml +++ b/testsuite/jetty/jetty94/pom.xml @@ -67,7 +67,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/performance/keycloak/src/main/scripts/jboss-cli/add-remote-cache-stores.cli b/testsuite/performance/keycloak/src/main/scripts/jboss-cli/add-remote-cache-stores.cli index e4b707ee8be..e9f6174a4d4 100644 --- a/testsuite/performance/keycloak/src/main/scripts/jboss-cli/add-remote-cache-stores.cli +++ b/testsuite/performance/keycloak/src/main/scripts/jboss-cli/add-remote-cache-stores.cli @@ -16,5 +16,5 @@ cd /subsystem=infinispan/cache-container=keycloak ./distributed-cache=loginFailures/store=remote:add(cache=loginFailures, fetch-state=false, passivation=false, preload=false, purge=false, remote-servers=["remote-cache"], shared=true, properties={rawValues=true, marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory}) ./distributed-cache=actionTokens/store=remote:add(cache=actionTokens, fetch-state=false, passivation=false, preload=false, purge=false, remote-servers=["remote-cache"], shared=true, properties={rawValues=true, marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory}) -./distributed-cache=actionTokens/eviction=EVICTION:add(max-entries=-1, strategy=NONE) +./distributed-cache=actionTokens/memory-object:add(size=-1) ./distributed-cache=actionTokens/expiration=EXPIRATION:add(max-idle=-1,interval=300000) \ No newline at end of file diff --git a/testsuite/performance/tests/pom.xml b/testsuite/performance/tests/pom.xml index 8aff879a7de..f43fe1c56cc 100644 --- a/testsuite/performance/tests/pom.xml +++ b/testsuite/performance/tests/pom.xml @@ -129,7 +129,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.logging diff --git a/testsuite/proxy/pom.xml b/testsuite/proxy/pom.xml index 64a29b93ef3..fd78932178c 100755 --- a/testsuite/proxy/pom.xml +++ b/testsuite/proxy/pom.xml @@ -58,7 +58,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/tomcat7/pom.xml b/testsuite/tomcat7/pom.xml index f175e066cc7..3173f2dad37 100755 --- a/testsuite/tomcat7/pom.xml +++ b/testsuite/tomcat7/pom.xml @@ -81,7 +81,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/tomcat8/pom.xml b/testsuite/tomcat8/pom.xml index 59424a94bee..2111bdc9e83 100755 --- a/testsuite/tomcat8/pom.xml +++ b/testsuite/tomcat8/pom.xml @@ -53,7 +53,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.resteasy diff --git a/testsuite/utils/pom.xml b/testsuite/utils/pom.xml index 706c0cd7041..5017aeefa10 100755 --- a/testsuite/utils/pom.xml +++ b/testsuite/utils/pom.xml @@ -79,7 +79,7 @@ org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec + jboss-jaxrs-api_2.1_spec org.jboss.spec.javax.transaction diff --git a/testsuite/utils/src/main/resources/META-INF/keycloak-server.json b/testsuite/utils/src/main/resources/META-INF/keycloak-server.json index d7aa39a67dd..8da4160c96e 100755 --- a/testsuite/utils/src/main/resources/META-INF/keycloak-server.json +++ b/testsuite/utils/src/main/resources/META-INF/keycloak-server.json @@ -104,13 +104,7 @@ "l1Lifespan": "${keycloak.connectionsInfinispan.l1Lifespan:600000}", "remoteStoreEnabled": "${keycloak.connectionsInfinispan.remoteStoreEnabled:false}", "remoteStoreHost": "${keycloak.connectionsInfinispan.remoteStoreServer:localhost}", - "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}", - "remoteStoreSecurityEnabled": "${keycloak.connectionsInfinispan.remoteStoreSecurityEnabled:false}", - "remoteStoreSecurityServerName": "${keycloak.connectionsInfinispan.remoteStoreSecurityServerName:keycloak-server}", - "remoteStoreSecurityRealm": "${keycloak.connectionsInfinispan.remoteStoreSecurityRealm:ApplicationRealm}", - "remoteStoreSecurityHotRodEndpoint": "${keycloak.connectionsInfinispan.remoteStoreSecurityHotRodEndpoint}", - "remoteStoreSecurityUsername": "${keycloak.connectionsInfinispan.remoteStoreSecurityUsername}", - "remoteStoreSecurityPassword": "${keycloak.connectionsInfinispan.remoteStoreSecurityPassword}" + "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}" } }, diff --git a/wildfly/adduser/pom.xml b/wildfly/adduser/pom.xml index 981f7f27d1e..b1fb823bed3 100755 --- a/wildfly/adduser/pom.xml +++ b/wildfly/adduser/pom.xml @@ -52,8 +52,12 @@ ${wildfly.core.version} - org.jboss.aesh + org.aesh aesh + + org.aesh + aesh-readline + diff --git a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java index 4a7c9a1256f..6edb948d663 100644 --- a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java +++ b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java @@ -18,16 +18,28 @@ package org.keycloak.wildfly.adduser; import com.fasterxml.jackson.core.type.TypeReference; -import org.jboss.aesh.cl.CommandDefinition; -import org.jboss.aesh.cl.Option; -import org.jboss.aesh.cl.parser.ParserGenerator; -import org.jboss.aesh.console.command.Command; -import org.jboss.aesh.console.command.CommandNotFoundException; -import org.jboss.aesh.console.command.CommandResult; -import org.jboss.aesh.console.command.container.CommandContainer; -import org.jboss.aesh.console.command.invocation.CommandInvocation; -import org.jboss.aesh.console.command.registry.AeshCommandRegistryBuilder; -import org.jboss.aesh.console.command.registry.CommandRegistry; +import org.aesh.command.CommandDefinition; +import org.aesh.command.impl.activator.AeshCommandActivatorProvider; +import org.aesh.command.impl.activator.AeshOptionActivatorProvider; +import org.aesh.command.impl.completer.AeshCompleterInvocationProvider; +import org.aesh.command.impl.container.AeshCommandContainerBuilder; +import org.aesh.command.impl.converter.AeshConverterInvocationProvider; +import org.aesh.command.impl.invocation.AeshInvocationProviders; +import org.aesh.command.impl.parser.CommandLineParser; +import org.aesh.command.impl.validator.AeshValidatorInvocationProvider; +import org.aesh.command.invocation.InvocationProviders; +import org.aesh.command.option.Option; +import org.aesh.command.Command; +import org.aesh.command.CommandNotFoundException; +import org.aesh.command.CommandResult; +import org.aesh.command.container.CommandContainer; +import org.aesh.command.invocation.CommandInvocation; +import org.aesh.command.impl.registry.AeshCommandRegistryBuilder; +import org.aesh.command.parser.CommandLineParserException; +import org.aesh.command.registry.CommandRegistry; +import org.aesh.command.settings.Settings; +import org.aesh.command.settings.SettingsBuilder; +import org.aesh.readline.AeshContext; import org.keycloak.common.util.Base64; import org.keycloak.credential.CredentialModel; import org.keycloak.credential.hash.PasswordHashProvider; @@ -57,34 +69,41 @@ public class AddUser { private static final int DEFAULT_HASH_ITERATIONS = 100000; private static final String DEFAULT_HASH_ALGORITH = PasswordPolicy.HASH_ALGORITHM_DEFAULT; - public static void main(String[] args) throws Exception { - AddUserCommand command = new AddUserCommand(); + public static void main(String[] args) { + AddUserCommand command; try { - ParserGenerator.parseAndPopulate(command, COMMAND_NAME, args); - } catch (Exception e) { - System.err.println(e.getMessage()); - System.exit(1); - } + Settings settings = SettingsBuilder.builder().build(); + InvocationProviders invocationProviders = new AeshInvocationProviders(settings); + AeshContext aeshContext = settings.aeshContext(); + CommandLineParser> parser = new AeshCommandContainerBuilder, CommandInvocation>().create(new AddUserCommand<>()).getParser(); - if (command.isHelp()) { - printHelp(command); - } else { - try { + StringBuilder sb = new StringBuilder(COMMAND_NAME); + for (String arg : args) { + sb.append(" " + arg); + } + parser.populateObject(sb.toString(), invocationProviders, aeshContext, CommandLineParser.Mode.VALIDATE); + command = parser.getCommand(); + + if (command.isHelp()) { + printHelp(command); + } else { String password = command.getPassword(); checkRequired(command, "user"); - if(isEmpty(command, "password")){ + if (isEmpty(command, "password")) { password = promptForInput(); } File addUserFile = getAddUserFile(command); createUser(addUserFile, command.getRealm(), command.getUser(), password, command.getRoles(), command.getIterations()); - } catch (Exception e) { - System.err.println(e.getMessage()); - System.exit(1); } } + catch (Exception e){ + System.err.println(e.getMessage()); + System.exit(1); + } + } private static File getAddUserFile(AddUserCommand command) throws Exception { @@ -255,7 +274,7 @@ public class AddUser { return new String(passwordArray); } - private static void printHelp(Command command) throws CommandNotFoundException { + private static void printHelp(Command command) throws CommandNotFoundException, CommandLineParserException { CommandRegistry registry = new AeshCommandRegistryBuilder().command(command).create(); CommandContainer commandContainer = registry.getCommand(command.getClass().getAnnotation(CommandDefinition.class).name(), null); String help = commandContainer.printHelp(null); @@ -263,7 +282,7 @@ public class AddUser { } @CommandDefinition(name= COMMAND_NAME, description = "[options...]") - public static class AddUserCommand implements Command { + public static class AddUserCommand implements Command { @Option(shortName = 'r', hasValue = true, description = "Name of realm to add user to") private String realm; diff --git a/wildfly/server-subsystem/src/main/config/default-server-subsys-config.properties b/wildfly/server-subsystem/src/main/config/default-server-subsys-config.properties index aaecc2ceba4..23f862bb4bf 100644 --- a/wildfly/server-subsystem/src/main/config/default-server-subsys-config.properties +++ b/wildfly/server-subsystem/src/main/config/default-server-subsys-config.properties @@ -58,7 +58,7 @@ keycloak.server.subsys.default.config=\ default\ \ \ - \ + \ \ \ \ diff --git a/wildfly/server-subsystem/src/main/resources/cli/default-keycloak-subsys-config.cli b/wildfly/server-subsystem/src/main/resources/cli/default-keycloak-subsys-config.cli index 26c6a8aaf33..6e14be67377 100644 --- a/wildfly/server-subsystem/src/main/resources/cli/default-keycloak-subsys-config.cli +++ b/wildfly/server-subsystem/src/main/resources/cli/default-keycloak-subsys-config.cli @@ -15,7 +15,7 @@ /subsystem=keycloak-server/spi=realmCache/:add /subsystem=keycloak-server/spi=realmCache/provider=default/:add(enabled=true) /subsystem=keycloak-server/spi=connectionsInfinispan/:add(default-provider=default) -/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default/:add(properties={cacheContainer => "java:comp/env/infinispan/Keycloak"},enabled=true) +/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default/:add(properties={cacheContainer => "java:jboss/infinispan/container/keycloak"},enabled=true) /subsystem=keycloak-server/spi=jta-lookup/:add(default-provider=${keycloak.jta.lookup.provider:jboss}) /subsystem=keycloak-server/spi=jta-lookup/provider=jboss/:add(enabled=true) /subsystem=keycloak-server/spi=publicKeyStorage/:add diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml index b3ea2a9d5f5..f1edb8092a2 100755 --- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml +++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml @@ -19,17 +19,17 @@ org.jboss.as.clustering.infinispan - + - + - + - + @@ -39,14 +39,14 @@ - + - + - + @@ -69,14 +69,14 @@ - + - + - + @@ -85,30 +85,30 @@ - + - + - + - - - - - - + + + + + + - + - + - + - - + + @@ -134,18 +134,18 @@ - + - + - + - + diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-undertow.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-undertow.xml index db46210b8c8..715d13621be 100644 --- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-undertow.xml +++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-undertow.xml @@ -1,30 +1,37 @@ + + org.wildfly.extension.undertow - - + + - - + + - + @@ -33,7 +40,7 @@ - + @@ -45,3 +52,4 @@ + diff --git a/wildfly/server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/JsonConfigConverterTestCase.java b/wildfly/server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/JsonConfigConverterTestCase.java index 9931b4dcd78..7752258f2a7 100644 --- a/wildfly/server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/JsonConfigConverterTestCase.java +++ b/wildfly/server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/JsonConfigConverterTestCase.java @@ -166,7 +166,7 @@ public class JsonConfigConverterTestCase { + " \"connectionsInfinispan\": {\n" + " \"provider\": \"default\",\n" + " \"default\": {\n" - + " \"cacheContainer\" : \"java:comp/env/infinispan/Keycloak\"\n" + + " \"cacheContainer\" : \"java:jboss/infinispan/container/keycloak\"\n" + " }\n" + " }\n" + "}"; @@ -429,7 +429,7 @@ public class JsonConfigConverterTestCase { " (\"spi\" => \"connectionsInfinispan\"),\n" + " (\"provider\" => \"default\")\n" + " ],\n" + - " \"properties\" => {\"cacheContainer\" => \"java:comp/env/infinispan/Keycloak\"},\n" + + " \"properties\" => {\"cacheContainer\" => \"java:jboss/infinispan/container/keycloak\"},\n" + " \"enabled\" => true\n" + "}" ));