KEYCLOAK-5915 Support for sticky sessions managed by loadbalancer. Support for KeyAffinityService

This commit is contained in:
mposolda 2017-12-05 22:47:08 +01:00 committed by Marek Posolda
parent 35e60e0aa4
commit 8a0fa521c4
27 changed files with 415 additions and 61 deletions

View file

@ -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);
}

View file

@ -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);

View file

@ -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,10 +55,16 @@ 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() {

View file

@ -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

View file

@ -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);
@ -177,6 +181,12 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
return adapter;
}
@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();
@ -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());

View file

@ -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);

View file

@ -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;
}

View file

@ -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();
}
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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();
}

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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<>();

View file

@ -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();

View file

@ -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);
});
}
}

View file

@ -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();

View file

@ -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>

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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);
}

View file

@ -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);