diff --git a/adapters/oidc/installed/pom.xml b/adapters/oidc/installed/pom.xml index 0e89e2b676..e07cc0e57a 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 a8acfdaf79..472e5c8790 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 b633e229a7..a8b20e2326 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 7f18d0df34..3754763c1f 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 c93393873d..7c64b1a960 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 cceef6646f..1d0ada966a 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 5774706ac9..47f05e5b1c 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 095fcc4cc5..166e2207fb 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 3b1812ea6b..2cc9a3bc08 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 6a4dba4ff1..07c65adc1e 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 7b13afe79e..5c2cb0e6f3 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 21fe61b3fd..9b9729cd83 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 56b676c89c..49de7ae400 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 5b11647bdc..e59194f0c0 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 5194c450c9..479fc1a9d4 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 4388f83dfc..9d93415978 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 6ad93e959e..4a85d38417 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 88744aca57..8854801656 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 c73d5c1a3b..0f8af6f9b2 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 6a40e72f7c..bbb589f80d 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 2ea58e0363..888915667e 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 d4b02f8632..2c5488087b 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 4fe832c04d..2d6af4f113 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 6d4c4421b6..78b5a8374c 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 6e21b7bbeb..0dfc0726c9 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 6e1607774d..07ef60bf69 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 c3cc1b6998..388a54bc43 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 bbfd3605b0..193975094b 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 70a6e5452f..66aa372352 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 4334c29915..73fbb5a9ce 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 c1f891442b..f796dfb1c7 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 0053791d1e..e3dfc3626d 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 cb23b6fd9f..03e51d0031 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 0000000000..25a6ad1afd --- /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 871525d03a..f9086289d5 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 001e295b47..5e87395e7b 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 22ef5b7976..1e1670d11b 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 9e47c415de..15d8c25413 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 3400782f31..fd6ebc0385 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 00b499e974..a18443884c 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 5f78eda326..c2e6c86f87 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 635f0e63e2..0e2e6157f3 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 cf51796e18..dfaa3aa799 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 fafd1561b8..40b1e1024d 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 71d826836a..1c83f0cf1e 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 930b24e5d3..0fc9cfe2e5 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 7b60dcb39d..cf62230bce 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 0000000000..491239b397 --- /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 ec647afdbe..7df94bf04b 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 a60b4b9ac3..0000000000 --- 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 15c9e4f06b..6dcfb703c5 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 1639c78599..477a01ed45 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 53b294c523..0ff1a901c2 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 0000000000..ec74871b14 --- /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 95133f5a0e..bd8efd07cc 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 7cf38adda6..e086fdfc0b 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 80894a7e8f..b662578b20 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 0000000000..950a4c03c5 --- /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 7e64720034..3ed606ba14 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 b26cb45f42..a5a6d8b588 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 0000000000..db5aa7d58e --- /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 696315367a..6f6f5f0ecd 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 bd56400809..e8736b3418 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 347ff20c24..81eb5cb838 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 03d518a13e..cceb8e27c3 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 40762db067..d7cadd868a 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 46c6f7c66a..bac1141458 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 9d818c38c5..abf6faea72 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 7b48a9613a..0809003295 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 4eebe36ca8..57aa4e34b0 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 c498e99ee0..88f81d2d2e 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 7540bb0c03..f3474d8f88 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 96588c81b8..fb63271242 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 47e31d28ba..bb0119f392 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 ec91b9c2a2..20cede5e6f 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 684b13d8cb..d54ca85721 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 5a866651a7..d88785bd71 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 aea8b2a69f..afcfe20205 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 33deb9b8a3..ed87fcfc83 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 643bb4b674..95cdd49dea 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 4bdb9ec091..2414599965 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 bc06479015..e1e7dcaa4e 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 83b832b998..921517cd6f 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 0000000000..3855f81bf0 --- /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 0000000000..7963f3d6e9 --- /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 0000000000..3f90433d45 --- /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 0000000000..d4c2884f8f --- /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 8bfbce3ce2..56fb88235c 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 20e7d18d09..0be943c9d6 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 7a37a58941..a3a3cfebde 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 8e2cde0d41..5f5192d3fa 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 d6a6aa674f..d579071a5a 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 e4b707ee8b..e9f6174a4d 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 8aff879a7d..f43fe1c56c 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 64a29b93ef..fd78932178 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 f175e066cc..3173f2dad3 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 59424a94be..2111bdc9e8 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 706c0cd704..5017aeefa1 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 d7aa39a67d..8da4160c96 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 981f7f27d1..b1fb823bed 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 4a7c9a1256..6edb948d66 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 aaecc2ceba..23f862bb4b 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 26c6a8aaf3..6e14be6737 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 b3ea2a9d5f..f1edb8092a 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 db46210b8c..715d13621b 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 9931b4dcd7..7752258f2a 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" + "}" ));