KEYCLOAK-5915 Support for sticky sessions managed by loadbalancer. Support for KeyAffinityService
This commit is contained in:
parent
35e60e0aa4
commit
8a0fa521c4
27 changed files with 415 additions and 61 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue