keycloak-uncached
Changes
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java 6(+1 -5)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java 7(+5 -2)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProviderFactory.java 7(+6 -1)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java 14(+13 -1)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java 15(+14 -1)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java 20(+15 -5)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java 5(+4 -1)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/InfinispanKeyGenerator.java 106(+106 -0)
model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoveSessionTest.java 2(+1 -1)
model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java 2(+1 -1)
model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheConcurrentWritesTest.java 2(+1 -1)
model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheWriteSkewTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java 27(+27 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java 160(+160 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java 12(+5 -7)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java 6(+3 -3)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java 10(+5 -5)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java 12(+6 -6)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java 18(+9 -9)
Details
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java
index 16ce4ab..bc7d1e8 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java
@@ -58,14 +58,10 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
private final UUID id;
- private AuthenticatedClientSessionEntity(UUID id) {
+ public AuthenticatedClientSessionEntity(UUID id) {
this.id = id;
}
- public AuthenticatedClientSessionEntity() {
- this.id = UUID.randomUUID();
- }
-
public String getAuthMethod() {
return authMethod;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java
index 47174f8..ce2105a 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java
@@ -32,6 +32,7 @@ import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessio
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.stream.RootAuthenticationSessionPredicate;
+import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RealmInfoUtil;
import org.keycloak.sessions.AuthenticationSessionProvider;
@@ -46,12 +47,14 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
private final KeycloakSession session;
private final Cache<String, RootAuthenticationSessionEntity> cache;
+ private final InfinispanKeyGenerator keyGenerator;
protected final InfinispanKeycloakTransaction tx;
protected final SessionEventsSenderTransaction clusterEventsSenderTx;
- public InfinispanAuthenticationSessionProvider(KeycloakSession session, Cache<String, RootAuthenticationSessionEntity> cache) {
+ public InfinispanAuthenticationSessionProvider(KeycloakSession session, InfinispanKeyGenerator keyGenerator, Cache<String, RootAuthenticationSessionEntity> cache) {
this.session = session;
this.cache = cache;
+ this.keyGenerator = keyGenerator;
this.tx = new InfinispanKeycloakTransaction();
this.clusterEventsSenderTx = new SessionEventsSenderTransaction(session);
@@ -62,7 +65,7 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
@Override
public RootAuthenticationSessionModel createRootAuthenticationSession(RealmModel realm) {
- String id = KeycloakModelUtils.generateId();
+ String id = keyGenerator.generateKeyString(session, cache);
return createRootAuthenticationSession(id, realm);
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProviderFactory.java
index 4055885..02a6f4d 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProviderFactory.java
@@ -30,6 +30,7 @@ import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessio
import org.keycloak.models.sessions.infinispan.events.AbstractAuthSessionClusterListener;
import org.keycloak.models.sessions.infinispan.events.ClientRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
+import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.utils.PostMigrationEvent;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
@@ -47,6 +48,8 @@ public class InfinispanAuthenticationSessionProviderFactory implements Authentic
private static final Logger log = Logger.getLogger(InfinispanAuthenticationSessionProviderFactory.class);
+ private InfinispanKeyGenerator keyGenerator;
+
private volatile Cache<String, RootAuthenticationSessionEntity> authSessionsCache;
public static final String PROVIDER_ID = "infinispan";
@@ -105,7 +108,7 @@ public class InfinispanAuthenticationSessionProviderFactory implements Authentic
@Override
public AuthenticationSessionProvider create(KeycloakSession session) {
lazyInit(session);
- return new InfinispanAuthenticationSessionProvider(session, authSessionsCache);
+ return new InfinispanAuthenticationSessionProvider(session, keyGenerator, authSessionsCache);
}
private void updateAuthNotes(ClusterEvent clEvent) {
@@ -149,6 +152,8 @@ public class InfinispanAuthenticationSessionProviderFactory implements Authentic
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
authSessionsCache = connections.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME);
+ keyGenerator = new InfinispanKeyGenerator();
+
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.registerListener(AUTHENTICATION_SESSION_EVENTS, this::updateAuthNotes);
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java
index 0aca09f..871525d 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProvider.java
@@ -31,14 +31,20 @@ public class InfinispanStickySessionEncoderProvider implements StickySessionEnco
private final KeycloakSession session;
private final String myNodeName;
+ private final boolean shouldAttachRoute;
- public InfinispanStickySessionEncoderProvider(KeycloakSession session, String myNodeName) {
+ public InfinispanStickySessionEncoderProvider(KeycloakSession session, String myNodeName, boolean shouldAttachRoute) {
this.session = session;
this.myNodeName = myNodeName;
+ this.shouldAttachRoute = shouldAttachRoute;
}
@Override
public String encodeSessionId(String sessionId) {
+ if (!shouldAttachRoute) {
+ return sessionId;
+ }
+
String nodeName = getNodeName(sessionId);
if (nodeName != null) {
return sessionId + '.' + nodeName;
@@ -49,11 +55,17 @@ public class InfinispanStickySessionEncoderProvider implements StickySessionEnco
@Override
public String decodeSessionId(String encodedSessionId) {
+ // Try to decode regardless if shouldAttachRoute is true/false. It's possible that some loadbalancers may forward the route information attached by them to the backend keycloak server. We need to remove it then.
int index = encodedSessionId.indexOf('.');
return index == -1 ? encodedSessionId : encodedSessionId.substring(0, index);
}
@Override
+ public boolean shouldAttachRoute() {
+ return shouldAttachRoute;
+ }
+
+ @Override
public void close() {
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java
index 2477b69..001e295 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java
@@ -17,6 +17,7 @@
package org.keycloak.models.sessions.infinispan;
+import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
@@ -30,6 +31,10 @@ import org.keycloak.sessions.StickySessionEncoderProviderFactory;
*/
public class InfinispanStickySessionEncoderProviderFactory implements StickySessionEncoderProviderFactory {
+ private static final Logger log = Logger.getLogger(InfinispanStickySessionEncoderProviderFactory.class);
+
+
+ private boolean shouldAttachRoute;
@Override
public StickySessionEncoderProvider create(KeycloakSession session) {
@@ -41,11 +46,19 @@ public class InfinispanStickySessionEncoderProviderFactory implements StickySess
myNodeName = null;
}
- return new InfinispanStickySessionEncoderProvider(session, myNodeName);
+ return new InfinispanStickySessionEncoderProvider(session, myNodeName, shouldAttachRoute);
}
@Override
public void init(Config.Scope config) {
+ this.shouldAttachRoute = config.getBoolean("shouldAttachRoute", true);
+ log.debugf("Should attach route to the sticky session cookie: %b", shouldAttachRoute);
+
+ }
+
+ // Used for testing
+ public void setShouldAttachRoute(boolean shouldAttachRoute) {
+ this.shouldAttachRoute = shouldAttachRoute;
}
@Override
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
index eb49db4..7c7679f 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
@@ -54,10 +54,10 @@ import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserLoginFailurePredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
+import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
import org.keycloak.models.utils.SessionTimeoutHelper;
-import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -96,10 +96,13 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
protected final LastSessionRefreshStore lastSessionRefreshStore;
protected final LastSessionRefreshStore offlineLastSessionRefreshStore;
+ protected final InfinispanKeyGenerator keyGenerator;
+
public InfinispanUserSessionProvider(KeycloakSession session,
RemoteCacheInvoker remoteCacheInvoker,
LastSessionRefreshStore lastSessionRefreshStore,
LastSessionRefreshStore offlineLastSessionRefreshStore,
+ InfinispanKeyGenerator keyGenerator,
Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionCache,
Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionCache,
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionCache,
@@ -124,6 +127,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
this.lastSessionRefreshStore = lastSessionRefreshStore;
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
+ this.keyGenerator = keyGenerator;
session.getTransactionManager().enlistAfterCompletion(clusterEventsSenderTx);
session.getTransactionManager().enlistAfterCompletion(sessionTx);
@@ -159,10 +163,10 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
@Override
public AuthenticatedClientSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession) {
- AuthenticatedClientSessionEntity entity = new AuthenticatedClientSessionEntity();
+ final UUID clientSessionId = keyGenerator.generateKeyUUID(session, clientSessionCache);
+ AuthenticatedClientSessionEntity entity = new AuthenticatedClientSessionEntity(clientSessionId);
entity.setRealmId(realm.getId());
entity.setTimestamp(Time.currentTime());
- final UUID clientSessionId = entity.getId();
InfinispanChangelogBasedTransaction<String, UserSessionEntity> userSessionUpdateTx = getTransaction(false);
InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx = getClientSessionTransaction(false);
@@ -178,6 +182,12 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
@Override
+ public UserSessionModel createUserSession(RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId) {
+ final String userSessionId = keyGenerator.generateKeyString(session, sessionCache);
+ return createUserSession(userSessionId, realm, user, loginUsername, ipAddress, authMethod, rememberMe, brokerSessionId, brokerUserId);
+ }
+
+ @Override
public UserSessionModel createUserSession(String id, RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId) {
UserSessionEntity entity = new UserSessionEntity();
entity.setId(id);
@@ -872,9 +882,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
InfinispanChangelogBasedTransaction<String, UserSessionEntity> userSessionUpdateTx,
InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx,
boolean offline) {
- AuthenticatedClientSessionEntity entity = new AuthenticatedClientSessionEntity();
+ final UUID clientSessionId = keyGenerator.generateKeyUUID(session, getClientSessionCache(offline));
+ AuthenticatedClientSessionEntity entity = new AuthenticatedClientSessionEntity(clientSessionId);
entity.setRealmId(sessionToImportInto.getRealm().getId());
- final UUID clientSessionId = entity.getId();
entity.setAction(clientSession.getAction());
entity.setAuthMethod(clientSession.getProtocol());
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
index 697c3f2..dc6e261 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
@@ -51,6 +51,7 @@ import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitia
import org.keycloak.models.sessions.infinispan.initializer.OfflinePersistentUserSessionLoader;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader;
+import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent;
@@ -80,6 +81,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
private RemoteCacheInvoker remoteCacheInvoker;
private LastSessionRefreshStore lastSessionRefreshStore;
private LastSessionRefreshStore offlineLastSessionRefreshStore;
+ private InfinispanKeyGenerator keyGenerator;
@Override
public InfinispanUserSessionProvider create(KeycloakSession session) {
@@ -90,7 +92,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> offlineClientSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME);
Cache<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
- return new InfinispanUserSessionProvider(session, remoteCacheInvoker, lastSessionRefreshStore, offlineLastSessionRefreshStore,
+ return new InfinispanUserSessionProvider(session, remoteCacheInvoker, lastSessionRefreshStore, offlineLastSessionRefreshStore, keyGenerator,
cache, offlineSessionsCache, clientSessionCache, offlineClientSessionsCache, loginFailures);
}
@@ -109,6 +111,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
if (event instanceof PostMigrationEvent) {
KeycloakSession session = ((PostMigrationEvent) event).getSession();
+ keyGenerator = new InfinispanKeyGenerator();
checkRemoteCaches(session);
loadPersistentSessions(factory, getMaxErrors(), getSessionsPerSegment());
registerClusterListeners(session);
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/InfinispanKeyGenerator.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/InfinispanKeyGenerator.java
new file mode 100644
index 0000000..a899363
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/InfinispanKeyGenerator.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan.util;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+
+import org.infinispan.Cache;
+import org.infinispan.affinity.KeyAffinityService;
+import org.infinispan.affinity.KeyAffinityServiceFactory;
+import org.infinispan.affinity.KeyGenerator;
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.sessions.StickySessionEncoderProvider;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class InfinispanKeyGenerator {
+
+ private static final Logger log = Logger.getLogger(InfinispanKeyGenerator.class);
+
+
+ private final Map<String, KeyAffinityService> keyAffinityServices = new ConcurrentHashMap<>();
+
+
+ public String generateKeyString(KeycloakSession session, Cache<String, ?> cache) {
+ return generateKey(session, cache, new StringKeyGenerator());
+ }
+
+
+ public UUID generateKeyUUID(KeycloakSession session, Cache<UUID, ?> cache) {
+ return generateKey(session, cache, new UUIDKeyGenerator());
+ }
+
+
+ private <K> K generateKey(KeycloakSession session, Cache<K, ?> cache, KeyGenerator<K> keyGenerator) {
+ String cacheName = cache.getName();
+
+ // "wantsLocalKey" is true if route is not attached to the sticky session cookie. Without attached route, We want the key, which will be "owned" by this node.
+ // This is needed due the fact that external loadbalancer will attach route corresponding to our node, which will be the owner of the particular key, hence we
+ // will be able to lookup key locally.
+ boolean wantsLocalKey = !session.getProvider(StickySessionEncoderProvider.class).shouldAttachRoute();
+
+ if (wantsLocalKey && cache.getCacheConfiguration().clustering().cacheMode().isClustered()) {
+ KeyAffinityService<K> keyAffinityService = keyAffinityServices.get(cacheName);
+ if (keyAffinityService == null) {
+ keyAffinityService = createKeyAffinityService(cache, keyGenerator);
+ keyAffinityServices.put(cacheName, keyAffinityService);
+
+ log.debugf("Registered key affinity service for cache '%s'", cacheName);
+ }
+
+ return keyAffinityService.getKeyForAddress(cache.getCacheManager().getAddress());
+ } else {
+ return keyGenerator.getKey();
+ }
+
+ }
+
+
+ private <K> KeyAffinityService<K> createKeyAffinityService(Cache<K, ?> cache, KeyGenerator<K> keyGenerator) {
+ // SingleThreadExecutor is recommended due it needs the single thread and leave it in the WAITING state
+ return KeyAffinityServiceFactory.newLocalKeyAffinityService(
+ cache,
+ keyGenerator,
+ Executors.newSingleThreadExecutor(),
+ 16);
+ }
+
+
+ private static class UUIDKeyGenerator implements KeyGenerator<UUID> {
+
+ @Override
+ public UUID getKey() {
+ return UUID.randomUUID();
+ }
+ }
+
+
+ private static class StringKeyGenerator implements KeyGenerator<String> {
+
+ @Override
+ public String getKey() {
+ return KeycloakModelUtils.generateId();
+ }
+ }
+}
diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoveSessionTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoveSessionTest.java
index 7e55783..7bd0854 100644
--- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoveSessionTest.java
+++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGRemoveSessionTest.java
@@ -174,7 +174,7 @@ public class ConcurrencyJDGRemoveSessionTest {
session.setStarted(Time.currentTime());
session.setLastSessionRefresh(Time.currentTime());
- AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity();
+ AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity(UUID.randomUUID());
clientSession.setAuthMethod("saml");
clientSession.setAction("something");
clientSession.setTimestamp(1234);
diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java
index 2e4428a..2a26a3c 100644
--- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java
+++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java
@@ -93,7 +93,7 @@ public class ConcurrencyJDGSessionsCacheTest {
session.setStarted(Time.currentTime());
session.setLastSessionRefresh(Time.currentTime());
- AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity();
+ AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity(UUID.randomUUID());
clientSession.setAuthMethod("saml");
clientSession.setAction("something");
clientSession.setTimestamp(1234);
diff --git a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheConcurrentWritesTest.java b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheConcurrentWritesTest.java
index a9bb784..af9139f 100644
--- a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheConcurrentWritesTest.java
+++ b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheConcurrentWritesTest.java
@@ -71,7 +71,7 @@ public class DistributedCacheConcurrentWritesTest {
session.setStarted(Time.currentTime());
session.setLastSessionRefresh(Time.currentTime());
- AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity();
+ AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity(UUID.randomUUID());
clientSession.setAuthMethod("saml");
clientSession.setAction("something");
clientSession.setTimestamp(1234);
diff --git a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheWriteSkewTest.java b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheWriteSkewTest.java
index d6bc350..23f25b7 100644
--- a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheWriteSkewTest.java
+++ b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/DistributedCacheWriteSkewTest.java
@@ -71,7 +71,7 @@ public class DistributedCacheWriteSkewTest {
session.setStarted(Time.currentTime());
session.setLastSessionRefresh(Time.currentTime());
- AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity();
+ AuthenticatedClientSessionEntity clientSession = new AuthenticatedClientSessionEntity(UUID.randomUUID());
clientSession.setAuthMethod("saml");
clientSession.setAction("something");
clientSession.setTimestamp(1234);
diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
index cd265f2..fc67d4e 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
@@ -32,6 +32,7 @@ public interface UserSessionProvider extends Provider {
AuthenticatedClientSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession);
AuthenticatedClientSessionModel getClientSession(UserSessionModel userSession, ClientModel client, UUID clientSessionId, boolean offline);
+ UserSessionModel createUserSession(RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId);
UserSessionModel createUserSession(String id, RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId);
UserSessionModel getUserSession(RealmModel realm, String id);
List<UserSessionModel> getUserSessions(RealmModel realm, UserModel user);
diff --git a/server-spi-private/src/main/java/org/keycloak/sessions/StickySessionEncoderProvider.java b/server-spi-private/src/main/java/org/keycloak/sessions/StickySessionEncoderProvider.java
index 69dad56..752fd01 100644
--- a/server-spi-private/src/main/java/org/keycloak/sessions/StickySessionEncoderProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/sessions/StickySessionEncoderProvider.java
@@ -24,8 +24,24 @@ import org.keycloak.provider.Provider;
*/
public interface StickySessionEncoderProvider extends Provider {
+
+ /**
+ * @param sessionId
+ * @return Encoded value to be used as the value of sticky session cookie (AUTH_SESSION_ID cookie)
+ */
String encodeSessionId(String sessionId);
+
+ /**
+ * @param encodedSessionId value of the sticky session cookie
+ * @return decoded value, which represents the actual ID of the {@link AuthenticationSessionModel}
+ */
String decodeSessionId(String encodedSessionId);
+
+ /**
+ * @return true if information about route should be attached to the sticky session cookie by Keycloak. Otherwise it may be attached by loadbalancer.
+ */
+ boolean shouldAttachRoute();
+
}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
index e74bc11..d1acce0 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -234,13 +234,12 @@ public class PolicyEvaluationService {
if (clientId != null) {
ClientModel clientModel = realm.getClientById(clientId);
- String id = KeycloakModelUtils.generateId();
- AuthenticationSessionModel authSession = keycloakSession.authenticationSessions().createRootAuthenticationSession(id, realm)
+ AuthenticationSessionModel authSession = keycloakSession.authenticationSessions().createRootAuthenticationSession(realm)
.createAuthenticationSession(clientModel);
authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
authSession.setAuthenticatedUser(userModel);
- userSession = keycloakSession.sessions().createUserSession(id, realm, userModel, userModel.getUsername(), "127.0.0.1", "passwd", false, null, null);
+ userSession = keycloakSession.sessions().createUserSession(authSession.getParentSession().getId(), realm, userModel, userModel.getUsername(), "127.0.0.1", "passwd", false, null, null);
AuthenticationManager.setRolesAndMappersInSession(authSession);
clientSession = TokenManager.attachAuthenticationSession(keycloakSession, userSession, authSession);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index 1826edf..649bccb 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -699,9 +699,8 @@ public class TokenEndpoint {
}
}
- String sessionId = KeycloakModelUtils.generateId();
tokenUser = requestedUser;
- tokenSession = session.sessions().createUserSession(sessionId, realm, requestedUser, requestedUser.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
+ tokenSession = session.sessions().createUserSession(realm, requestedUser, requestedUser.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
}
String requestedIssuer = formParams.getFirst(OAuth2Constants.REQUESTED_ISSUER);
@@ -850,8 +849,7 @@ public class TokenEndpoint {
UserModel user = importUserFromExternalIdentity(context);
- String sessionId = KeycloakModelUtils.generateId();
- UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "external-exchange", false, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "external-exchange", false, null, null);
externalIdp.exchangeExternalComplete(userSession, context, formParams);
// this must exist so that we can obtain access token from user session if idp's store tokens is off
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
index dcfd651..eaf7285 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java
@@ -281,8 +281,7 @@ public class UserResource {
}
EventBuilder event = new EventBuilder(realm, session, clientConnection);
- String sessionId = KeycloakModelUtils.generateId();
- UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null);
AuthenticationManager.createLoginCookie(session, realm, userSession.getUser(), userSession, uriInfo, clientConnection);
URI redirect = AccountFormService.accountServiceApplicationPage(uriInfo).build(realm.getName());
Map<String, Object> result = new HashMap<>();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
index d5c9ff2..d15fa54 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java
@@ -8,6 +8,7 @@ import org.keycloak.models.Constants;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.arquillian.ContainerInfo;
+import org.keycloak.testsuite.client.KeycloakTestingClient;
import java.util.HashMap;
import java.util.HashSet;
@@ -26,11 +27,17 @@ import static org.keycloak.testsuite.util.WaitUtils.pause;
*/
public abstract class AbstractClusterTest extends AbstractKeycloakTest {
+ // Keep the following constants in sync with arquillian
+ public static final String QUALIFIER_AUTH_SERVER_NODE_1 = "auth-server-${auth.server}-backend1";
+ public static final String QUALIFIER_AUTH_SERVER_NODE_2 = "auth-server-${auth.server}-backend2";
+
@ArquillianResource
protected ContainerController controller;
protected Map<ContainerInfo, Keycloak> backendAdminClients = new HashMap<>();
+ protected Map<ContainerInfo, KeycloakTestingClient> backendTestingClients = new HashMap<>();
+
private int currentFailNodeIndex = 0;
public int getClusterSize() {
@@ -101,6 +108,9 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
if (!backendAdminClients.containsKey(node)) {
backendAdminClients.put(node, createAdminClientFor(node));
}
+ if (!backendTestingClients.containsKey(node)) {
+ backendTestingClients.put(node, createTestingClientFor(node));
+ }
}
protected Keycloak createAdminClientFor(ContainerInfo node) {
@@ -109,9 +119,16 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
}
+ protected KeycloakTestingClient createTestingClientFor(ContainerInfo node) {
+ log.info("Initializing testing client for " + node.getContextRoot() + "/auth");
+ return KeycloakTestingClient.getInstance(node.getContextRoot() + "/auth");
+ }
+
protected void killBackendNode(ContainerInfo node) {
backendAdminClients.get(node).close();
backendAdminClients.remove(node);
+ backendTestingClients.get(node).close();
+ backendTestingClients.remove(node);
log.info("Killing backend node: " + node);
controller.kill(node.getQualifier());
}
@@ -126,6 +143,16 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
return adminClient;
}
+ protected KeycloakTestingClient getTestingClientFor(ContainerInfo node) {
+ KeycloakTestingClient testingClient = backendTestingClients.get(node);
+
+ if (testingClient == null && node.equals(suiteContext.getAuthServerInfo())) {
+ testingClient = this.testingClient;
+ }
+
+ return testingClient;
+ }
+
@Before
public void beforeClusterTest() {
failback();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java
new file mode 100644
index 0000000..684b13d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.cluster;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.hamcrest.Matchers;
+import org.infinispan.Cache;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.sessions.infinispan.InfinispanStickySessionEncoderProviderFactory;
+import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.sessions.StickySessionEncoderProvider;
+import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
+import org.keycloak.testsuite.client.KeycloakTestingClient;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
+import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
+import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
+
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AuthenticationSessionClusterTest extends AbstractClusterTest {
+
+ @Deployment(name = "node0")
+ @TargetsContainer(QUALIFIER_AUTH_SERVER_NODE_1)
+ public static WebArchive deployDC0() {
+ return RunOnServerDeployment.create(
+ AuthenticationSessionClusterTest.class,
+ AbstractClusterTest.class,
+ AbstractTestRealmKeycloakTest.class,
+ KeycloakTestingClient.class
+ );
+ }
+
+
+ @Page
+ protected LoginPage loginPage;
+
+ @Page
+ protected LoginPasswordUpdatePage updatePasswordPage;
+
+
+ @Page
+ protected LoginUpdateProfilePage updateProfilePage;
+
+ @Page
+ protected AppPage appPage;
+
+
+ @Before
+ public void setup() {
+ try {
+ adminClient.realm("test").remove();
+ } catch (Exception ignore) {
+ }
+
+ RealmRepresentation testRealm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+ adminClient.realms().create(testRealm);
+ }
+
+ @After
+ public void after() {
+ adminClient.realm("test").remove();
+ }
+
+
+ @Test
+ public void testAuthSessionCookieWithAttachedRoute() throws Exception {
+ // TODO Maybe add compatibility between cluster and cross-dc tests regarding route name (jboss.node.name). Cross-dc tests use arquillian container qualifier when cluster tests just 'node1' .
+// String node1Route = backendNode(0).getArquillianContainer().getName();
+// String node2Route = backendNode(1).getArquillianContainer().getName();
+
+ String accountServiceNode1URL = RealmsResource.accountUrl(UriBuilder.fromUri(backendNode(0).getUriBuilder().build() + "/auth")).build("test").toString();
+ String accountServiceNode2URL = RealmsResource.accountUrl(UriBuilder.fromUri(backendNode(1).getUriBuilder().build() + "/auth")).build("test").toString();
+
+ Set<String> visitedRoutes = new HashSet<>();
+ for (int i = 0; i < 20; i++) {
+ driver.navigate().to(accountServiceNode1URL);
+ String authSessionCookie = AuthenticationSessionFailoverClusterTest.getAuthSessionCookieValue(driver);
+
+ Assert.assertThat(authSessionCookie.length(), Matchers.greaterThan(36));
+ String route = authSessionCookie.substring(37);
+ visitedRoutes.add(route);
+
+ // Drop all cookies before continue
+ driver.manage().deleteAllCookies();
+ }
+
+ Assert.assertThat(visitedRoutes, Matchers.containsInAnyOrder("node1", "node2"));
+ }
+
+
+ @Test
+ public void testAuthSessionCookieWithoutRoute() throws Exception {
+ String accountServiceNode1URL = RealmsResource.accountUrl(UriBuilder.fromUri(backendNode(0).getUriBuilder().build() + "/auth")).build("test").toString();
+ String accountServiceNode2URL = RealmsResource.accountUrl(UriBuilder.fromUri(backendNode(1).getUriBuilder().build() + "/auth")).build("test").toString();
+
+ // Disable route on backend server
+ getTestingClientFor(backendNode(0)).server().run(session -> {
+ InfinispanStickySessionEncoderProviderFactory factory = (InfinispanStickySessionEncoderProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(StickySessionEncoderProvider.class, "infinispan");
+ factory.setShouldAttachRoute(false);
+ });
+
+ // Test routes
+ for (int i = 0; i < 20; i++) {
+ driver.navigate().to(accountServiceNode1URL);
+ String authSessionCookie = AuthenticationSessionFailoverClusterTest.getAuthSessionCookieValue(driver);
+
+ Assert.assertEquals(36, authSessionCookie.length());
+
+ // Drop all cookies before continue
+ driver.manage().deleteAllCookies();
+
+ // Check that route owner is always node1
+ getTestingClientFor(backendNode(0)).server().run(session -> {
+ Cache authSessionCache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME);
+ String keyOwner = InfinispanUtil.getKeyPrimaryOwnerAddress(authSessionCache, authSessionCookie);
+ Assert.assertEquals("node1", keyOwner);
+ });
+ }
+
+ // Revert route on backend server
+ getTestingClientFor(backendNode(0)).server().run(session -> {
+ InfinispanStickySessionEncoderProviderFactory factory = (InfinispanStickySessionEncoderProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(StickySessionEncoderProvider.class, "infinispan");
+ factory.setShouldAttachRoute(true);
+ });
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java
index c1811f9..817bdc6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java
@@ -18,7 +18,6 @@
package org.keycloak.testsuite.cluster;
import java.io.IOException;
-import java.util.List;
import javax.mail.MessagingException;
@@ -30,7 +29,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationSessionManager;
-import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.pages.AppPage;
@@ -39,9 +37,9 @@ import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
import org.keycloak.testsuite.util.UserBuilder;
import org.openqa.selenium.Cookie;
+import org.openqa.selenium.WebDriver;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
import static org.keycloak.testsuite.util.WaitUtils.pause;
@@ -113,14 +111,14 @@ public class AuthenticationSessionFailoverClusterTest extends AbstractFailoverCl
protected void failoverTest(boolean expectSuccessfulFailover) throws IOException, MessagingException {
loginPage.open();
- String cookieValue1 = getAuthSessionCookieValue();
+ String cookieValue1 = getAuthSessionCookieValue(driver);
// Login and assert on "updatePassword" page
loginPage.login("login-test", "password");
updatePasswordPage.assertCurrent();
// Route didn't change
- Assert.assertEquals(cookieValue1, getAuthSessionCookieValue());
+ Assert.assertEquals(cookieValue1, getAuthSessionCookieValue(driver));
log.info("Authentication session cookie: " + cookieValue1);
@@ -137,7 +135,7 @@ public class AuthenticationSessionFailoverClusterTest extends AbstractFailoverCl
//Action was successful
updateProfilePage.assertCurrent();
- String cookieValue2 = getAuthSessionCookieValue();
+ String cookieValue2 = getAuthSessionCookieValue(driver);
log.info("Authentication session cookie after failover: " + cookieValue2);
@@ -163,7 +161,7 @@ public class AuthenticationSessionFailoverClusterTest extends AbstractFailoverCl
appPage.assertCurrent();
}
- private String getAuthSessionCookieValue() {
+ static String getAuthSessionCookieValue(WebDriver driver) {
Cookie authSessionCookie = driver.manage().getCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID);
Assert.assertNotNull(authSessionCookie);
return authSessionCookie.getValue();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
index 9d99efb..93ade25 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -161,6 +161,10 @@
<property name="bindHttpPortOffset">1</property>
<property name="route">node1</property>
<property name="remoteMode">${undertow.remote}</property>
+ <property name="keycloakConfigPropertyOverrides">{
+ "keycloak.connectionsInfinispan.nodeName": "node1"
+ }
+ </property>
</configuration>
</container>
<container qualifier="auth-server-undertow-backend2" mode="manual" >
@@ -172,6 +176,10 @@
<property name="bindHttpPortOffset">2</property>
<property name="route">node2</property>
<property name="remoteMode">${undertow.remote}</property>
+ <property name="keycloakConfigPropertyOverrides">{
+ "keycloak.connectionsInfinispan.nodeName": "node2"
+ }
+ </property>
</configuration>
</container>
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
index 9162726..c8ba747 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
@@ -141,7 +141,7 @@ public class UserSessionInitializerTest {
private UserSessionModel[] createSessions() {
UserSessionModel[] sessions = new UserSessionModel[3];
- sessions[0] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+ sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
Set<String> roles = new HashSet<String>();
roles.add("one");
@@ -154,10 +154,10 @@ public class UserSessionInitializerTest {
createClientSession(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state", roles, protocolMappers);
createClientSession(realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[1] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[2] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
+ sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
resetSession();
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java
index efa2f7d..2148991 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java
@@ -230,7 +230,7 @@ public class UserSessionPersisterProviderTest {
fooRealm.addClient("foo-app");
session.users().addUser(fooRealm, "user3");
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
createClientSession(fooRealm.getClientByClientId("foo-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
resetSession();
@@ -264,7 +264,7 @@ public class UserSessionPersisterProviderTest {
fooRealm.addClient("bar-app");
session.users().addUser(fooRealm, "user3");
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
createClientSession(fooRealm.getClientByClientId("foo-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
createClientSession(fooRealm.getClientByClientId("bar-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
@@ -371,7 +371,7 @@ public class UserSessionPersisterProviderTest {
private UserSessionModel[] createSessions() {
UserSessionModel[] sessions = new UserSessionModel[3];
- sessions[0] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+ sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
Set<String> roles = new HashSet<String>();
roles.add("one");
@@ -384,10 +384,10 @@ public class UserSessionPersisterProviderTest {
createClientSession(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state", roles, protocolMappers);
createClientSession(realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[1] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[2] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
+ sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
return sessions;
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
index d5085b0..26b535a 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
@@ -188,7 +188,7 @@ public class UserSessionProviderOfflineTest {
fooRealm.addClient("foo-app");
session.users().addUser(fooRealm, "user3");
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
AuthenticatedClientSessionModel clientSession = createClientSession(fooRealm.getClientByClientId("foo-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
resetSession();
@@ -237,7 +237,7 @@ public class UserSessionProviderOfflineTest {
fooRealm.addClient("bar-app");
session.users().addUser(fooRealm, "user3");
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
createClientSession(fooRealm.getClientByClientId("foo-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
createClientSession(fooRealm.getClientByClientId("bar-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
@@ -298,7 +298,7 @@ public class UserSessionProviderOfflineTest {
fooRealm.addClient("foo-app");
session.users().addUser(fooRealm, "user3");
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(fooRealm, session.users().getUserByUsername("user3", fooRealm), "user3", "127.0.0.1", "form", true, null, null);
AuthenticatedClientSessionModel clientSession = createClientSession(fooRealm.getClientByClientId("foo-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
resetSession();
@@ -425,7 +425,7 @@ public class UserSessionProviderOfflineTest {
private UserSessionModel[] createSessions() {
UserSessionModel[] sessions = new UserSessionModel[3];
- sessions[0] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+ sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
Set<String> roles = new HashSet<String>();
roles.add("one");
@@ -438,10 +438,10 @@ public class UserSessionProviderOfflineTest {
createClientSession(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state", roles, protocolMappers);
createClientSession(realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[1] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[2] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
+ sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
return sessions;
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
index 3e2a4dc..2d25a07 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
@@ -312,13 +312,13 @@ public class UserSessionProviderTest {
Set<String> expired = new HashSet<String>();
Time.setOffset(-(realm.getSsoSessionMaxLifespan() + 1));
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
expired.add(userSession.getId());
AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, client, userSession);
Assert.assertEquals(userSession, clientSession.getUserSession());
Time.setOffset(0);
- UserSessionModel s = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.1", "form", true, null, null);
+ UserSessionModel s = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.1", "form", true, null, null);
//s.setLastSessionRefresh(Time.currentTime() - (realm.getSsoSessionIdleTimeout() + 1));
s.setLastSessionRefresh(0);
expired.add(s.getId());
@@ -326,7 +326,7 @@ public class UserSessionProviderTest {
Set<String> valid = new HashSet<String>();
Set<String> validClientSessions = new HashSet<String>();
- userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+ userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
valid.add(userSession.getId());
validClientSessions.add(session.sessions().createClientSession(realm, client, userSession).getId());
@@ -382,7 +382,7 @@ public class UserSessionProviderTest {
try {
for (int i = 0; i < 25; i++) {
Time.setOffset(i);
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0." + i, "form", false, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0." + i, "form", false, null, null);
AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app"), userSession);
clientSession.setRedirectUri("http://redirect");
clientSession.setRoles(new HashSet<String>());
@@ -406,7 +406,7 @@ public class UserSessionProviderTest {
@Test
public void testCreateAndGetInSameTransaction() {
ClientModel client = realm.getClientByClientId("test-app");
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
AuthenticatedClientSessionModel clientSession = createClientSession(client, userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
UserSessionModel userSessionLoaded = session.sessions().getUserSession(realm, userSession.getId());
@@ -420,7 +420,7 @@ public class UserSessionProviderTest {
@Test
public void testAuthenticatedClientSessions() {
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
ClientModel client1 = realm.getClientByClientId("test-app");
ClientModel client2 = realm.getClientByClientId("third-party");
@@ -599,7 +599,7 @@ public class UserSessionProviderTest {
private UserSessionModel[] createSessions() {
UserSessionModel[] sessions = new UserSessionModel[3];
- sessions[0] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+ sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
Set<String> roles = new HashSet<String>();
roles.add("one");
@@ -612,10 +612,10 @@ public class UserSessionProviderTest {
createClientSession(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state", roles, protocolMappers);
createClientSession(realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[1] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
- sessions[2] = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
+ sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
createClientSession(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
resetSession();
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java
index 4790e9c..bd5cb1e 100644
--- a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java
@@ -338,7 +338,7 @@ public abstract class AbstractSessionCacheCommand extends AbstractCommand {
UserModel user = batchSession.users().getUserByUsername(username, realm);
for (int i=0 ; i<countInIteration ; i++) {
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, user, username, "127.0.0.1", "form", false, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, "127.0.0.1", "form", false, null, null);
session.sessions().createClientSession(userSession.getRealm(), client, userSession);
}
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/PersistSessionsCommand.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/PersistSessionsCommand.java
index c8b6771..1e4cb48 100644
--- a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/PersistSessionsCommand.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/PersistSessionsCommand.java
@@ -80,7 +80,7 @@ public class PersistSessionsCommand extends AbstractCommand {
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
for (int i = 0; i < countInThisBatch; i++) {
- UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, john, "john-doh@localhost", "127.0.0.2", "form", true, null, null);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, john, "john-doh@localhost", "127.0.0.2", "form", true, null, null);
AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, testApp, userSession);
clientSession.setRedirectUri("http://redirect");
clientSession.setNote("foo", "bar-" + i);