Merge pull request #1981 from stianst/master
KEYCLOAK-2247 Upgrade to WildFly 10.0.0.CR5
This commit is contained in:
commit
084873f7fb
36 changed files with 1511 additions and 387 deletions
10
.travis.yml
10
.travis.yml
|
@ -1,10 +1,18 @@
|
||||||
language: java
|
language: java
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- MAVEN_SKIP_RC=true
|
||||||
|
- MAVEN_OPTS="-Xms512m -Xmx2048m"
|
||||||
|
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8
|
- oraclejdk8
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export MAVEN_SKIP_RC=true
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- travis_wait mvn install -Pdistribution -DskipTests=true -B -V -q
|
- mvn install -Pdistribution -DskipTests=true -B -V -q
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- mvn test -B
|
- mvn test -B
|
||||||
|
|
|
@ -1,4 +1,26 @@
|
||||||
<build xmlns="urn:wildfly:feature-pack-build:1.0">
|
<!--
|
||||||
|
~ JBoss, Home of Professional Open Source.
|
||||||
|
~ Copyright 2014, Red Hat, Inc., and individual contributors
|
||||||
|
~ as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
~ distribution for a full listing of individual contributors.
|
||||||
|
~
|
||||||
|
~ This is free software; you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU Lesser General Public License as
|
||||||
|
~ published by the Free Software Foundation; either version 2.1 of
|
||||||
|
~ the License, or (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This software is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
~ Lesser General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public
|
||||||
|
~ License along with this software; if not, write to the Free
|
||||||
|
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<build xmlns="urn:wildfly:feature-pack-build:1.1">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<artifact name="org.wildfly:wildfly-feature-pack" />
|
<artifact name="org.wildfly:wildfly-feature-pack" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -8,20 +30,31 @@
|
||||||
<property name="jgroups.supplement" value="" />
|
<property name="jgroups.supplement" value="" />
|
||||||
</standalone>
|
</standalone>
|
||||||
<domain template="configuration/domain/template.xml" subsystems="configuration/domain/subsystems.xml" output-file="domain/configuration/domain.xml" />
|
<domain template="configuration/domain/template.xml" subsystems="configuration/domain/subsystems.xml" output-file="domain/configuration/domain.xml" />
|
||||||
|
<host template="configuration/host/host.xml" subsystems="configuration/host/subsystems.xml" output-file="domain/configuration/host.xml" />
|
||||||
|
<host template="configuration/host/host-master.xml" subsystems="configuration/host/subsystems.xml" output-file="domain/configuration/host-master.xml" />
|
||||||
|
<host template="configuration/host/host-slave.xml" subsystems="configuration/host/subsystems.xml" output-file="domain/configuration/host-slave.xml" />
|
||||||
</config>
|
</config>
|
||||||
|
|
||||||
<mkdirs>
|
<mkdirs>
|
||||||
|
<dir name="domain/data/content"/>
|
||||||
|
<dir name="standalone/lib/ext"/>
|
||||||
|
<dir name="domain/tmp/auth"/>
|
||||||
|
<dir name="standalone/tmp/auth"/>
|
||||||
|
<dir name=".installation"/>
|
||||||
</mkdirs>
|
</mkdirs>
|
||||||
<file-permissions>
|
<file-permissions>
|
||||||
<permission value="755">
|
<permission value="755">
|
||||||
<filter pattern="*.sh" include="true"/>
|
<filter pattern="*.sh" include="true"/>
|
||||||
|
<filter pattern="*" include="false"/>
|
||||||
</permission>
|
</permission>
|
||||||
<permission value="700">
|
<permission value="700">
|
||||||
<filter pattern="*/tmp/auth" include="true"/>
|
<filter pattern="*/tmp/auth" include="true"/>
|
||||||
|
<filter pattern="*" include="false"/>
|
||||||
</permission>
|
</permission>
|
||||||
<permission value="600">
|
<permission value="600">
|
||||||
<filter pattern="*-users.properties" include="true" />
|
<filter pattern="*-users.properties" include="true" />
|
||||||
<filter pattern="*/.installation" include="true"/>
|
<filter pattern="*/.installation" include="true"/>
|
||||||
|
<filter pattern="*" include="false"/>
|
||||||
</permission>
|
</permission>
|
||||||
</file-permissions>
|
</file-permissions>
|
||||||
<line-endings>
|
<line-endings>
|
||||||
|
@ -33,4 +66,4 @@
|
||||||
<filter pattern="*.conf" include="true"/>
|
<filter pattern="*.conf" include="true"/>
|
||||||
</unix>
|
</unix>
|
||||||
</line-endings>
|
</line-endings>
|
||||||
</build>
|
</build>
|
||||||
|
|
|
@ -53,63 +53,4 @@
|
||||||
<subsystem supplement="ha">undertow.xml</subsystem>
|
<subsystem supplement="ha">undertow.xml</subsystem>
|
||||||
<subsystem>keycloak-server.xml</subsystem>
|
<subsystem>keycloak-server.xml</subsystem>
|
||||||
</subsystems>
|
</subsystems>
|
||||||
<subsystems name="full">
|
|
||||||
<!-- Each subsystem to be included relative to the src/main/resources directory -->
|
|
||||||
<subsystem>logging.xml</subsystem>
|
|
||||||
<subsystem>bean-validation.xml</subsystem>
|
|
||||||
<subsystem>keycloak-datasources.xml</subsystem>
|
|
||||||
<subsystem supplement="full">ee.xml</subsystem>
|
|
||||||
<subsystem supplement="full">ejb3.xml</subsystem>
|
|
||||||
<subsystem>io.xml</subsystem>
|
|
||||||
<subsystem>keycloak-infinispan.xml</subsystem>
|
|
||||||
<subsystem>iiop-openjdk.xml</subsystem>
|
|
||||||
<subsystem>jaxrs.xml</subsystem>
|
|
||||||
<subsystem>jca.xml</subsystem>
|
|
||||||
<subsystem>jdr.xml</subsystem>
|
|
||||||
<subsystem supplement="domain">jmx.xml</subsystem>
|
|
||||||
<subsystem>jpa.xml</subsystem>
|
|
||||||
<subsystem>jsf.xml</subsystem>
|
|
||||||
<subsystem>jsr77.xml</subsystem>
|
|
||||||
<subsystem>mail.xml</subsystem>
|
|
||||||
<subsystem>messaging.xml</subsystem>
|
|
||||||
<subsystem>naming.xml</subsystem>
|
|
||||||
<subsystem>remoting.xml</subsystem>
|
|
||||||
<subsystem>request-controller.xml</subsystem>
|
|
||||||
<subsystem>security.xml</subsystem>
|
|
||||||
<subsystem>security-manager.xml</subsystem>
|
|
||||||
<subsystem>transactions.xml</subsystem>
|
|
||||||
<subsystem>undertow.xml</subsystem>
|
|
||||||
<subsystem>keycloak-server.xml</subsystem>
|
|
||||||
</subsystems>
|
|
||||||
<subsystems name="full-ha">
|
|
||||||
<!-- Each subsystem to be included relative to the src/main/resources directory -->
|
|
||||||
<subsystem>logging.xml</subsystem>
|
|
||||||
<subsystem>bean-validation.xml</subsystem>
|
|
||||||
<subsystem>keycloak-datasources.xml</subsystem>
|
|
||||||
<subsystem supplement="full">ee.xml</subsystem>
|
|
||||||
<subsystem supplement="full-ha">ejb3.xml</subsystem>
|
|
||||||
<subsystem>io.xml</subsystem>
|
|
||||||
<subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
|
|
||||||
<subsystem>iiop-openjdk.xml</subsystem>
|
|
||||||
<subsystem>jaxrs.xml</subsystem>
|
|
||||||
<subsystem>jca.xml</subsystem>
|
|
||||||
<subsystem>jdr.xml</subsystem>
|
|
||||||
<subsystem>jgroups.xml</subsystem>
|
|
||||||
<subsystem supplement="domain">jmx.xml</subsystem>
|
|
||||||
<subsystem>jpa.xml</subsystem>
|
|
||||||
<subsystem>jsf.xml</subsystem>
|
|
||||||
<subsystem>jsr77.xml</subsystem>
|
|
||||||
<subsystem>mail.xml</subsystem>
|
|
||||||
<subsystem supplement="ha">messaging.xml</subsystem>
|
|
||||||
<subsystem>mod_cluster.xml</subsystem>
|
|
||||||
<subsystem>naming.xml</subsystem>
|
|
||||||
<subsystem>remoting.xml</subsystem>
|
|
||||||
<subsystem>resource-adapters.xml</subsystem>
|
|
||||||
<subsystem>request-controller.xml</subsystem>
|
|
||||||
<subsystem>security.xml</subsystem>
|
|
||||||
<subsystem>security-manager.xml</subsystem>
|
|
||||||
<subsystem>transactions.xml</subsystem>
|
|
||||||
<subsystem supplement="ha">undertow.xml</subsystem>
|
|
||||||
<subsystem>keycloak-server.xml</subsystem>
|
|
||||||
</subsystems>
|
|
||||||
</config>
|
</config>
|
||||||
|
|
|
@ -24,18 +24,12 @@
|
||||||
</management>
|
</management>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile name="default">
|
<profile name="default">
|
||||||
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||||
</profile>
|
</profile>
|
||||||
<profile name="ha">
|
<profile name="ha">
|
||||||
<?SUBSYSTEMS socket-binding-group="ha-sockets"?>
|
<?SUBSYSTEMS socket-binding-group="ha-sockets"?>
|
||||||
</profile>
|
</profile>
|
||||||
<profile name="full">
|
|
||||||
<?SUBSYSTEMS socket-binding-group="full-sockets"?>
|
|
||||||
</profile>
|
|
||||||
<profile name="full-ha">
|
|
||||||
<?SUBSYSTEMS socket-binding-group="full-ha-sockets"?>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -60,28 +54,20 @@
|
||||||
<!-- Needed for server groups using the 'ha' profile -->
|
<!-- Needed for server groups using the 'ha' profile -->
|
||||||
<?SOCKET-BINDINGS?>
|
<?SOCKET-BINDINGS?>
|
||||||
</socket-binding-group>
|
</socket-binding-group>
|
||||||
<socket-binding-group name="full-sockets" default-interface="public">
|
|
||||||
<!-- Needed for server groups using the 'full' profile -->
|
|
||||||
<?SOCKET-BINDINGS?>
|
|
||||||
</socket-binding-group>
|
|
||||||
<socket-binding-group name="full-ha-sockets" default-interface="public">
|
|
||||||
<!-- Needed for server groups using the 'full-ha' profile -->
|
|
||||||
<?SOCKET-BINDINGS?>
|
|
||||||
</socket-binding-group>
|
|
||||||
</socket-binding-groups>
|
</socket-binding-groups>
|
||||||
|
|
||||||
<server-groups>
|
<server-groups>
|
||||||
<server-group name="main-server-group" profile="full">
|
<server-group name="main-server-group" profile="default">
|
||||||
<jvm name="default">
|
<jvm name="default">
|
||||||
<heap size="64m" max-size="512m"/>
|
<heap size="64m" max-size="512m"/>
|
||||||
</jvm>
|
</jvm>
|
||||||
<socket-binding-group ref="full-sockets"/>
|
<socket-binding-group ref="standard-sockets"/>
|
||||||
</server-group>
|
</server-group>
|
||||||
<server-group name="other-server-group" profile="full-ha">
|
<server-group name="other-server-group" profile="ha">
|
||||||
<jvm name="default">
|
<jvm name="default">
|
||||||
<heap size="64m" max-size="512m"/>
|
<heap size="64m" max-size="512m"/>
|
||||||
</jvm>
|
</jvm>
|
||||||
<socket-binding-group ref="full-ha-sockets"/>
|
<socket-binding-group ref="ha-sockets"/>
|
||||||
</server-group>
|
</server-group>
|
||||||
</server-groups>
|
</server-groups>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
A simple configuration for a Host Controller that only acts as the master domain controller
|
||||||
|
and does not itself directly control any servers.
|
||||||
|
-->
|
||||||
|
<host name="master" xmlns="urn:jboss:domain:4.0">
|
||||||
|
<extensions>
|
||||||
|
<?EXTENSIONS?>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<management>
|
||||||
|
<security-realms>
|
||||||
|
<security-realm name="ManagementRealm">
|
||||||
|
<authentication>
|
||||||
|
<local default-user="$local" skip-group-loading="true"/>
|
||||||
|
<properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authentication>
|
||||||
|
<authorization map-groups-to-roles="false">
|
||||||
|
<properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authorization>
|
||||||
|
</security-realm>
|
||||||
|
<security-realm name="ApplicationRealm">
|
||||||
|
<authentication>
|
||||||
|
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
|
||||||
|
<properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authentication>
|
||||||
|
<authorization>
|
||||||
|
<properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authorization>
|
||||||
|
</security-realm>
|
||||||
|
</security-realms>
|
||||||
|
<audit-log>
|
||||||
|
<formatters>
|
||||||
|
<json-formatter name="json-formatter"/>
|
||||||
|
</formatters>
|
||||||
|
<handlers>
|
||||||
|
<file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
|
||||||
|
<file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||||
|
</handlers>
|
||||||
|
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="host-file"/>
|
||||||
|
</handlers>
|
||||||
|
</logger>
|
||||||
|
<server-logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="server-file"/>
|
||||||
|
</handlers>
|
||||||
|
</server-logger>
|
||||||
|
</audit-log>
|
||||||
|
<management-interfaces>
|
||||||
|
<native-interface security-realm="ManagementRealm">
|
||||||
|
<socket interface="management" port="${jboss.management.native.port:9999}"/>
|
||||||
|
</native-interface>
|
||||||
|
<http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
|
||||||
|
<socket interface="management" port="${jboss.management.http.port:9990}"/>
|
||||||
|
</http-interface>
|
||||||
|
</management-interfaces>
|
||||||
|
</management>
|
||||||
|
|
||||||
|
<domain-controller>
|
||||||
|
<local/>
|
||||||
|
</domain-controller>
|
||||||
|
|
||||||
|
<interfaces>
|
||||||
|
<interface name="management">
|
||||||
|
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
|
||||||
|
<jvms>
|
||||||
|
<jvm name="default">
|
||||||
|
<heap size="64m" max-size="256m"/>
|
||||||
|
<jvm-options>
|
||||||
|
<option value="-server"/>
|
||||||
|
</jvm-options>
|
||||||
|
</jvm>
|
||||||
|
</jvms>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
</host>
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<host xmlns="urn:jboss:domain:4.0">
|
||||||
|
<extensions>
|
||||||
|
<?EXTENSIONS?>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<management>
|
||||||
|
<security-realms>
|
||||||
|
<security-realm name="ManagementRealm">
|
||||||
|
<server-identities>
|
||||||
|
<!-- Replace this with either a base64 password of your own, or use a vault with a vault expression -->
|
||||||
|
<secret value="c2xhdmVfdXNlcl9wYXNzd29yZA=="/>
|
||||||
|
</server-identities>
|
||||||
|
|
||||||
|
<authentication>
|
||||||
|
<local default-user="$local" skip-group-loading="true"/>
|
||||||
|
<properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authentication>
|
||||||
|
<authorization map-groups-to-roles="false">
|
||||||
|
<properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authorization>
|
||||||
|
</security-realm>
|
||||||
|
<security-realm name="ApplicationRealm">
|
||||||
|
<authentication>
|
||||||
|
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
|
||||||
|
<properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authentication>
|
||||||
|
<authorization>
|
||||||
|
<properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authorization>
|
||||||
|
</security-realm>
|
||||||
|
</security-realms>
|
||||||
|
<audit-log>
|
||||||
|
<formatters>
|
||||||
|
<json-formatter name="json-formatter"/>
|
||||||
|
</formatters>
|
||||||
|
<handlers>
|
||||||
|
<file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
|
||||||
|
<file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||||
|
</handlers>
|
||||||
|
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="host-file"/>
|
||||||
|
</handlers>
|
||||||
|
</logger>
|
||||||
|
<server-logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="server-file"/>
|
||||||
|
</handlers>
|
||||||
|
</server-logger>
|
||||||
|
</audit-log>
|
||||||
|
<management-interfaces>
|
||||||
|
<native-interface security-realm="ManagementRealm">
|
||||||
|
<socket interface="management" port="${jboss.management.native.port:9999}"/>
|
||||||
|
</native-interface>
|
||||||
|
</management-interfaces>
|
||||||
|
</management>
|
||||||
|
|
||||||
|
<domain-controller>
|
||||||
|
<remote security-realm="ManagementRealm">
|
||||||
|
<discovery-options>
|
||||||
|
<static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote}" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9999}"/>
|
||||||
|
</discovery-options>
|
||||||
|
</remote>
|
||||||
|
</domain-controller>
|
||||||
|
|
||||||
|
<interfaces>
|
||||||
|
<interface name="management">
|
||||||
|
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||||
|
</interface>
|
||||||
|
<interface name="public">
|
||||||
|
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<?INTERFACES?>
|
||||||
|
|
||||||
|
</interfaces>
|
||||||
|
|
||||||
|
<jvms>
|
||||||
|
<jvm name="default">
|
||||||
|
<heap size="64m" max-size="256m"/>
|
||||||
|
<jvm-options>
|
||||||
|
<option value="-server"/>
|
||||||
|
</jvm-options>
|
||||||
|
</jvm>
|
||||||
|
</jvms>
|
||||||
|
|
||||||
|
<servers>
|
||||||
|
<server name="server-one" group="main-server-group"/>
|
||||||
|
<server name="server-two" group="other-server-group">
|
||||||
|
<!-- server-two avoids port conflicts by incrementing the ports in
|
||||||
|
the default socket-group declared in the server-group -->
|
||||||
|
<socket-bindings port-offset="150"/>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||||
|
</profile>
|
||||||
|
</host>
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<host name="master" xmlns="urn:jboss:domain:4.0">
|
||||||
|
<extensions>
|
||||||
|
<?EXTENSIONS?>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<management>
|
||||||
|
<security-realms>
|
||||||
|
<security-realm name="ManagementRealm">
|
||||||
|
<authentication>
|
||||||
|
<local default-user="$local" skip-group-loading="true"/>
|
||||||
|
<properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authentication>
|
||||||
|
<authorization map-groups-to-roles="false">
|
||||||
|
<properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authorization>
|
||||||
|
</security-realm>
|
||||||
|
<security-realm name="ApplicationRealm">
|
||||||
|
<authentication>
|
||||||
|
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
|
||||||
|
<properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authentication>
|
||||||
|
<authorization>
|
||||||
|
<properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
|
||||||
|
</authorization>
|
||||||
|
</security-realm>
|
||||||
|
</security-realms>
|
||||||
|
<audit-log>
|
||||||
|
<formatters>
|
||||||
|
<json-formatter name="json-formatter"/>
|
||||||
|
</formatters>
|
||||||
|
<handlers>
|
||||||
|
<file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
|
||||||
|
<file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||||
|
</handlers>
|
||||||
|
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="host-file"/>
|
||||||
|
</handlers>
|
||||||
|
</logger>
|
||||||
|
<server-logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="server-file"/>
|
||||||
|
</handlers>
|
||||||
|
</server-logger>
|
||||||
|
</audit-log>
|
||||||
|
<management-interfaces>
|
||||||
|
<native-interface security-realm="ManagementRealm">
|
||||||
|
<socket interface="management" port="${jboss.management.native.port:9999}"/>
|
||||||
|
</native-interface>
|
||||||
|
<http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
|
||||||
|
<socket interface="management" port="${jboss.management.http.port:9990}"/>
|
||||||
|
</http-interface>
|
||||||
|
</management-interfaces>
|
||||||
|
</management>
|
||||||
|
|
||||||
|
<domain-controller>
|
||||||
|
<local/>
|
||||||
|
<!-- Alternative remote domain controller configuration with a host and port -->
|
||||||
|
<!-- <remote protocol="remote" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9999}" security-realm="ManagementRealm"/> -->
|
||||||
|
</domain-controller>
|
||||||
|
|
||||||
|
<interfaces>
|
||||||
|
<interface name="management">
|
||||||
|
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||||
|
</interface>
|
||||||
|
<interface name="public">
|
||||||
|
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<?INTERFACES?>
|
||||||
|
|
||||||
|
</interfaces>
|
||||||
|
|
||||||
|
<jvms>
|
||||||
|
<jvm name="default">
|
||||||
|
<heap size="64m" max-size="256m"/>
|
||||||
|
<jvm-options>
|
||||||
|
<option value="-server"/>
|
||||||
|
</jvm-options>
|
||||||
|
</jvm>
|
||||||
|
</jvms>
|
||||||
|
|
||||||
|
<servers>
|
||||||
|
<server name="server-one" group="main-server-group">
|
||||||
|
<!-- Remote JPDA debugging for a specific server
|
||||||
|
<jvm name="default">
|
||||||
|
<jvm-options>
|
||||||
|
<option value="-agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n"/>
|
||||||
|
</jvm-options>
|
||||||
|
</jvm>
|
||||||
|
-->
|
||||||
|
</server>
|
||||||
|
<server name="server-two" group="main-server-group" auto-start="true">
|
||||||
|
<!-- server-two avoids port conflicts by incrementing the ports in
|
||||||
|
the default socket-group declared in the server-group -->
|
||||||
|
<socket-bindings port-offset="150"/>
|
||||||
|
</server>
|
||||||
|
<server name="server-three" group="other-server-group" auto-start="false">
|
||||||
|
<!-- server-three avoids port conflicts by incrementing the ports in
|
||||||
|
the default socket-group declared in the server-group -->
|
||||||
|
<socket-bindings port-offset="250"/>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||||
|
</profile>
|
||||||
|
</host>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<!--
|
||||||
|
~ JBoss, Home of Professional Open Source.
|
||||||
|
~ Copyright 2015, Red Hat, Inc., and individual contributors
|
||||||
|
~ as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
~ distribution for a full listing of individual contributors.
|
||||||
|
~
|
||||||
|
~ This is free software; you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU Lesser General Public License as
|
||||||
|
~ published by the Free Software Foundation; either version 2.1 of
|
||||||
|
~ the License, or (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This software is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
~ Lesser General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public
|
||||||
|
~ License along with this software; if not, write to the Free
|
||||||
|
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
|
||||||
|
<config>
|
||||||
|
<subsystems>
|
||||||
|
<subsystem>jmx.xml</subsystem>
|
||||||
|
</subsystems>
|
||||||
|
</config>
|
|
@ -1,30 +1,30 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
|
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
|
||||||
<config>
|
<config>
|
||||||
<subsystems>
|
<subsystems>
|
||||||
<subsystem>logging.xml</subsystem>
|
<subsystem>logging.xml</subsystem>
|
||||||
<subsystem>bean-validation.xml</subsystem>
|
<subsystem>bean-validation.xml</subsystem>
|
||||||
<subsystem>keycloak-datasources.xml</subsystem>
|
<subsystem>keycloak-datasources.xml</subsystem>
|
||||||
<subsystem>ee.xml</subsystem>
|
<subsystem>ee.xml</subsystem>
|
||||||
<subsystem supplement="ha">ejb3.xml</subsystem>
|
<subsystem supplement="ha">ejb3.xml</subsystem>
|
||||||
<subsystem>io.xml</subsystem>
|
<subsystem>io.xml</subsystem>
|
||||||
<subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
|
<subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
|
||||||
<subsystem>jaxrs.xml</subsystem>
|
<subsystem>jaxrs.xml</subsystem>
|
||||||
<subsystem>jca.xml</subsystem>
|
<subsystem>jca.xml</subsystem>
|
||||||
<subsystem>jdr.xml</subsystem>
|
<subsystem>jdr.xml</subsystem>
|
||||||
<subsystem>jgroups.xml</subsystem>
|
<subsystem>jgroups.xml</subsystem>
|
||||||
<subsystem>jmx.xml</subsystem>
|
<subsystem>jmx.xml</subsystem>
|
||||||
<subsystem>jpa.xml</subsystem>
|
<subsystem>jpa.xml</subsystem>
|
||||||
<subsystem>jsf.xml</subsystem>
|
<subsystem>jsf.xml</subsystem>
|
||||||
<subsystem>mail.xml</subsystem>
|
<subsystem>mail.xml</subsystem>
|
||||||
<subsystem>mod_cluster.xml</subsystem>
|
<subsystem>mod_cluster.xml</subsystem>
|
||||||
<subsystem>naming.xml</subsystem>
|
<subsystem>naming.xml</subsystem>
|
||||||
<subsystem>remoting.xml</subsystem>
|
<subsystem>remoting.xml</subsystem>
|
||||||
<subsystem>request-controller.xml</subsystem>
|
<subsystem>request-controller.xml</subsystem>
|
||||||
<subsystem>security-manager.xml</subsystem>
|
<subsystem>security-manager.xml</subsystem>
|
||||||
<subsystem>security.xml</subsystem>
|
<subsystem>security.xml</subsystem>
|
||||||
<subsystem>transactions.xml</subsystem>
|
<subsystem>transactions.xml</subsystem>
|
||||||
<subsystem supplement="ha">undertow.xml</subsystem>
|
<subsystem supplement="ha">undertow.xml</subsystem>
|
||||||
<subsystem>keycloak-server.xml</subsystem>
|
<subsystem>keycloak-server.xml</subsystem>
|
||||||
</subsystems>
|
</subsystems>
|
||||||
</config>
|
</config>
|
|
@ -29,15 +29,15 @@
|
||||||
</security-realms>
|
</security-realms>
|
||||||
<audit-log>
|
<audit-log>
|
||||||
<formatters>
|
<formatters>
|
||||||
<json-formatter name="json-formatter"/>
|
<json-formatter name="json-formatter"/>
|
||||||
</formatters>
|
</formatters>
|
||||||
<handlers>
|
<handlers>
|
||||||
<file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
<file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||||
</handlers>
|
</handlers>
|
||||||
<logger log-boot="true" log-read-only="false" enabled="false">
|
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
<handlers>
|
<handlers>
|
||||||
<handler name="file"/>
|
<handler name="file"/>
|
||||||
</handlers>
|
</handlers>
|
||||||
</logger>
|
</logger>
|
||||||
</audit-log>
|
</audit-log>
|
||||||
<management-interfaces>
|
<management-interfaces>
|
||||||
|
@ -69,8 +69,9 @@
|
||||||
<interface name="public">
|
<interface name="public">
|
||||||
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||||
</interface>
|
</interface>
|
||||||
<!-- TODO - only show this if the jacorb subsystem is added -->
|
|
||||||
<?INTERFACES?>
|
<?INTERFACES?>
|
||||||
|
|
||||||
</interfaces>
|
</interfaces>
|
||||||
|
|
||||||
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
|
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
|
||||||
|
@ -80,4 +81,4 @@
|
||||||
<?SOCKET-BINDINGS?>
|
<?SOCKET-BINDINGS?>
|
||||||
|
|
||||||
</socket-binding-group>
|
</socket-binding-group>
|
||||||
</server>
|
</server>
|
||||||
|
|
|
@ -23,14 +23,12 @@ public interface UserSessionProvider extends Provider {
|
||||||
List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId);
|
List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId);
|
||||||
UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId);
|
UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId);
|
||||||
|
|
||||||
List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue);
|
long getActiveUserSessions(RealmModel realm, ClientModel client);
|
||||||
|
|
||||||
int getActiveUserSessions(RealmModel realm, ClientModel client);
|
|
||||||
void removeUserSession(RealmModel realm, UserSessionModel session);
|
void removeUserSession(RealmModel realm, UserSessionModel session);
|
||||||
void removeUserSessions(RealmModel realm, UserModel user);
|
void removeUserSessions(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
// Implementation should propagate removal of expired userSessions to userSessionPersister too
|
// Implementation should propagate removal of expired userSessions to userSessionPersister too
|
||||||
void removeExpiredUserSessions(RealmModel realm);
|
void removeExpired(RealmModel realm);
|
||||||
void removeUserSessions(RealmModel realm);
|
void removeUserSessions(RealmModel realm);
|
||||||
void removeClientSession(RealmModel realm, ClientSessionModel clientSession);
|
void removeClientSession(RealmModel realm, ClientSessionModel clientSession);
|
||||||
|
|
||||||
|
@ -56,7 +54,7 @@ public interface UserSessionProvider extends Provider {
|
||||||
// Don't remove userSession even if it's last userSession
|
// Don't remove userSession even if it's last userSession
|
||||||
void removeOfflineClientSession(RealmModel realm, String clientSessionId);
|
void removeOfflineClientSession(RealmModel realm, String clientSessionId);
|
||||||
|
|
||||||
int getOfflineSessionsCount(RealmModel realm, ClientModel client);
|
long getOfflineSessionsCount(RealmModel realm, ClientModel client);
|
||||||
List<UserSessionModel> getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max);
|
List<UserSessionModel> getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max);
|
||||||
|
|
||||||
// Triggered by persister during pre-load
|
// Triggered by persister during pre-load
|
||||||
|
|
|
@ -0,0 +1,387 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan;
|
||||||
|
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.distexec.mapreduce.MapReduceTask;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
|
import org.keycloak.models.*;
|
||||||
|
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.*;
|
||||||
|
import org.keycloak.models.sessions.infinispan.mapreduce.*;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.models.utils.RealmInfoUtil;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class CompatInfinispanUserSessionProvider extends InfinispanUserSessionProvider {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(CompatInfinispanUserSessionProvider.class);
|
||||||
|
|
||||||
|
public CompatInfinispanUserSessionProvider(KeycloakSession session, Cache<String, SessionEntity> sessionCache, Cache<String, SessionEntity> offlineSessionCache,
|
||||||
|
Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache) {
|
||||||
|
super(session, sessionCache, offlineSessionCache, loginFailureCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserSessionModel> getUserSessions(RealmModel realm, UserModel user) {
|
||||||
|
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
return wrapUserSessions(realm, sessions.values(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
|
||||||
|
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).brokerUserId(brokerUserId))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
return wrapUserSessions(realm, sessions.values(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
|
||||||
|
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).brokerSessionId(brokerSessionId))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
List<UserSessionModel> userSessionModels = wrapUserSessions(realm, sessions.values(), false);
|
||||||
|
if (userSessionModels.isEmpty()) return null;
|
||||||
|
return userSessionModels.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
|
||||||
|
return getUserSessions(realm, client, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults) {
|
||||||
|
return getUserSessions(realm, client, firstResult, maxResults, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
Map<String, Integer> map = new MapReduceTask(cache)
|
||||||
|
.mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
|
||||||
|
.reducedWith(new LargestResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
List<Map.Entry<String, Integer>> sessionTimestamps = new LinkedList<Map.Entry<String, Integer>>(map.entrySet());
|
||||||
|
|
||||||
|
Collections.sort(sessionTimestamps, new Comparator<Map.Entry<String, Integer>>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
|
||||||
|
return e1.getValue().compareTo(e2.getValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (firstResult != -1 || maxResults == -1) {
|
||||||
|
if (firstResult == -1) {
|
||||||
|
firstResult = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxResults == -1) {
|
||||||
|
maxResults = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstResult > sessionTimestamps.size()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
int toIndex = (firstResult + maxResults) < sessionTimestamps.size() ? firstResult + maxResults : sessionTimestamps.size();
|
||||||
|
sessionTimestamps = sessionTimestamps.subList(firstResult, toIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
|
||||||
|
for (Map.Entry<String, Integer> e : sessionTimestamps) {
|
||||||
|
UserSessionEntity userSessionEntity = (UserSessionEntity) cache.get(e.getKey());
|
||||||
|
if (userSessionEntity != null) {
|
||||||
|
userSessions.add(wrap(realm, userSessionEntity, offline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userSessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getActiveUserSessions(RealmModel realm, ClientModel client) {
|
||||||
|
return getUserSessionsCount(realm, client, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
Map map = new MapReduceTask(cache)
|
||||||
|
.mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
|
||||||
|
.reducedWith(new LargestResultReducer()).execute();
|
||||||
|
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUserSession(RealmModel realm, UserSessionModel session) {
|
||||||
|
removeUserSession(realm, session.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUserSessions(RealmModel realm, UserModel user) {
|
||||||
|
removeUserSessions(realm, user, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
Map<String, String> sessions = new MapReduceTask(cache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String id : sessions.keySet()) {
|
||||||
|
removeUserSession(realm, id, offline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeExpired(RealmModel realm) {
|
||||||
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
|
|
||||||
|
int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan();
|
||||||
|
int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout();
|
||||||
|
int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
|
||||||
|
int expiredDettachedClientSession = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
|
||||||
|
|
||||||
|
Map<String, String> map = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).expired(expired, expiredRefresh).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String id : map.keySet()) {
|
||||||
|
removeUserSession(realm, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
map = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession(true).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String id : map.keySet()) {
|
||||||
|
tx.remove(sessionCache, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expired offline user sessions
|
||||||
|
Map<String, SessionEntity> map2 = new MapReduceTask(offlineSessionCache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).expired(null, expiredOffline))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (Map.Entry<String, SessionEntity> entry : map2.entrySet()) {
|
||||||
|
String userSessionId = entry.getKey();
|
||||||
|
tx.remove(offlineSessionCache, userSessionId);
|
||||||
|
// Propagate to persister
|
||||||
|
persister.removeUserSession(userSessionId, true);
|
||||||
|
|
||||||
|
UserSessionEntity entity = (UserSessionEntity) entry.getValue();
|
||||||
|
for (String clientSessionId : entity.getClientSessions()) {
|
||||||
|
tx.remove(offlineSessionCache, clientSessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expired offline client sessions
|
||||||
|
map = new MapReduceTask(offlineSessionCache)
|
||||||
|
.mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredOffline).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String clientSessionId : map.keySet()) {
|
||||||
|
tx.remove(offlineSessionCache, clientSessionId);
|
||||||
|
persister.removeClientSession(clientSessionId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expired client initial access
|
||||||
|
map = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(ClientInitialAccessMapper.create(realm.getId()).expired(Time.currentTime()).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String id : map.keySet()) {
|
||||||
|
tx.remove(sessionCache, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUserSessions(RealmModel realm) {
|
||||||
|
removeUserSessions(realm, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeUserSessions(RealmModel realm, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
Map<String, String> ids = new MapReduceTask(cache)
|
||||||
|
.mappedWith(SessionMapper.create(realm.getId()).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String id : ids.keySet()) {
|
||||||
|
cache.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUserLoginFailure(RealmModel realm, String username) {
|
||||||
|
LoginFailureKey key = new LoginFailureKey(realm.getId(), username);
|
||||||
|
tx.remove(loginFailureCache, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAllUserLoginFailures(RealmModel realm) {
|
||||||
|
Map<LoginFailureKey, Object> sessions = new MapReduceTask(loginFailureCache)
|
||||||
|
.mappedWith(UserLoginFailureMapper.create(realm.getId()).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (LoginFailureKey id : sessions.keySet()) {
|
||||||
|
tx.remove(loginFailureCache, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRealmRemoved(RealmModel realm) {
|
||||||
|
removeUserSessions(realm, true);
|
||||||
|
removeUserSessions(realm, false);
|
||||||
|
removeAllUserLoginFailures(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClientRemoved(RealmModel realm, ClientModel client) {
|
||||||
|
onClientRemoved(realm, client, true);
|
||||||
|
onClientRemoved(realm, client, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClientRemoved(RealmModel realm, ClientModel client, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
Map<String, ClientSessionEntity> map = new MapReduceTask(cache)
|
||||||
|
.mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (Map.Entry<String, ClientSessionEntity> entry : map.entrySet()) {
|
||||||
|
|
||||||
|
// detach from userSession
|
||||||
|
ClientSessionAdapter adapter = wrap(realm, entry.getValue(), offline);
|
||||||
|
adapter.setUserSession(null);
|
||||||
|
|
||||||
|
tx.remove(cache, entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUserRemoved(RealmModel realm, UserModel user) {
|
||||||
|
removeUserSessions(realm, user, true);
|
||||||
|
removeUserSessions(realm, user, false);
|
||||||
|
|
||||||
|
loginFailureCache.remove(new LoginFailureKey(realm.getId(), user.getUsername()));
|
||||||
|
loginFailureCache.remove(new LoginFailureKey(realm.getId(), user.getEmail()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
|
||||||
|
removeClientSession(realm, clientSession, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeClientSession(RealmModel realm, ClientSessionModel clientSession, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
UserSessionModel userSession = clientSession.getUserSession();
|
||||||
|
if (userSession != null) {
|
||||||
|
UserSessionEntity entity = ((UserSessionAdapter) userSession).getEntity();
|
||||||
|
if (entity.getClientSessions() != null) {
|
||||||
|
entity.getClientSessions().remove(clientSession.getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
tx.replace(cache, entity.getId(), entity);
|
||||||
|
}
|
||||||
|
tx.remove(cache, clientSession.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeUserSession(RealmModel realm, String userSessionId) {
|
||||||
|
removeUserSession(realm, userSessionId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeUserSession(RealmModel realm, String userSessionId, boolean offline) {
|
||||||
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
|
tx.remove(cache, userSessionId);
|
||||||
|
|
||||||
|
// TODO: Isn't more effective to retrieve from userSessionEntity directly?
|
||||||
|
Map<String, String> map = new MapReduceTask(cache)
|
||||||
|
.mappedWith(ClientSessionMapper.create(realm.getId()).userSession(userSessionId).emitKey())
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (String id : map.keySet()) {
|
||||||
|
tx.remove(cache, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeOfflineUserSession(RealmModel realm, String userSessionId) {
|
||||||
|
removeUserSession(realm, userSessionId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ClientSessionModel> getOfflineClientSessions(RealmModel realm, UserModel user) {
|
||||||
|
Map<String, UserSessionEntity> sessions = new MapReduceTask(offlineSessionCache)
|
||||||
|
.mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
List<ClientSessionEntity> clientSessions = new LinkedList<>();
|
||||||
|
for (UserSessionEntity userSession : sessions.values()) {
|
||||||
|
Set<String> currClientSessions = userSession.getClientSessions();
|
||||||
|
for (String clientSessionId : currClientSessions) {
|
||||||
|
ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId);
|
||||||
|
if (cls != null) {
|
||||||
|
clientSessions.add(cls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapClientSessions(realm, clientSessions, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeOfflineClientSession(RealmModel realm, String clientSessionId) {
|
||||||
|
ClientSessionModel clientSession = getOfflineClientSession(realm, clientSessionId);
|
||||||
|
removeClientSession(realm, clientSession, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getOfflineSessionsCount(RealmModel realm, ClientModel client) {
|
||||||
|
return getUserSessionsCount(realm, client, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserSessionModel> getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max) {
|
||||||
|
return getUserSessions(realm, client, first, max, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
|
||||||
|
Map<String, ClientInitialAccessEntity> entities = new MapReduceTask(sessionCache)
|
||||||
|
.mappedWith(ClientInitialAccessMapper.create(realm.getId()))
|
||||||
|
.reducedWith(new FirstResultReducer())
|
||||||
|
.execute();
|
||||||
|
return wrapClientInitialAccess(realm, entities.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Consumers {
|
||||||
|
|
||||||
|
private Consumers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserSessionModelsConsumer userSessionModels(InfinispanUserSessionProvider provider, RealmModel realm, boolean offline) {
|
||||||
|
return new UserSessionModelsConsumer(provider, realm, offline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UserSessionIdAndTimestampConsumer implements Consumer<Map.Entry<String, SessionEntity>> {
|
||||||
|
|
||||||
|
private Map<String, Integer> sessions = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
if (e instanceof ClientSessionEntity) {
|
||||||
|
ClientSessionEntity ce = (ClientSessionEntity) e;
|
||||||
|
sessions.put(ce.getUserSession(), ce.getTimestamp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UserSessionModelsConsumer implements Consumer<Map.Entry<String, SessionEntity>> {
|
||||||
|
|
||||||
|
private InfinispanUserSessionProvider provider;
|
||||||
|
private RealmModel realm;
|
||||||
|
private boolean offline;
|
||||||
|
private List<UserSessionModel> sessions = new LinkedList<>();
|
||||||
|
|
||||||
|
private UserSessionModelsConsumer(InfinispanUserSessionProvider provider, RealmModel realm, boolean offline) {
|
||||||
|
this.provider = provider;
|
||||||
|
this.realm = realm;
|
||||||
|
this.offline = offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
sessions.add(provider.wrap(realm, (UserSessionEntity) e, offline));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UserSessionModel> getSessions() {
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,21 @@
|
||||||
package org.keycloak.models.sessions.infinispan;
|
package org.keycloak.models.sessions.infinispan;
|
||||||
|
|
||||||
import org.infinispan.Cache;
|
import org.infinispan.Cache;
|
||||||
import org.infinispan.distexec.mapreduce.MapReduceTask;
|
import org.infinispan.CacheStream;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.models.*;
|
import org.keycloak.models.*;
|
||||||
import org.keycloak.models.session.UserSessionPersisterProvider;
|
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||||
import org.keycloak.models.sessions.infinispan.entities.*;
|
import org.keycloak.models.sessions.infinispan.entities.*;
|
||||||
import org.keycloak.models.sessions.infinispan.mapreduce.*;
|
import org.keycloak.models.sessions.infinispan.stream.*;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.RealmInfoUtil;
|
import org.keycloak.models.utils.RealmInfoUtil;
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
import java.util.function.Consumer;
|
||||||
import java.util.Comparator;
|
import java.util.function.Predicate;
|
||||||
import java.util.HashMap;
|
import java.util.stream.Collectors;
|
||||||
import java.util.HashSet;
|
import java.util.stream.Stream;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -28,11 +24,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(InfinispanUserSessionProvider.class);
|
private static final Logger log = Logger.getLogger(InfinispanUserSessionProvider.class);
|
||||||
|
|
||||||
private final KeycloakSession session;
|
protected final KeycloakSession session;
|
||||||
private final Cache<String, SessionEntity> sessionCache;
|
protected final Cache<String, SessionEntity> sessionCache;
|
||||||
private final Cache<String, SessionEntity> offlineSessionCache;
|
protected final Cache<String, SessionEntity> offlineSessionCache;
|
||||||
private final Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache;
|
protected final Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache;
|
||||||
private final InfinispanKeycloakTransaction tx;
|
protected final InfinispanKeycloakTransaction tx;
|
||||||
|
|
||||||
public InfinispanUserSessionProvider(KeycloakSession session, Cache<String, SessionEntity> sessionCache, Cache<String, SessionEntity> offlineSessionCache,
|
public InfinispanUserSessionProvider(KeycloakSession session, Cache<String, SessionEntity> sessionCache, Cache<String, SessionEntity> offlineSessionCache,
|
||||||
Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache) {
|
Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache) {
|
||||||
|
@ -139,36 +135,31 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
return wrap(realm, entity, offline);
|
return wrap(realm, entity, offline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected List<UserSessionModel> getUserSessions(RealmModel realm, Predicate<Map.Entry<String, SessionEntity>> predicate, boolean offline) {
|
||||||
public List<UserSessionModel> getUserSessions(RealmModel realm, UserModel user) {
|
CacheStream<Map.Entry<String, SessionEntity>> cacheStream = getCache(offline).entrySet().stream();
|
||||||
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
Iterator<Map.Entry<String, SessionEntity>> itr = cacheStream.filter(predicate).iterator();
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
|
List<UserSessionModel> sessions = new LinkedList<>();
|
||||||
.reducedWith(new FirstResultReducer())
|
while (itr.hasNext()) {
|
||||||
.execute();
|
UserSessionEntity e = (UserSessionEntity) itr.next().getValue();
|
||||||
|
sessions.add(wrap(realm, e, offline));
|
||||||
|
}
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
|
|
||||||
return wrapUserSessions(realm, sessions.values(), false);
|
@Override
|
||||||
|
public List<UserSessionModel> getUserSessions(final RealmModel realm, UserModel user) {
|
||||||
|
return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).user(user.getId()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
|
public List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
|
||||||
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerUserId(brokerUserId), false);
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).brokerUserId(brokerUserId))
|
|
||||||
.reducedWith(new FirstResultReducer())
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return wrapUserSessions(realm, sessions.values(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
|
public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
|
||||||
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
List<UserSessionModel> userSessions = getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerSessionId(brokerSessionId), false);
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).brokerSessionId(brokerSessionId))
|
return userSessions.isEmpty() ? null : userSessions.get(0);
|
||||||
.reducedWith(new FirstResultReducer())
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
List<UserSessionModel> userSessionModels = wrapUserSessions(realm, sessions.values(), false);
|
|
||||||
if (userSessionModels.isEmpty()) return null;
|
|
||||||
return userSessionModels.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -181,86 +172,58 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
return getUserSessions(realm, client, firstResult, maxResults, false);
|
return getUserSessions(realm, client, firstResult, maxResults, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults, boolean offline) {
|
protected List<UserSessionModel> getUserSessions(final RealmModel realm, ClientModel client, int firstResult, int maxResults, final boolean offline) {
|
||||||
Cache<String, SessionEntity> cache = getCache(offline);
|
final Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
Map<String, Integer> map = new MapReduceTask(cache)
|
Iterator<UserSessionTimestamp> itr = cache.entrySet().stream()
|
||||||
.mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
|
.filter(ClientSessionPredicate.create(realm.getId()).client(client.getId()).requireUserSession())
|
||||||
.reducedWith(new LargestResultReducer())
|
.map(Mappers.clientSessionToUserSessionTimestamp())
|
||||||
.execute();
|
.iterator();
|
||||||
|
|
||||||
List<Map.Entry<String, Integer>> sessionTimestamps = new LinkedList<Map.Entry<String, Integer>>(map.entrySet());
|
Map<String, UserSessionTimestamp> m = new HashMap<>();
|
||||||
|
while(itr.hasNext()) {
|
||||||
|
UserSessionTimestamp next = itr.next();
|
||||||
|
if (!m.containsKey(next.getUserSessionId()) || m.get(next.getUserSessionId()).getClientSessionTimestamp() < next.getClientSessionTimestamp()) {
|
||||||
|
m.put(next.getUserSessionId(), next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Collections.sort(sessionTimestamps, new Comparator<Map.Entry<String, Integer>>() {
|
Stream<UserSessionTimestamp> stream = new LinkedList<>(m.values()).stream().sorted(Comparators.userSessionTimestamp());
|
||||||
|
|
||||||
|
if (firstResult > 0) {
|
||||||
|
stream = stream.skip(firstResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxResults > 0) {
|
||||||
|
stream = stream.limit(maxResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<UserSessionModel> sessions = new LinkedList<>();
|
||||||
|
stream.forEach(new Consumer<UserSessionTimestamp>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
|
public void accept(UserSessionTimestamp userSessionTimestamp) {
|
||||||
return e1.getValue().compareTo(e2.getValue());
|
SessionEntity entity = cache.get(userSessionTimestamp.getUserSessionId());
|
||||||
|
if (entity != null) {
|
||||||
|
sessions.add(wrap(realm, (UserSessionEntity) entity, offline));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (firstResult != -1 || maxResults == -1) {
|
return sessions;
|
||||||
if (firstResult == -1) {
|
|
||||||
firstResult = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxResults == -1) {
|
|
||||||
maxResults = Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstResult > sessionTimestamps.size()) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
int toIndex = (firstResult + maxResults) < sessionTimestamps.size() ? firstResult + maxResults : sessionTimestamps.size();
|
|
||||||
sessionTimestamps = sessionTimestamps.subList(firstResult, toIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
|
|
||||||
for (Map.Entry<String, Integer> e : sessionTimestamps) {
|
|
||||||
UserSessionEntity userSessionEntity = (UserSessionEntity) cache.get(e.getKey());
|
|
||||||
if (userSessionEntity != null) {
|
|
||||||
userSessions.add(wrap(realm, userSessionEntity, offline));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return userSessions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) {
|
public long getActiveUserSessions(RealmModel realm, ClientModel client) {
|
||||||
HashMap<String, String> notes = new HashMap<>();
|
|
||||||
notes.put(noteName, noteValue);
|
|
||||||
return getUserSessionsByNotes(realm, notes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<UserSessionModel> getUserSessionsByNotes(RealmModel realm, Map<String, String> notes) {
|
|
||||||
Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
|
|
||||||
.mappedWith(UserSessionNoteMapper.create(realm.getId()).notes(notes))
|
|
||||||
.reducedWith(new FirstResultReducer())
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return wrapUserSessions(realm, sessions.values(), false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
|
|
||||||
return getUserSessionsCount(realm, client, false);
|
return getUserSessionsCount(realm, client, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
|
protected long getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
|
||||||
Cache<String, SessionEntity> cache = getCache(offline);
|
return getCache(offline).entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).client(client.getId()).requireUserSession()).map(Mappers.clientSessionToUserSessionId()).distinct().count();
|
||||||
|
|
||||||
Map map = new MapReduceTask(cache)
|
|
||||||
.mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
|
|
||||||
.reducedWith(new LargestResultReducer()).execute();
|
|
||||||
|
|
||||||
return map.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUserSession(RealmModel realm, UserSessionModel session) {
|
public void removeUserSession(RealmModel realm, UserSessionModel session) {
|
||||||
removeUserSession(realm, session.getId());
|
removeUserSession(realm, session.getId(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -271,80 +234,81 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
|
protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
|
||||||
Cache<String, SessionEntity> cache = getCache(offline);
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
Map<String, String> sessions = new MapReduceTask(cache)
|
Iterator<String> itr = cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).map(Mappers.sessionId()).iterator();
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()).emitKey())
|
while (itr.hasNext()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
removeUserSession(realm, itr.next(), offline);
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (String id : sessions.keySet()) {
|
|
||||||
removeUserSession(realm, id, offline);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeExpiredUserSessions(RealmModel realm) {
|
public void removeExpired(RealmModel realm) {
|
||||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
removeExpiredUserSessions(realm);
|
||||||
|
removeExpiredClientSessions(realm);
|
||||||
|
removeExpiredOfflineUserSessions(realm);
|
||||||
|
removeExpiredOfflineClientSessions(realm);
|
||||||
|
removeExpiredClientInitialAccess(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeExpiredUserSessions(RealmModel realm) {
|
||||||
int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan();
|
int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan();
|
||||||
int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout();
|
int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout();
|
||||||
int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
|
|
||||||
|
Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).expired(expired, expiredRefresh)).iterator();
|
||||||
|
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
|
||||||
|
tx.remove(sessionCache, entity.getId());
|
||||||
|
|
||||||
|
if (entity.getClientSessions() != null) {
|
||||||
|
for (String clientSessionId : entity.getClientSessions()) {
|
||||||
|
tx.remove(sessionCache, clientSessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeExpiredClientSessions(RealmModel realm) {
|
||||||
int expiredDettachedClientSession = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
|
int expiredDettachedClientSession = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
|
||||||
|
|
||||||
Map<String, String> map = new MapReduceTask(sessionCache)
|
Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession()).iterator();
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).expired(expired, expiredRefresh).emitKey())
|
while (itr.hasNext()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
tx.remove(sessionCache, itr.next().getKey());
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (String id : map.keySet()) {
|
|
||||||
removeUserSession(realm, id);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
map = new MapReduceTask(sessionCache)
|
private void removeExpiredOfflineUserSessions(RealmModel realm) {
|
||||||
.mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession(true).emitKey())
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
.reducedWith(new FirstResultReducer())
|
int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (String id : map.keySet()) {
|
Iterator<Map.Entry<String, SessionEntity>> itr = offlineSessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).expired(null, expiredOffline)).iterator();
|
||||||
tx.remove(sessionCache, id);
|
while (itr.hasNext()) {
|
||||||
}
|
UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
|
||||||
|
tx.remove(offlineSessionCache, entity.getId());
|
||||||
|
|
||||||
// Remove expired offline user sessions
|
persister.removeUserSession(entity.getId(), true);
|
||||||
Map<String, SessionEntity> map2 = new MapReduceTask(offlineSessionCache)
|
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).expired(null, expiredOffline))
|
|
||||||
.reducedWith(new FirstResultReducer())
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (Map.Entry<String, SessionEntity> entry : map2.entrySet()) {
|
|
||||||
String userSessionId = entry.getKey();
|
|
||||||
tx.remove(offlineSessionCache, userSessionId);
|
|
||||||
// Propagate to persister
|
|
||||||
persister.removeUserSession(userSessionId, true);
|
|
||||||
|
|
||||||
UserSessionEntity entity = (UserSessionEntity) entry.getValue();
|
|
||||||
for (String clientSessionId : entity.getClientSessions()) {
|
for (String clientSessionId : entity.getClientSessions()) {
|
||||||
tx.remove(offlineSessionCache, clientSessionId);
|
tx.remove(offlineSessionCache, clientSessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove expired offline client sessions
|
private void removeExpiredOfflineClientSessions(RealmModel realm) {
|
||||||
map = new MapReduceTask(offlineSessionCache)
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
.mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredOffline).emitKey())
|
int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
|
||||||
.reducedWith(new FirstResultReducer())
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (String clientSessionId : map.keySet()) {
|
Iterator<String> itr = offlineSessionCache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).expiredRefresh(expiredOffline)).map(Mappers.sessionId()).iterator();
|
||||||
tx.remove(offlineSessionCache, clientSessionId);
|
while (itr.hasNext()) {
|
||||||
persister.removeClientSession(clientSessionId, true);
|
String sessionId = itr.next();
|
||||||
|
tx.remove(offlineSessionCache, sessionId);
|
||||||
|
persister.removeClientSession(sessionId, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove expired client initial access
|
private void removeExpiredClientInitialAccess(RealmModel realm) {
|
||||||
map = new MapReduceTask(sessionCache)
|
Iterator<String> itr = sessionCache.entrySet().stream().filter(ClientInitialAccessPredicate.create(realm.getId()).expired(Time.currentTime())).map(Mappers.sessionId()).iterator();
|
||||||
.mappedWith(ClientInitialAccessMapper.create(realm.getId()).expired(Time.currentTime()).emitKey())
|
while (itr.hasNext()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
tx.remove(sessionCache, itr.next());
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (String id : map.keySet()) {
|
|
||||||
tx.remove(sessionCache, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,13 +320,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
protected void removeUserSessions(RealmModel realm, boolean offline) {
|
protected void removeUserSessions(RealmModel realm, boolean offline) {
|
||||||
Cache<String, SessionEntity> cache = getCache(offline);
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
Map<String, String> ids = new MapReduceTask(cache)
|
Iterator<String> itr = cache.entrySet().stream().filter(SessionPredicate.create(realm.getId())).map(Mappers.sessionId()).iterator();
|
||||||
.mappedWith(SessionMapper.create(realm.getId()).emitKey())
|
while (itr.hasNext()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
cache.remove(itr.next());
|
||||||
.execute();
|
|
||||||
|
|
||||||
for (String id : ids.keySet()) {
|
|
||||||
cache.remove(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,24 +344,18 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUserLoginFailure(RealmModel realm, String username) {
|
public void removeUserLoginFailure(RealmModel realm, String username) {
|
||||||
LoginFailureKey key = new LoginFailureKey(realm.getId(), username);
|
tx.remove(loginFailureCache, new LoginFailureKey(realm.getId(), username));
|
||||||
tx.remove(loginFailureCache, key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAllUserLoginFailures(RealmModel realm) {
|
public void removeAllUserLoginFailures(RealmModel realm) {
|
||||||
Map<LoginFailureKey, Object> sessions = new MapReduceTask(loginFailureCache)
|
Iterator<LoginFailureKey> itr = loginFailureCache.entrySet().stream().filter(UserLoginFailurePredicate.create(realm.getId())).map(Mappers.loginFailureId()).iterator();
|
||||||
.mappedWith(UserLoginFailureMapper.create(realm.getId()).emitKey())
|
while (itr.hasNext()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
LoginFailureKey key = itr.next();
|
||||||
.execute();
|
tx.remove(loginFailureCache, key);
|
||||||
|
|
||||||
for (LoginFailureKey id : sessions.keySet()) {
|
|
||||||
tx.remove(loginFailureCache, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRealmRemoved(RealmModel realm) {
|
public void onRealmRemoved(RealmModel realm) {
|
||||||
removeUserSessions(realm, true);
|
removeUserSessions(realm, true);
|
||||||
|
@ -418,18 +372,13 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
private void onClientRemoved(RealmModel realm, ClientModel client, boolean offline) {
|
private void onClientRemoved(RealmModel realm, ClientModel client, boolean offline) {
|
||||||
Cache<String, SessionEntity> cache = getCache(offline);
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
Map<String, ClientSessionEntity> map = new MapReduceTask(cache)
|
Iterator<Map.Entry<String, SessionEntity>> itr = cache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).client(client.getId())).iterator();
|
||||||
.mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()))
|
while (itr.hasNext()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
ClientSessionEntity entity = (ClientSessionEntity) itr.next().getValue();
|
||||||
.execute();
|
ClientSessionAdapter adapter = wrap(realm, entity, offline);
|
||||||
|
|
||||||
for (Map.Entry<String, ClientSessionEntity> entry : map.entrySet()) {
|
|
||||||
|
|
||||||
// detach from userSession
|
|
||||||
ClientSessionAdapter adapter = wrap(realm, entry.getValue(), offline);
|
|
||||||
adapter.setUserSession(null);
|
adapter.setUserSession(null);
|
||||||
|
|
||||||
tx.remove(cache, entry.getKey());
|
tx.remove(cache, entity.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,27 +440,19 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void removeUserSession(RealmModel realm, String userSessionId) {
|
|
||||||
removeUserSession(realm, userSessionId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void removeUserSession(RealmModel realm, String userSessionId, boolean offline) {
|
protected void removeUserSession(RealmModel realm, String userSessionId, boolean offline) {
|
||||||
Cache<String, SessionEntity> cache = getCache(offline);
|
Cache<String, SessionEntity> cache = getCache(offline);
|
||||||
|
|
||||||
tx.remove(cache, userSessionId);
|
tx.remove(cache, userSessionId);
|
||||||
|
|
||||||
// TODO: Isn't more effective to retrieve from userSessionEntity directly?
|
UserSessionEntity sessionEntity = (UserSessionEntity) cache.get(userSessionId);
|
||||||
Map<String, String> map = new MapReduceTask(cache)
|
if (sessionEntity.getClientSessions() != null) {
|
||||||
.mappedWith(ClientSessionMapper.create(realm.getId()).userSession(userSessionId).emitKey())
|
for (String clientSessionId : sessionEntity.getClientSessions()) {
|
||||||
.reducedWith(new FirstResultReducer())
|
tx.remove(cache, clientSessionId);
|
||||||
.execute();
|
}
|
||||||
|
|
||||||
for (String id : map.keySet()) {
|
|
||||||
tx.remove(cache, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InfinispanKeycloakTransaction getTx() {
|
InfinispanKeycloakTransaction getTx() {
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +463,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UserSessionModel> wrapUserSessions(RealmModel realm, Collection<UserSessionEntity> entities, boolean offline) {
|
List<UserSessionModel> wrapUserSessions(RealmModel realm, Collection<UserSessionEntity> entities, boolean offline) {
|
||||||
List<UserSessionModel> models = new LinkedList<UserSessionModel>();
|
List<UserSessionModel> models = new LinkedList<>();
|
||||||
for (UserSessionEntity e : entities) {
|
for (UserSessionEntity e : entities) {
|
||||||
models.add(wrap(realm, e, offline));
|
models.add(wrap(realm, e, offline));
|
||||||
}
|
}
|
||||||
|
@ -553,7 +494,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ClientSessionModel> wrapClientSessions(RealmModel realm, Collection<ClientSessionEntity> entities, boolean offline) {
|
List<ClientSessionModel> wrapClientSessions(RealmModel realm, Collection<ClientSessionEntity> entities, boolean offline) {
|
||||||
List<ClientSessionModel> models = new LinkedList<ClientSessionModel>();
|
List<ClientSessionModel> models = new LinkedList<>();
|
||||||
for (ClientSessionEntity e : entities) {
|
for (ClientSessionEntity e : entities) {
|
||||||
models.add(wrap(realm, e, offline));
|
models.add(wrap(realm, e, offline));
|
||||||
}
|
}
|
||||||
|
@ -600,23 +541,21 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClientSessionModel> getOfflineClientSessions(RealmModel realm, UserModel user) {
|
public List<ClientSessionModel> getOfflineClientSessions(RealmModel realm, UserModel user) {
|
||||||
Map<String, UserSessionEntity> sessions = new MapReduceTask(offlineSessionCache)
|
Iterator<Map.Entry<String, SessionEntity>> itr = offlineSessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).iterator();
|
||||||
.mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
|
List<ClientSessionModel> clientSessions = new LinkedList<>();
|
||||||
.reducedWith(new FirstResultReducer())
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
List<ClientSessionEntity> clientSessions = new LinkedList<>();
|
while(itr.hasNext()) {
|
||||||
for (UserSessionEntity userSession : sessions.values()) {
|
UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
|
||||||
Set<String> currClientSessions = userSession.getClientSessions();
|
Set<String> currClientSessions = entity.getClientSessions();
|
||||||
for (String clientSessionId : currClientSessions) {
|
for (String clientSessionId : currClientSessions) {
|
||||||
ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId);
|
ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId);
|
||||||
if (cls != null) {
|
if (cls != null) {
|
||||||
clientSessions.add(cls);
|
clientSessions.add(wrap(realm, cls, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapClientSessions(realm, clientSessions, true);
|
return clientSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -626,7 +565,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOfflineSessionsCount(RealmModel realm, ClientModel client) {
|
public long getOfflineSessionsCount(RealmModel realm, ClientModel client) {
|
||||||
return getUserSessionsCount(realm, client, true);
|
return getUserSessionsCount(realm, client, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,18 +660,19 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
|
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
|
||||||
Map<String, ClientInitialAccessEntity> entities = new MapReduceTask(sessionCache)
|
Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(ClientInitialAccessPredicate.create(realm.getId())).iterator();
|
||||||
.mappedWith(ClientInitialAccessMapper.create(realm.getId()))
|
List<ClientInitialAccessModel> list = new LinkedList<>();
|
||||||
.reducedWith(new FirstResultReducer())
|
while (itr.hasNext()) {
|
||||||
.execute();
|
list.add(wrap(realm, (ClientInitialAccessEntity) itr.next().getValue()));
|
||||||
return wrapClientInitialAccess(realm, entities.values());
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
class InfinispanKeycloakTransaction implements KeycloakTransaction {
|
class InfinispanKeycloakTransaction implements KeycloakTransaction {
|
||||||
|
|
||||||
private boolean active;
|
private boolean active;
|
||||||
private boolean rollback;
|
private boolean rollback;
|
||||||
private Map<Object, CacheTask> tasks = new HashMap<Object, CacheTask>();
|
private Map<Object, CacheTask> tasks = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void begin() {
|
public void begin() {
|
||||||
|
|
|
@ -47,7 +47,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
|
||||||
Cache<String, SessionEntity> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME);
|
Cache<String, SessionEntity> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME);
|
||||||
Cache<String, SessionEntity> offlineSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
|
Cache<String, SessionEntity> offlineSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
|
||||||
Cache<LoginFailureKey, LoginFailureEntity> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
|
Cache<LoginFailureKey, LoginFailureEntity> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
|
||||||
return new InfinispanUserSessionProvider(session, cache, offlineSessionsCache, loginFailures);
|
|
||||||
|
return isStreamMode() ? new InfinispanUserSessionProvider(session, cache, offlineSessionsCache, loginFailures) : new CompatInfinispanUserSessionProvider(session, cache, offlineSessionsCache, loginFailures);
|
||||||
} else {
|
} else {
|
||||||
return compatProviderFactory.create(session);
|
return compatProviderFactory.create(session);
|
||||||
}
|
}
|
||||||
|
@ -147,5 +148,9 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStreamMode() {
|
||||||
|
return Version.getVersionShort() >= Version.getVersionShort("8.1.0.Final");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class UserSessionTimestamp implements Serializable {
|
||||||
|
private String userSessionId;
|
||||||
|
private int clientSessionTimestamp;
|
||||||
|
|
||||||
|
public UserSessionTimestamp(String userSessionId, int clientSessionTimestamp) {
|
||||||
|
this.userSessionId = userSessionId;
|
||||||
|
this.clientSessionTimestamp = clientSessionTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserSessionId() {
|
||||||
|
return userSessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClientSessionTimestamp() {
|
||||||
|
return clientSessionTimestamp;
|
||||||
|
}
|
||||||
|
}
|
|
@ -176,17 +176,6 @@ public class MemUserSessionProvider implements UserSessionProvider {
|
||||||
return userSessions;
|
return userSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) {
|
|
||||||
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
|
|
||||||
for (UserSessionEntity s : this.userSessions.values()) {
|
|
||||||
if (s.getRealm().equals(realm.getId()) && noteValue.equals(s.getNotes().get(noteName))) {
|
|
||||||
userSessions.add(new UserSessionAdapter(session, this, realm, s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return userSessions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
|
public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
|
||||||
return getUserSessions(realm, client, false);
|
return getUserSessions(realm, client, false);
|
||||||
|
@ -230,7 +219,7 @@ public class MemUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
|
public long getActiveUserSessions(RealmModel realm, ClientModel client) {
|
||||||
return getUserSessions(realm, client, false).size();
|
return getUserSessions(realm, client, false).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +276,7 @@ public class MemUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeExpiredUserSessions(RealmModel realm) {
|
public void removeExpired(RealmModel realm) {
|
||||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
|
|
||||||
Iterator<UserSessionEntity> itr = userSessions.values().iterator();
|
Iterator<UserSessionEntity> itr = userSessions.values().iterator();
|
||||||
|
@ -565,7 +554,7 @@ public class MemUserSessionProvider implements UserSessionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOfflineSessionsCount(RealmModel realm, ClientModel client) {
|
public long getOfflineSessionsCount(RealmModel realm, ClientModel client) {
|
||||||
return getUserSessions(realm, client, true).size();
|
return getUserSessions(realm, client, true).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,13 +151,14 @@ public class InfinispanUserSessionInitializer {
|
||||||
int processors = Runtime.getRuntime().availableProcessors();
|
int processors = Runtime.getRuntime().availableProcessors();
|
||||||
|
|
||||||
ExecutorService localExecutor = Executors.newCachedThreadPool();
|
ExecutorService localExecutor = Executors.newCachedThreadPool();
|
||||||
DistributedExecutorService distributedExecutorService = new DefaultExecutorService(cache, localExecutor);
|
Transport transport = cache.getCacheManager().getTransport();
|
||||||
|
boolean distributed = transport != null;
|
||||||
|
ExecutorService executorService = distributed ? new DefaultExecutorService(cache, localExecutor) : localExecutor;
|
||||||
|
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!state.isFinished()) {
|
while (!state.isFinished()) {
|
||||||
Transport transport = cache.getCacheManager().getTransport();
|
|
||||||
int nodesCount = transport==null ? 1 : transport.getMembers().size();
|
int nodesCount = transport==null ? 1 : transport.getMembers().size();
|
||||||
int distributedWorkersCount = processors * nodesCount;
|
int distributedWorkersCount = processors * nodesCount;
|
||||||
|
|
||||||
|
@ -173,8 +174,11 @@ public class InfinispanUserSessionInitializer {
|
||||||
for (Integer segment : segments) {
|
for (Integer segment : segments) {
|
||||||
SessionInitializerWorker worker = new SessionInitializerWorker();
|
SessionInitializerWorker worker = new SessionInitializerWorker();
|
||||||
worker.setWorkerEnvironment(segment, sessionsPerSegment, sessionLoader);
|
worker.setWorkerEnvironment(segment, sessionsPerSegment, sessionLoader);
|
||||||
|
if (!distributed) {
|
||||||
|
worker.setEnvironment(cache, null);
|
||||||
|
}
|
||||||
|
|
||||||
Future<WorkerResult> future = distributedExecutorService.submit(worker);
|
Future<WorkerResult> future = executorService.submit(worker);
|
||||||
futures.add(future);
|
futures.add(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +214,9 @@ public class InfinispanUserSessionInitializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
distributedExecutorService.shutdown();
|
if (distributed) {
|
||||||
|
executorService.shutdown();
|
||||||
|
}
|
||||||
localExecutor.shutdown();
|
localExecutor.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.ClientInitialAccessEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class ClientInitialAccessPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
|
||||||
|
|
||||||
|
public ClientInitialAccessPredicate(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
private Integer expired;
|
||||||
|
|
||||||
|
public static ClientInitialAccessPredicate create(String realm) {
|
||||||
|
return new ClientInitialAccessPredicate(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientInitialAccessPredicate expired(int time) {
|
||||||
|
this.expired = time;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
|
||||||
|
if (!realm.equals(e.getRealm())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(e instanceof ClientInitialAccessEntity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientInitialAccessEntity entity = (ClientInitialAccessEntity) e;
|
||||||
|
|
||||||
|
if (expired != null) {
|
||||||
|
if (entity.getRemainingCount() <= 0) {
|
||||||
|
return true;
|
||||||
|
} else if (entity.getExpiration() > 0 && (entity.getTimestamp() + entity.getExpiration()) < expired) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class ClientSessionPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
private String client;
|
||||||
|
|
||||||
|
private String userSession;
|
||||||
|
|
||||||
|
private Long expiredRefresh;
|
||||||
|
|
||||||
|
private Boolean requireUserSession = false;
|
||||||
|
|
||||||
|
private Boolean requireNullUserSession = false;
|
||||||
|
|
||||||
|
private ClientSessionPredicate(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientSessionPredicate create(String realm) {
|
||||||
|
return new ClientSessionPredicate(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientSessionPredicate client(String client) {
|
||||||
|
this.client = client;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientSessionPredicate userSession(String userSession) {
|
||||||
|
this.userSession = userSession;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientSessionPredicate expiredRefresh(long expiredRefresh) {
|
||||||
|
this.expiredRefresh = expiredRefresh;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientSessionPredicate requireUserSession() {
|
||||||
|
requireUserSession = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientSessionPredicate requireNullUserSession() {
|
||||||
|
requireNullUserSession = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
|
||||||
|
if (!realm.equals(e.getRealm())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(e instanceof ClientSessionEntity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientSessionEntity entity = (ClientSessionEntity) e;
|
||||||
|
|
||||||
|
if (client != null && !entity.getClient().equals(client)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userSession != null && !userSession.equals(entity.getUserSession())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requireUserSession && entity.getUserSession() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requireNullUserSession && entity.getUserSession() != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expiredRefresh != null && entity.getTimestamp() > expiredRefresh) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.UserSessionTimestamp;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Comparators {
|
||||||
|
|
||||||
|
public static Comparator<UserSessionTimestamp> userSessionTimestamp() {
|
||||||
|
return new UserSessionTimestampComparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UserSessionTimestampComparator implements Comparator<UserSessionTimestamp>, Serializable {
|
||||||
|
@Override
|
||||||
|
public int compare(UserSessionTimestamp u1, UserSessionTimestamp u2) {
|
||||||
|
return u1.getClientSessionTimestamp() - u2.getClientSessionTimestamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.UserSessionTimestamp;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Mappers {
|
||||||
|
|
||||||
|
public static Function<Map.Entry<String, SessionEntity>, UserSessionTimestamp> clientSessionToUserSessionTimestamp() {
|
||||||
|
return new ClientSessionToUserSessionTimestampMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<Map.Entry<String, Optional<UserSessionTimestamp>>, UserSessionTimestamp> userSessionTimestamp() {
|
||||||
|
return new UserSessionTimestampMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<Map.Entry<String, SessionEntity>, String> sessionId() {
|
||||||
|
return new SessionIdMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<Map.Entry<LoginFailureKey, LoginFailureEntity>, LoginFailureKey> loginFailureId() {
|
||||||
|
return new LoginFailureIdMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<Map.Entry<String, SessionEntity>, String> clientSessionToUserSessionId() {
|
||||||
|
return new ClientSessionToUserSessionIdMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClientSessionToUserSessionTimestampMapper implements Function<Map.Entry<String, SessionEntity>, UserSessionTimestamp>, Serializable {
|
||||||
|
@Override
|
||||||
|
public UserSessionTimestamp apply(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
ClientSessionEntity entity = (ClientSessionEntity) e;
|
||||||
|
return new UserSessionTimestamp(entity.getUserSession(), entity.getTimestamp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UserSessionTimestampMapper implements Function<Map.Entry<String, Optional<org.keycloak.models.sessions.infinispan.UserSessionTimestamp>>, org.keycloak.models.sessions.infinispan.UserSessionTimestamp>, Serializable {
|
||||||
|
@Override
|
||||||
|
public org.keycloak.models.sessions.infinispan.UserSessionTimestamp apply(Map.Entry<String, Optional<org.keycloak.models.sessions.infinispan.UserSessionTimestamp>> e) {
|
||||||
|
return e.getValue().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SessionIdMapper implements Function<Map.Entry<String, SessionEntity>, String>, Serializable {
|
||||||
|
@Override
|
||||||
|
public String apply(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LoginFailureIdMapper implements Function<Map.Entry<LoginFailureKey, LoginFailureEntity>, LoginFailureKey>, Serializable {
|
||||||
|
@Override
|
||||||
|
public LoginFailureKey apply(Map.Entry<LoginFailureKey, LoginFailureEntity> entry) {
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClientSessionToUserSessionIdMapper implements Function<Map.Entry<String, SessionEntity>, String>, Serializable {
|
||||||
|
@Override
|
||||||
|
public String apply(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
ClientSessionEntity entity = (ClientSessionEntity) e;
|
||||||
|
return entity.getUserSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class SessionPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
private SessionPredicate(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SessionPredicate create(String realm) {
|
||||||
|
return new SessionPredicate(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
return realm.equals(entry.getValue().getRealm());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class UserLoginFailurePredicate implements Predicate<Map.Entry<LoginFailureKey, LoginFailureEntity>>, Serializable {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
private UserLoginFailurePredicate(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserLoginFailurePredicate create(String realm) {
|
||||||
|
return new UserLoginFailurePredicate(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Map.Entry<LoginFailureKey, LoginFailureEntity> entry) {
|
||||||
|
LoginFailureEntity e = entry.getValue();
|
||||||
|
return realm.equals(e.getRealm());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class UserSessionPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
private String user;
|
||||||
|
|
||||||
|
private Integer expired;
|
||||||
|
|
||||||
|
private Integer expiredRefresh;
|
||||||
|
|
||||||
|
private String brokerSessionId;
|
||||||
|
private String brokerUserId;
|
||||||
|
|
||||||
|
private UserSessionPredicate(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserSessionPredicate create(String realm) {
|
||||||
|
return new UserSessionPredicate(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserSessionPredicate user(String user) {
|
||||||
|
this.user = user;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserSessionPredicate expired(Integer expired, Integer expiredRefresh) {
|
||||||
|
this.expired = expired;
|
||||||
|
this.expiredRefresh = expiredRefresh;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserSessionPredicate brokerSessionId(String id) {
|
||||||
|
this.brokerSessionId = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserSessionPredicate brokerUserId(String id) {
|
||||||
|
this.brokerUserId = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Map.Entry<String, SessionEntity> entry) {
|
||||||
|
SessionEntity e = entry.getValue();
|
||||||
|
|
||||||
|
if (!(e instanceof UserSessionEntity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSessionEntity entity = (UserSessionEntity) e;
|
||||||
|
|
||||||
|
if (!realm.equals(entity.getRealm())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user != null && !entity.getUser().equals(user)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brokerSessionId != null && !brokerSessionId.equals(entity.getBrokerSessionId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brokerUserId != null && !brokerUserId.equals(entity.getBrokerUserId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expired != null && expiredRefresh != null && entity.getStarted() > expired && entity.getLastSessionRefresh() > expiredRefresh) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expired == null && expiredRefresh != null && entity.getLastSessionRefresh() > expiredRefresh) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
8
pom.xml
8
pom.xml
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.jboss</groupId>
|
<groupId>org.jboss</groupId>
|
||||||
<artifactId>jboss-parent</artifactId>
|
<artifactId>jboss-parent</artifactId>
|
||||||
<version>16</version>
|
<version>19</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>Keycloak</name>
|
<name>Keycloak</name>
|
||||||
|
@ -49,8 +49,8 @@
|
||||||
<dom4j.version>1.6.1</dom4j.version>
|
<dom4j.version>1.6.1</dom4j.version>
|
||||||
<xml-apis.version>1.4.01</xml-apis.version>
|
<xml-apis.version>1.4.01</xml-apis.version>
|
||||||
<slf4j.version>1.7.7</slf4j.version>
|
<slf4j.version>1.7.7</slf4j.version>
|
||||||
<wildfly.version>10.0.0.CR4</wildfly.version>
|
<wildfly.version>10.0.0.CR5</wildfly.version>
|
||||||
<wildfly.core.version>2.0.1.Final</wildfly.core.version>
|
<wildfly.core.version>2.0.5.Final</wildfly.core.version>
|
||||||
<wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
|
<wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
|
||||||
|
|
||||||
<!-- this is EAP 6.4 alpha, publicly available -->
|
<!-- this is EAP 6.4 alpha, publicly available -->
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<sun.jaxb.version>2.2.11</sun.jaxb.version>
|
<sun.jaxb.version>2.2.11</sun.jaxb.version>
|
||||||
<sun.xsom.version>20140925</sun.xsom.version>
|
<sun.xsom.version>20140925</sun.xsom.version>
|
||||||
<javax.mail.version>1.4.5</javax.mail.version>
|
<javax.mail.version>1.4.5</javax.mail.version>
|
||||||
<infinispan.version>6.0.2.Final</infinispan.version>
|
<infinispan.version>8.1.0.Final</infinispan.version>
|
||||||
<liquibase.version>3.4.1</liquibase.version>
|
<liquibase.version>3.4.1</liquibase.version>
|
||||||
<jetty9.version>9.1.0.v20131115</jetty9.version>
|
<jetty9.version>9.1.0.v20131115</jetty9.version>
|
||||||
<osgi.version>4.2.0</osgi.version>
|
<osgi.version>4.2.0</osgi.version>
|
||||||
|
|
|
@ -383,9 +383,9 @@ public class ClientResource {
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Map<String, Integer> getApplicationSessionCount() {
|
public Map<String, Long> getApplicationSessionCount() {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
Map<String, Integer> map = new HashMap<String, Integer>();
|
Map<String, Long> map = new HashMap<>();
|
||||||
map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client));
|
map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client));
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -430,9 +430,9 @@ public class ClientResource {
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Map<String, Integer> getOfflineSessionCount() {
|
public Map<String, Long> getOfflineSessionCount() {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
Map<String, Integer> map = new HashMap<String, Integer>();
|
Map<String, Long> map = new HashMap<>();
|
||||||
map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client));
|
map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client));
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,9 +369,9 @@ public class RealmAdminResource {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
List<Map<String, String>> data = new LinkedList<Map<String, String>>();
|
List<Map<String, String>> data = new LinkedList<Map<String, String>>();
|
||||||
for (ClientModel client : realm.getClients()) {
|
for (ClientModel client : realm.getClients()) {
|
||||||
int size = session.sessions().getActiveUserSessions(client.getRealm(), client);
|
long size = session.sessions().getActiveUserSessions(client.getRealm(), client);
|
||||||
if (size == 0) continue;
|
if (size == 0) continue;
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
Map<String, String> map = new HashMap<>();
|
||||||
map.put("id", client.getId());
|
map.put("id", client.getId());
|
||||||
map.put("clientId", client.getClientId());
|
map.put("clientId", client.getClientId());
|
||||||
map.put("active", size + "");
|
map.put("active", size + "");
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class ClearExpiredUserSessions implements ScheduledTask {
|
||||||
public void run(KeycloakSession session) {
|
public void run(KeycloakSession session) {
|
||||||
UserSessionProvider sessions = session.sessions();
|
UserSessionProvider sessions = session.sessions();
|
||||||
for (RealmModel realm : session.realms().getRealms()) {
|
for (RealmModel realm : session.realms().getRealms()) {
|
||||||
sessions.removeExpiredUserSessions(realm);
|
sessions.removeExpired(realm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,8 @@ public class AdapterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoginSSOAndLogout() throws Exception {
|
public void testLoginSSOAndLogout() throws Exception {
|
||||||
|
testStrategy.testLoginSSOMax();
|
||||||
|
|
||||||
testStrategy.testLoginSSOAndLogout();
|
testStrategy.testLoginSSOAndLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,7 +310,7 @@ public class AdapterTestStrategy extends ExternalResource {
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.realms().getRealmByName("demo");
|
realm = session.realms().getRealmByName("demo");
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
session.close();
|
session.close();
|
||||||
|
|
||||||
|
|
|
@ -286,9 +286,6 @@ public class BruteForceTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBrowserInvalidPassword() throws Exception {
|
public void testBrowserInvalidPassword() throws Exception {
|
||||||
loginSuccess();
|
loginSuccess();
|
||||||
|
|
|
@ -524,7 +524,7 @@ public class LoginTest {
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
manager.getSession().sessions().removeExpiredUserSessions(appRealm);
|
manager.getSession().sessions().removeExpired(appRealm);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -347,7 +347,7 @@ public class UserSessionProviderOfflineTest {
|
||||||
|
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
|
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ public class UserSessionProviderOfflineTest {
|
||||||
// Expire everything and assert nothing found
|
// Expire everything and assert nothing found
|
||||||
Time.setOffset(3000000);
|
Time.setOffset(3000000);
|
||||||
try {
|
try {
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
|
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,7 @@ import org.keycloak.services.managers.UserManager;
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@ -276,7 +272,7 @@ public class UserSessionProviderTest {
|
||||||
|
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
for (String e : expired) {
|
for (String e : expired) {
|
||||||
|
@ -309,13 +305,13 @@ public class UserSessionProviderTest {
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
Time.setOffset(25);
|
Time.setOffset(25);
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
assertNotNull(session.sessions().getClientSession(clientSessionId));
|
assertNotNull(session.sessions().getClientSession(clientSessionId));
|
||||||
|
|
||||||
Time.setOffset(35);
|
Time.setOffset(35);
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
assertNull(session.sessions().getClientSession(clientSessionId));
|
assertNull(session.sessions().getClientSession(clientSessionId));
|
||||||
|
@ -328,13 +324,13 @@ public class UserSessionProviderTest {
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
Time.setOffset(35);
|
Time.setOffset(35);
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
assertNotNull(session.sessions().getClientSession(clientSessionId));
|
assertNotNull(session.sessions().getClientSession(clientSessionId));
|
||||||
|
|
||||||
Time.setOffset(45);
|
Time.setOffset(45);
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
assertNull(session.sessions().getClientSession(clientSessionId));
|
assertNull(session.sessions().getClientSession(clientSessionId));
|
||||||
|
@ -347,13 +343,13 @@ public class UserSessionProviderTest {
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
Time.setOffset(45);
|
Time.setOffset(45);
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
assertNotNull(session.sessions().getClientSession(clientSessionId));
|
assertNotNull(session.sessions().getClientSession(clientSessionId));
|
||||||
|
|
||||||
Time.setOffset(55);
|
Time.setOffset(55);
|
||||||
session.sessions().removeExpiredUserSessions(realm);
|
session.sessions().removeExpired(realm);
|
||||||
resetSession();
|
resetSession();
|
||||||
|
|
||||||
assertNull(session.sessions().getClientSession(clientSessionId));
|
assertNull(session.sessions().getClientSession(clientSessionId));
|
||||||
|
@ -463,6 +459,18 @@ public class UserSessionProviderTest {
|
||||||
|
|
||||||
failure1 = session.sessions().getUserLoginFailure(realm, "user1");
|
failure1 = session.sessions().getUserLoginFailure(realm, "user1");
|
||||||
assertEquals(0, failure1.getNumFailures());
|
assertEquals(0, failure1.getNumFailures());
|
||||||
|
|
||||||
|
session.sessions().removeUserLoginFailure(realm, "user1");
|
||||||
|
|
||||||
|
resetSession();
|
||||||
|
|
||||||
|
assertNull(session.sessions().getUserLoginFailure(realm, "user1"));
|
||||||
|
|
||||||
|
session.sessions().removeAllUserLoginFailures(realm);
|
||||||
|
|
||||||
|
resetSession();
|
||||||
|
|
||||||
|
assertNull(session.sessions().getUserLoginFailure(realm, "user2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -263,7 +263,7 @@ public class OfflineTokenTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
manager.getSession().sessions().removeExpiredUserSessions(appRealm);
|
manager.getSession().sessions().removeExpired(appRealm);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue