diff --git a/.travis.yml b/.travis.yml index b2b362762e..3da0679c50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,18 @@ language: java +env: + global: + - MAVEN_SKIP_RC=true + - MAVEN_OPTS="-Xms512m -Xmx2048m" + jdk: - oraclejdk8 +before_script: + - export MAVEN_SKIP_RC=true + install: - - travis_wait mvn install -Pdistribution -DskipTests=true -B -V -q + - mvn install -Pdistribution -DskipTests=true -B -V -q script: - mvn test -B diff --git a/distribution/feature-packs/server-feature-pack/feature-pack-build.xml b/distribution/feature-packs/server-feature-pack/feature-pack-build.xml index f9208857aa..6ef7e7bb6b 100644 --- a/distribution/feature-packs/server-feature-pack/feature-pack-build.xml +++ b/distribution/feature-packs/server-feature-pack/feature-pack-build.xml @@ -1,4 +1,26 @@ - + + + @@ -8,20 +30,31 @@ + + + + + + + + + + + @@ -33,4 +66,4 @@ - \ No newline at end of file + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml index 29c6e63889..bea2e10873 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml @@ -53,63 +53,4 @@ undertow.xml keycloak-server.xml - - - logging.xml - bean-validation.xml - keycloak-datasources.xml - ee.xml - ejb3.xml - io.xml - keycloak-infinispan.xml - iiop-openjdk.xml - jaxrs.xml - jca.xml - jdr.xml - jmx.xml - jpa.xml - jsf.xml - jsr77.xml - mail.xml - messaging.xml - naming.xml - remoting.xml - request-controller.xml - security.xml - security-manager.xml - transactions.xml - undertow.xml - keycloak-server.xml - - - - logging.xml - bean-validation.xml - keycloak-datasources.xml - ee.xml - ejb3.xml - io.xml - keycloak-infinispan.xml - iiop-openjdk.xml - jaxrs.xml - jca.xml - jdr.xml - jgroups.xml - jmx.xml - jpa.xml - jsf.xml - jsr77.xml - mail.xml - messaging.xml - mod_cluster.xml - naming.xml - remoting.xml - resource-adapters.xml - request-controller.xml - security.xml - security-manager.xml - transactions.xml - undertow.xml - keycloak-server.xml - diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml index 8c4464c591..770d2619bd 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml @@ -24,18 +24,12 @@ - - - - - - - - - - - - + + + + + + - - - - - - - - - + - + - + - + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml new file mode 100644 index 0000000000..5d959bd093 --- /dev/null +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml new file mode 100644 index 0000000000..4b79b0aedc --- /dev/null +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml new file mode 100644 index 0000000000..501fae8931 --- /dev/null +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/subsystems.xml new file mode 100644 index 0000000000..3df2a95f79 --- /dev/null +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/subsystems.xml @@ -0,0 +1,29 @@ + + + + + + + jmx.xml + + diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml index 151ab710de..bf84e794ee 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml @@ -1,30 +1,30 @@ - - logging.xml - bean-validation.xml - keycloak-datasources.xml - ee.xml - ejb3.xml - io.xml - keycloak-infinispan.xml - jaxrs.xml - jca.xml - jdr.xml - jgroups.xml - jmx.xml - jpa.xml - jsf.xml - mail.xml - mod_cluster.xml - naming.xml - remoting.xml - request-controller.xml - security-manager.xml - security.xml - transactions.xml - undertow.xml - keycloak-server.xml - + + logging.xml + bean-validation.xml + keycloak-datasources.xml + ee.xml + ejb3.xml + io.xml + keycloak-infinispan.xml + jaxrs.xml + jca.xml + jdr.xml + jgroups.xml + jmx.xml + jpa.xml + jsf.xml + mail.xml + mod_cluster.xml + naming.xml + remoting.xml + request-controller.xml + security-manager.xml + security.xml + transactions.xml + undertow.xml + keycloak-server.xml + \ No newline at end of file diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml index 76fbe9e4a4..4df055c0ab 100644 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml @@ -29,15 +29,15 @@ - - + + - + - - - + + + @@ -69,8 +69,9 @@ - + + @@ -80,4 +81,4 @@ - \ No newline at end of file + diff --git a/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java b/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java index 0c1df9cc1f..f2acf49115 100755 --- a/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java +++ b/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java @@ -23,14 +23,12 @@ public interface UserSessionProvider extends Provider { List getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId); UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId); - List getUserSessionsByNote(RealmModel realm, String noteName, String noteValue); - - int getActiveUserSessions(RealmModel realm, ClientModel client); + long getActiveUserSessions(RealmModel realm, ClientModel client); void removeUserSession(RealmModel realm, UserSessionModel session); void removeUserSessions(RealmModel realm, UserModel user); // Implementation should propagate removal of expired userSessions to userSessionPersister too - void removeExpiredUserSessions(RealmModel realm); + void removeExpired(RealmModel realm); void removeUserSessions(RealmModel realm); 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 void removeOfflineClientSession(RealmModel realm, String clientSessionId); - int getOfflineSessionsCount(RealmModel realm, ClientModel client); + long getOfflineSessionsCount(RealmModel realm, ClientModel client); List getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max); // Triggered by persister during pre-load diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/CompatInfinispanUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/CompatInfinispanUserSessionProvider.java new file mode 100644 index 0000000000..bcd72e79ef --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/CompatInfinispanUserSessionProvider.java @@ -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 Stian Thorgersen + */ +public class CompatInfinispanUserSessionProvider extends InfinispanUserSessionProvider { + + private static final Logger log = Logger.getLogger(CompatInfinispanUserSessionProvider.class); + + public CompatInfinispanUserSessionProvider(KeycloakSession session, Cache sessionCache, Cache offlineSessionCache, + Cache loginFailureCache) { + super(session, sessionCache, offlineSessionCache, loginFailureCache); + } + + @Override + public List getUserSessions(RealmModel realm, UserModel user) { + Map 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 getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) { + Map 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 sessions = new MapReduceTask(sessionCache) + .mappedWith(UserSessionMapper.create(realm.getId()).brokerSessionId(brokerSessionId)) + .reducedWith(new FirstResultReducer()) + .execute(); + + List userSessionModels = wrapUserSessions(realm, sessions.values(), false); + if (userSessionModels.isEmpty()) return null; + return userSessionModels.get(0); + } + + @Override + public List getUserSessions(RealmModel realm, ClientModel client) { + return getUserSessions(realm, client, -1, -1); + } + + @Override + public List getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults) { + return getUserSessions(realm, client, firstResult, maxResults, false); + } + + protected List getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults, boolean offline) { + Cache cache = getCache(offline); + + Map map = new MapReduceTask(cache) + .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp()) + .reducedWith(new LargestResultReducer()) + .execute(); + + List> sessionTimestamps = new LinkedList>(map.entrySet()); + + Collections.sort(sessionTimestamps, new Comparator>() { + @Override + public int compare(Map.Entry e1, Map.Entry 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 userSessions = new LinkedList(); + for (Map.Entry 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 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 cache = getCache(offline); + + Map 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 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 map2 = new MapReduceTask(offlineSessionCache) + .mappedWith(UserSessionMapper.create(realm.getId()).expired(null, expiredOffline)) + .reducedWith(new FirstResultReducer()) + .execute(); + + for (Map.Entry 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 cache = getCache(offline); + + Map 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 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 cache = getCache(offline); + + Map map = new MapReduceTask(cache) + .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId())) + .reducedWith(new FirstResultReducer()) + .execute(); + + for (Map.Entry 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 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 cache = getCache(offline); + + tx.remove(cache, userSessionId); + + // TODO: Isn't more effective to retrieve from userSessionEntity directly? + Map 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 getOfflineClientSessions(RealmModel realm, UserModel user) { + Map sessions = new MapReduceTask(offlineSessionCache) + .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId())) + .reducedWith(new FirstResultReducer()) + .execute(); + + List clientSessions = new LinkedList<>(); + for (UserSessionEntity userSession : sessions.values()) { + Set 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 getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max) { + return getUserSessions(realm, client, first, max, true); + } + + @Override + public List listClientInitialAccess(RealmModel realm) { + Map entities = new MapReduceTask(sessionCache) + .mappedWith(ClientInitialAccessMapper.create(realm.getId())) + .reducedWith(new FirstResultReducer()) + .execute(); + return wrapClientInitialAccess(realm, entities.values()); + } + +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/Consumers.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/Consumers.java new file mode 100644 index 0000000000..0eed3308c4 --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/Consumers.java @@ -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 Stian Thorgersen + */ +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> { + + private Map sessions = new HashMap<>(); + + @Override + public void accept(Map.Entry 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> { + + private InfinispanUserSessionProvider provider; + private RealmModel realm; + private boolean offline; + private List 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 entry) { + SessionEntity e = entry.getValue(); + sessions.add(provider.wrap(realm, (UserSessionEntity) e, offline)); + } + + public List getSessions() { + return sessions; + } + + } +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java index d89f47b023..7e66b12b2a 100755 --- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java @@ -1,25 +1,21 @@ package org.keycloak.models.sessions.infinispan; import org.infinispan.Cache; -import org.infinispan.distexec.mapreduce.MapReduceTask; +import org.infinispan.CacheStream; 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.sessions.infinispan.stream.*; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.RealmInfoUtil; -import org.keycloak.common.util.Time; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @author Stian Thorgersen @@ -28,11 +24,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { private static final Logger log = Logger.getLogger(InfinispanUserSessionProvider.class); - private final KeycloakSession session; - private final Cache sessionCache; - private final Cache offlineSessionCache; - private final Cache loginFailureCache; - private final InfinispanKeycloakTransaction tx; + protected final KeycloakSession session; + protected final Cache sessionCache; + protected final Cache offlineSessionCache; + protected final Cache loginFailureCache; + protected final InfinispanKeycloakTransaction tx; public InfinispanUserSessionProvider(KeycloakSession session, Cache sessionCache, Cache offlineSessionCache, Cache loginFailureCache) { @@ -139,36 +135,31 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { return wrap(realm, entity, offline); } - @Override - public List getUserSessions(RealmModel realm, UserModel user) { - Map sessions = new MapReduceTask(sessionCache) - .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId())) - .reducedWith(new FirstResultReducer()) - .execute(); + protected List getUserSessions(RealmModel realm, Predicate> predicate, boolean offline) { + CacheStream> cacheStream = getCache(offline).entrySet().stream(); + Iterator> itr = cacheStream.filter(predicate).iterator(); + List sessions = new LinkedList<>(); + while (itr.hasNext()) { + UserSessionEntity e = (UserSessionEntity) itr.next().getValue(); + sessions.add(wrap(realm, e, offline)); + } + return sessions; + } - return wrapUserSessions(realm, sessions.values(), false); + @Override + public List getUserSessions(final RealmModel realm, UserModel user) { + return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).user(user.getId()), false); } @Override public List getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) { - Map sessions = new MapReduceTask(sessionCache) - .mappedWith(UserSessionMapper.create(realm.getId()).brokerUserId(brokerUserId)) - .reducedWith(new FirstResultReducer()) - .execute(); - - return wrapUserSessions(realm, sessions.values(), false); + return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerUserId(brokerUserId), false); } @Override public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) { - Map sessions = new MapReduceTask(sessionCache) - .mappedWith(UserSessionMapper.create(realm.getId()).brokerSessionId(brokerSessionId)) - .reducedWith(new FirstResultReducer()) - .execute(); - - List userSessionModels = wrapUserSessions(realm, sessions.values(), false); - if (userSessionModels.isEmpty()) return null; - return userSessionModels.get(0); + List userSessions = getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerSessionId(brokerSessionId), false); + return userSessions.isEmpty() ? null : userSessions.get(0); } @Override @@ -181,86 +172,58 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { return getUserSessions(realm, client, firstResult, maxResults, false); } - protected List getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults, boolean offline) { - Cache cache = getCache(offline); + protected List getUserSessions(final RealmModel realm, ClientModel client, int firstResult, int maxResults, final boolean offline) { + final Cache cache = getCache(offline); - Map map = new MapReduceTask(cache) - .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp()) - .reducedWith(new LargestResultReducer()) - .execute(); + Iterator itr = cache.entrySet().stream() + .filter(ClientSessionPredicate.create(realm.getId()).client(client.getId()).requireUserSession()) + .map(Mappers.clientSessionToUserSessionTimestamp()) + .iterator(); - List> sessionTimestamps = new LinkedList>(map.entrySet()); + Map 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>() { + Stream 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 sessions = new LinkedList<>(); + stream.forEach(new Consumer() { @Override - public int compare(Map.Entry e1, Map.Entry e2) { - return e1.getValue().compareTo(e2.getValue()); + public void accept(UserSessionTimestamp userSessionTimestamp) { + SessionEntity entity = cache.get(userSessionTimestamp.getUserSessionId()); + if (entity != null) { + sessions.add(wrap(realm, (UserSessionEntity) entity, offline)); + } } }); - 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 userSessions = new LinkedList(); - for (Map.Entry e : sessionTimestamps) { - UserSessionEntity userSessionEntity = (UserSessionEntity) cache.get(e.getKey()); - if (userSessionEntity != null) { - userSessions.add(wrap(realm, userSessionEntity, offline)); - } - } - - return userSessions; + return sessions; } @Override - public List getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) { - HashMap notes = new HashMap<>(); - notes.put(noteName, noteValue); - return getUserSessionsByNotes(realm, notes); - } - - public List getUserSessionsByNotes(RealmModel realm, Map notes) { - Map 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) { + public long getActiveUserSessions(RealmModel realm, ClientModel client) { return getUserSessionsCount(realm, client, false); } - protected int getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) { - Cache cache = getCache(offline); - - Map map = new MapReduceTask(cache) - .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp()) - .reducedWith(new LargestResultReducer()).execute(); - - return map.size(); + protected long getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) { + return getCache(offline).entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).client(client.getId()).requireUserSession()).map(Mappers.clientSessionToUserSessionId()).distinct().count(); } @Override public void removeUserSession(RealmModel realm, UserSessionModel session) { - removeUserSession(realm, session.getId()); + removeUserSession(realm, session.getId(), false); } @Override @@ -271,80 +234,81 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) { Cache cache = getCache(offline); - Map 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); + Iterator itr = cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).map(Mappers.sessionId()).iterator(); + while (itr.hasNext()) { + removeUserSession(realm, itr.next(), offline); } } @Override - public void removeExpiredUserSessions(RealmModel realm) { - UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); + public void removeExpired(RealmModel realm) { + removeExpiredUserSessions(realm); + removeExpiredClientSessions(realm); + removeExpiredOfflineUserSessions(realm); + removeExpiredOfflineClientSessions(realm); + removeExpiredClientInitialAccess(realm); + } + private void removeExpiredUserSessions(RealmModel realm) { int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan(); int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout(); - int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout(); + + Iterator> 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); - Map 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); + Iterator> itr = sessionCache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession()).iterator(); + while (itr.hasNext()) { + tx.remove(sessionCache, itr.next().getKey()); } + } - map = new MapReduceTask(sessionCache) - .mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession(true).emitKey()) - .reducedWith(new FirstResultReducer()) - .execute(); + private void removeExpiredOfflineUserSessions(RealmModel realm) { + UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); + int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout(); - for (String id : map.keySet()) { - tx.remove(sessionCache, id); - } + Iterator> itr = offlineSessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).expired(null, expiredOffline)).iterator(); + while (itr.hasNext()) { + UserSessionEntity entity = (UserSessionEntity) itr.next().getValue(); + tx.remove(offlineSessionCache, entity.getId()); - // Remove expired offline user sessions - Map map2 = new MapReduceTask(offlineSessionCache) - .mappedWith(UserSessionMapper.create(realm.getId()).expired(null, expiredOffline)) - .reducedWith(new FirstResultReducer()) - .execute(); + persister.removeUserSession(entity.getId(), true); - for (Map.Entry 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(); + private void removeExpiredOfflineClientSessions(RealmModel realm) { + UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); + int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout(); - for (String clientSessionId : map.keySet()) { - tx.remove(offlineSessionCache, clientSessionId); - persister.removeClientSession(clientSessionId, true); + Iterator itr = offlineSessionCache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).expiredRefresh(expiredOffline)).map(Mappers.sessionId()).iterator(); + while (itr.hasNext()) { + String sessionId = itr.next(); + tx.remove(offlineSessionCache, sessionId); + persister.removeClientSession(sessionId, 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); + private void removeExpiredClientInitialAccess(RealmModel realm) { + Iterator itr = sessionCache.entrySet().stream().filter(ClientInitialAccessPredicate.create(realm.getId()).expired(Time.currentTime())).map(Mappers.sessionId()).iterator(); + while (itr.hasNext()) { + tx.remove(sessionCache, itr.next()); } } @@ -356,13 +320,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { protected void removeUserSessions(RealmModel realm, boolean offline) { Cache cache = getCache(offline); - Map ids = new MapReduceTask(cache) - .mappedWith(SessionMapper.create(realm.getId()).emitKey()) - .reducedWith(new FirstResultReducer()) - .execute(); - - for (String id : ids.keySet()) { - cache.remove(id); + Iterator itr = cache.entrySet().stream().filter(SessionPredicate.create(realm.getId())).map(Mappers.sessionId()).iterator(); + while (itr.hasNext()) { + cache.remove(itr.next()); } } @@ -384,24 +344,18 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { @Override public void removeUserLoginFailure(RealmModel realm, String username) { - LoginFailureKey key = new LoginFailureKey(realm.getId(), username); - tx.remove(loginFailureCache, key); + tx.remove(loginFailureCache, new LoginFailureKey(realm.getId(), username)); } @Override public void removeAllUserLoginFailures(RealmModel realm) { - Map sessions = new MapReduceTask(loginFailureCache) - .mappedWith(UserLoginFailureMapper.create(realm.getId()).emitKey()) - .reducedWith(new FirstResultReducer()) - .execute(); - - for (LoginFailureKey id : sessions.keySet()) { - tx.remove(loginFailureCache, id); + Iterator itr = loginFailureCache.entrySet().stream().filter(UserLoginFailurePredicate.create(realm.getId())).map(Mappers.loginFailureId()).iterator(); + while (itr.hasNext()) { + LoginFailureKey key = itr.next(); + tx.remove(loginFailureCache, key); } } - - @Override public void onRealmRemoved(RealmModel realm) { removeUserSessions(realm, true); @@ -418,18 +372,13 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { private void onClientRemoved(RealmModel realm, ClientModel client, boolean offline) { Cache cache = getCache(offline); - Map map = new MapReduceTask(cache) - .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId())) - .reducedWith(new FirstResultReducer()) - .execute(); - - for (Map.Entry entry : map.entrySet()) { - - // detach from userSession - ClientSessionAdapter adapter = wrap(realm, entry.getValue(), offline); + Iterator> itr = cache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).client(client.getId())).iterator(); + while (itr.hasNext()) { + ClientSessionEntity entity = (ClientSessionEntity) itr.next().getValue(); + ClientSessionAdapter adapter = wrap(realm, entity, offline); 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) { Cache cache = getCache(offline); tx.remove(cache, userSessionId); - // TODO: Isn't more effective to retrieve from userSessionEntity directly? - Map 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); + UserSessionEntity sessionEntity = (UserSessionEntity) cache.get(userSessionId); + if (sessionEntity.getClientSessions() != null) { + for (String clientSessionId : sessionEntity.getClientSessions()) { + tx.remove(cache, clientSessionId); + } } } - InfinispanKeycloakTransaction getTx() { return tx; } @@ -522,7 +463,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { } List wrapUserSessions(RealmModel realm, Collection entities, boolean offline) { - List models = new LinkedList(); + List models = new LinkedList<>(); for (UserSessionEntity e : entities) { models.add(wrap(realm, e, offline)); } @@ -553,7 +494,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { } List wrapClientSessions(RealmModel realm, Collection entities, boolean offline) { - List models = new LinkedList(); + List models = new LinkedList<>(); for (ClientSessionEntity e : entities) { models.add(wrap(realm, e, offline)); } @@ -600,23 +541,21 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { @Override public List getOfflineClientSessions(RealmModel realm, UserModel user) { - Map sessions = new MapReduceTask(offlineSessionCache) - .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId())) - .reducedWith(new FirstResultReducer()) - .execute(); + Iterator> itr = offlineSessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).iterator(); + List clientSessions = new LinkedList<>(); - List clientSessions = new LinkedList<>(); - for (UserSessionEntity userSession : sessions.values()) { - Set currClientSessions = userSession.getClientSessions(); + while(itr.hasNext()) { + UserSessionEntity entity = (UserSessionEntity) itr.next().getValue(); + Set currClientSessions = entity.getClientSessions(); for (String clientSessionId : currClientSessions) { ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId); if (cls != null) { - clientSessions.add(cls); + clientSessions.add(wrap(realm, cls, true)); } } } - return wrapClientSessions(realm, clientSessions, true); + return clientSessions; } @Override @@ -626,7 +565,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { } @Override - public int getOfflineSessionsCount(RealmModel realm, ClientModel client) { + public long getOfflineSessionsCount(RealmModel realm, ClientModel client) { return getUserSessionsCount(realm, client, true); } @@ -721,18 +660,19 @@ public class InfinispanUserSessionProvider implements UserSessionProvider { @Override public List listClientInitialAccess(RealmModel realm) { - Map entities = new MapReduceTask(sessionCache) - .mappedWith(ClientInitialAccessMapper.create(realm.getId())) - .reducedWith(new FirstResultReducer()) - .execute(); - return wrapClientInitialAccess(realm, entities.values()); + Iterator> itr = sessionCache.entrySet().stream().filter(ClientInitialAccessPredicate.create(realm.getId())).iterator(); + List list = new LinkedList<>(); + while (itr.hasNext()) { + list.add(wrap(realm, (ClientInitialAccessEntity) itr.next().getValue())); + } + return list; } class InfinispanKeycloakTransaction implements KeycloakTransaction { private boolean active; private boolean rollback; - private Map tasks = new HashMap(); + private Map tasks = new HashMap<>(); @Override public void begin() { diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java index 382d01f630..e18aa847e0 100755 --- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java @@ -47,7 +47,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider Cache cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME); Cache offlineSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME); Cache 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 { return compatProviderFactory.create(session); } @@ -147,5 +148,9 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider return false; } + private boolean isStreamMode() { + return Version.getVersionShort() >= Version.getVersionShort("8.1.0.Final"); + } + } diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionTimestamp.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionTimestamp.java new file mode 100644 index 0000000000..3284e43158 --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionTimestamp.java @@ -0,0 +1,24 @@ +package org.keycloak.models.sessions.infinispan; + +import java.io.Serializable; + +/** + * @author Stian Thorgersen + */ +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; + } +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java index db20ef8940..693db6718c 100755 --- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java @@ -176,17 +176,6 @@ public class MemUserSessionProvider implements UserSessionProvider { return userSessions; } - @Override - public List getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) { - List userSessions = new LinkedList(); - 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 public List getUserSessions(RealmModel realm, ClientModel client) { return getUserSessions(realm, client, false); @@ -230,7 +219,7 @@ public class MemUserSessionProvider implements UserSessionProvider { } @Override - public int getActiveUserSessions(RealmModel realm, ClientModel client) { + public long getActiveUserSessions(RealmModel realm, ClientModel client) { return getUserSessions(realm, client, false).size(); } @@ -287,7 +276,7 @@ public class MemUserSessionProvider implements UserSessionProvider { } @Override - public void removeExpiredUserSessions(RealmModel realm) { + public void removeExpired(RealmModel realm) { UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class); Iterator itr = userSessions.values().iterator(); @@ -565,7 +554,7 @@ public class MemUserSessionProvider implements UserSessionProvider { } @Override - public int getOfflineSessionsCount(RealmModel realm, ClientModel client) { + public long getOfflineSessionsCount(RealmModel realm, ClientModel client) { return getUserSessions(realm, client, true).size(); } diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java index b368fd3811..2a9058d643 100644 --- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java @@ -151,13 +151,14 @@ public class InfinispanUserSessionInitializer { int processors = Runtime.getRuntime().availableProcessors(); 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; try { while (!state.isFinished()) { - Transport transport = cache.getCacheManager().getTransport(); int nodesCount = transport==null ? 1 : transport.getMembers().size(); int distributedWorkersCount = processors * nodesCount; @@ -173,8 +174,11 @@ public class InfinispanUserSessionInitializer { for (Integer segment : segments) { SessionInitializerWorker worker = new SessionInitializerWorker(); worker.setWorkerEnvironment(segment, sessionsPerSegment, sessionLoader); + if (!distributed) { + worker.setEnvironment(cache, null); + } - Future future = distributedExecutorService.submit(worker); + Future future = executorService.submit(worker); futures.add(future); } @@ -210,7 +214,9 @@ public class InfinispanUserSessionInitializer { } } } finally { - distributedExecutorService.shutdown(); + if (distributed) { + executorService.shutdown(); + } localExecutor.shutdown(); } } diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientInitialAccessPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientInitialAccessPredicate.java new file mode 100644 index 0000000000..22518ef679 --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientInitialAccessPredicate.java @@ -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 Stian Thorgersen + */ +public class ClientInitialAccessPredicate implements Predicate>, 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 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; + } + +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientSessionPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientSessionPredicate.java new file mode 100644 index 0000000000..490b8f4906 --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientSessionPredicate.java @@ -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 Stian Thorgersen + */ +public class ClientSessionPredicate implements Predicate>, 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 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; + } + +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Comparators.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Comparators.java new file mode 100644 index 0000000000..ba7fd0234d --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Comparators.java @@ -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 Stian Thorgersen + */ +public class Comparators { + + public static Comparator userSessionTimestamp() { + return new UserSessionTimestampComparator(); + } + + private static class UserSessionTimestampComparator implements Comparator, Serializable { + @Override + public int compare(UserSessionTimestamp u1, UserSessionTimestamp u2) { + return u1.getClientSessionTimestamp() - u2.getClientSessionTimestamp(); + } + } + +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java new file mode 100644 index 0000000000..3164f6dbfb --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java @@ -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 Stian Thorgersen + */ +public class Mappers { + + public static Function, UserSessionTimestamp> clientSessionToUserSessionTimestamp() { + return new ClientSessionToUserSessionTimestampMapper(); + } + + public static Function>, UserSessionTimestamp> userSessionTimestamp() { + return new UserSessionTimestampMapper(); + } + + public static Function, String> sessionId() { + return new SessionIdMapper(); + } + + public static Function, LoginFailureKey> loginFailureId() { + return new LoginFailureIdMapper(); + } + + public static Function, String> clientSessionToUserSessionId() { + return new ClientSessionToUserSessionIdMapper(); + } + + private static class ClientSessionToUserSessionTimestampMapper implements Function, UserSessionTimestamp>, Serializable { + @Override + public UserSessionTimestamp apply(Map.Entry entry) { + SessionEntity e = entry.getValue(); + ClientSessionEntity entity = (ClientSessionEntity) e; + return new UserSessionTimestamp(entity.getUserSession(), entity.getTimestamp()); + } + } + + private static class UserSessionTimestampMapper implements Function>, org.keycloak.models.sessions.infinispan.UserSessionTimestamp>, Serializable { + @Override + public org.keycloak.models.sessions.infinispan.UserSessionTimestamp apply(Map.Entry> e) { + return e.getValue().get(); + } + } + + private static class SessionIdMapper implements Function, String>, Serializable { + @Override + public String apply(Map.Entry entry) { + return entry.getKey(); + } + } + + private static class LoginFailureIdMapper implements Function, LoginFailureKey>, Serializable { + @Override + public LoginFailureKey apply(Map.Entry entry) { + return entry.getKey(); + } + } + + private static class ClientSessionToUserSessionIdMapper implements Function, String>, Serializable { + @Override + public String apply(Map.Entry entry) { + SessionEntity e = entry.getValue(); + ClientSessionEntity entity = (ClientSessionEntity) e; + return entity.getUserSession(); + } + } +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java new file mode 100755 index 0000000000..6dd5540b3d --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java @@ -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 Stian Thorgersen + */ +public class SessionPredicate implements Predicate>, 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 entry) { + return realm.equals(entry.getValue().getRealm()); + } + +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java new file mode 100755 index 0000000000..fb0fb7ecab --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java @@ -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 Stian Thorgersen + */ +public class UserLoginFailurePredicate implements Predicate>, 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 entry) { + LoginFailureEntity e = entry.getValue(); + return realm.equals(e.getRealm()); + } + +} diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java new file mode 100644 index 0000000000..2add0492dd --- /dev/null +++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java @@ -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 Stian Thorgersen + */ +public class UserSessionPredicate implements Predicate>, 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 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; + } +} diff --git a/pom.xml b/pom.xml index b2aa2f416b..03e1416a39 100755 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jboss jboss-parent - 16 + 19 Keycloak @@ -49,8 +49,8 @@ 1.6.1 1.4.01 1.7.7 - 10.0.0.CR4 - 2.0.1.Final + 10.0.0.CR5 + 2.0.5.Final 1.1.0.Final @@ -66,7 +66,7 @@ 2.2.11 20140925 1.4.5 - 6.0.2.Final + 8.1.0.Final 3.4.1 9.1.0.v20131115 4.2.0 diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java index eef260b191..7c19f6156d 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java @@ -399,9 +399,9 @@ public class ClientResource { @GET @NoCache @Produces(MediaType.APPLICATION_JSON) - public Map getApplicationSessionCount() { + public Map getApplicationSessionCount() { auth.requireView(); - Map map = new HashMap(); + Map map = new HashMap<>(); map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client)); return map; } @@ -446,9 +446,9 @@ public class ClientResource { @GET @NoCache @Produces(MediaType.APPLICATION_JSON) - public Map getOfflineSessionCount() { + public Map getOfflineSessionCount() { auth.requireView(); - Map map = new HashMap(); + Map map = new HashMap<>(); map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client)); return map; } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 9d144e4c2d..cb97855f02 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -369,9 +369,9 @@ public class RealmAdminResource { auth.requireView(); List> data = new LinkedList>(); 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; - Map map = new HashMap(); + Map map = new HashMap<>(); map.put("id", client.getId()); map.put("clientId", client.getClientId()); map.put("active", size + ""); diff --git a/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java b/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java index 96c8baded6..8f6b91c457 100755 --- a/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java +++ b/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java @@ -13,7 +13,7 @@ public class ClearExpiredUserSessions implements ScheduledTask { public void run(KeycloakSession session) { UserSessionProvider sessions = session.sessions(); for (RealmModel realm : session.realms().getRealms()) { - sessions.removeExpiredUserSessions(realm); + sessions.removeExpired(realm); } } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java index 5d02107f5f..08529ca5c5 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java @@ -100,6 +100,8 @@ public class AdapterTest { @Test public void testLoginSSOAndLogout() throws Exception { + testStrategy.testLoginSSOMax(); + testStrategy.testLoginSSOAndLogout(); } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java index 1e6009674a..f93c4ebf87 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java @@ -310,7 +310,7 @@ public class AdapterTestStrategy extends ExternalResource { session = keycloakRule.startSession(); realm = session.realms().getRealmByName("demo"); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); session.getTransaction().commit(); session.close(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java index 4d438972f8..19beaf6edf 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java @@ -286,9 +286,6 @@ public class BruteForceTest { } - - - @Test public void testBrowserInvalidPassword() throws Exception { loginSuccess(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java index 30d94fae78..c12e6feb58 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java @@ -524,7 +524,7 @@ public class LoginTest { keycloakRule.update(new KeycloakRule.KeycloakSetup() { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - manager.getSession().sessions().removeExpiredUserSessions(appRealm); + manager.getSession().sessions().removeExpired(appRealm); } }); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java index ab93b1c663..147ee8619f 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java @@ -347,7 +347,7 @@ public class UserSessionProviderOfflineTest { resetSession(); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); @@ -372,7 +372,7 @@ public class UserSessionProviderOfflineTest { // Expire everything and assert nothing found Time.setOffset(3000000); try { - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java index 88e7597ddc..81064583f7 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java @@ -17,11 +17,7 @@ import org.keycloak.services.managers.UserManager; import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.common.util.Time; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.junit.Assert.*; @@ -276,7 +272,7 @@ public class UserSessionProviderTest { resetSession(); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); for (String e : expired) { @@ -309,13 +305,13 @@ public class UserSessionProviderTest { resetSession(); Time.setOffset(25); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); assertNotNull(session.sessions().getClientSession(clientSessionId)); Time.setOffset(35); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); assertNull(session.sessions().getClientSession(clientSessionId)); @@ -328,13 +324,13 @@ public class UserSessionProviderTest { resetSession(); Time.setOffset(35); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); assertNotNull(session.sessions().getClientSession(clientSessionId)); Time.setOffset(45); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); assertNull(session.sessions().getClientSession(clientSessionId)); @@ -347,13 +343,13 @@ public class UserSessionProviderTest { resetSession(); Time.setOffset(45); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); assertNotNull(session.sessions().getClientSession(clientSessionId)); Time.setOffset(55); - session.sessions().removeExpiredUserSessions(realm); + session.sessions().removeExpired(realm); resetSession(); assertNull(session.sessions().getClientSession(clientSessionId)); @@ -463,6 +459,18 @@ public class UserSessionProviderTest { failure1 = session.sessions().getUserLoginFailure(realm, "user1"); 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 diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java index caa61edefd..1af7515dc3 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java @@ -263,7 +263,7 @@ public class OfflineTokenTest { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - manager.getSession().sessions().removeExpiredUserSessions(appRealm); + manager.getSession().sessions().removeExpired(appRealm); } });