Remove unused code from model/infinispan module

Closes #29137

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
Pedro Ruivo 2024-04-29 10:59:17 +01:00 committed by Alexander Schwartz
parent 7775e4ad18
commit 4c6f3ce35d
56 changed files with 115 additions and 1038 deletions

View file

@ -41,7 +41,6 @@ import org.infinispan.factories.impl.ComponentRef;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
import org.infinispan.persistence.remote.RemoteStore;
import org.infinispan.remoting.transport.Transport;
import org.infinispan.remoting.transport.jgroups.JGroupsTransport;
import org.infinispan.util.EmbeddedTimeService;
import org.jboss.logging.Logger;
@ -79,16 +78,6 @@ public class InfinispanUtil {
}
/**
*
* @param cache
* @return true if cluster coordinator OR if it's local cache
*/
public static boolean isCoordinator(Cache cache) {
Transport transport = cache.getCacheManager().getTransport();
return transport == null || transport.isCoordinator();
}
/**
* Convert the given value to the proper value, which can be used when calling operations for the infinispan remoteCache.
*

View file

@ -134,7 +134,7 @@ public abstract class CacheManager {
protected void bumpVersion(String id) {
long next = counter.next();
Object rev = revisions.put(id, next);
revisions.put(id, next);
}
public void addRevisioned(Revisioned object, long startupRevision) {

View file

@ -102,7 +102,7 @@ public class RealmCacheManager extends CacheManager {
addInvalidations(InGroupPredicate.create().group(groupId), invalidations);
}
public void clientAdded(String realmId, String clientUUID, String clientId, Set<String> invalidations) {
public void clientAdded(String realmId, Set<String> invalidations) {
invalidations.add(RealmCacheSession.getRealmClientsQueryCacheKey(realmId));
}

View file

@ -122,7 +122,6 @@ public class RealmCacheSession implements CacheRealmProvider {
protected Set<String> invalidations = new HashSet<>();
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
protected boolean clearAll;
protected final long startupRevision;
private final StoreManagers datastoreProvider;
@ -135,14 +134,6 @@ public class RealmCacheSession implements CacheRealmProvider {
session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
}
public long getStartupRevision() {
return startupRevision;
}
public boolean isInvalid(String id) {
return invalidations.contains(id);
}
@Override
public void clear() {
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
@ -355,9 +346,6 @@ public class RealmCacheSession implements CacheRealmProvider {
@Override
public void commit() {
try {
if (clearAll) {
cache.clear();
}
runInvalidations();
transactionActive = false;
} finally {
@ -551,7 +539,7 @@ public class RealmCacheSession implements CacheRealmProvider {
listInvalidations.add(realm.getId());
invalidationEvents.add(ClientAddedEvent.create(client.getId(), client.getClientId(), realm.getId()));
cache.clientAdded(realm.getId(), client.getId(), client.getClientId(), invalidations);
cache.clientAdded(realm.getId(), invalidations);
return client;
}

View file

@ -99,7 +99,7 @@ public class UserAdapter implements CachedUserModel {
@Override
public UserModel getDelegateForUpdate() {
if (updated == null) {
userProviderCache.registerUserInvalidation(realm, cached);
userProviderCache.registerUserInvalidation(cached);
updated = modelSupplier.get();
if (updated == null) throw new IllegalStateException("Not found in database");
}

View file

@ -34,8 +34,6 @@ public class UserCacheManager extends CacheManager {
private static final Logger logger = Logger.getLogger(UserCacheManager.class);
protected volatile boolean enabled = true;
public UserCacheManager(Cache<String, Revisioned> cache, Cache<String, Long> revisions) {
super(cache, revisions);
}

View file

@ -120,7 +120,7 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
return delegate;
}
public void registerUserInvalidation(RealmModel realm,CachedUser user) {
public void registerUserInvalidation(CachedUser user) {
cache.userUpdatedInvalidations(user.getId(), user.getUsername(), user.getEmail(), user.getRealm(), invalidations);
invalidationEvents.add(UserUpdatedEvent.create(user.getId(), user.getUsername(), user.getEmail(), user.getRealm()));
}
@ -326,7 +326,7 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
// although we do set a timeout, Infinispan has no guarantees when the user will be evicted
// its also hard to test stuff
if (model.shouldInvalidate(cached)) {
registerUserInvalidation(realm, cached);
registerUserInvalidation(cached);
return getDelegate().getUserById(realm, cached.getId());
}
}

View file

@ -99,7 +99,6 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
protected Set<String> invalidations = new HashSet<>();
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
protected boolean clearAll;
protected final long startupRevision;
protected StoreFactory delegate;
protected KeycloakSession session;
@ -250,16 +249,6 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
cache.sendInvalidationEvents(session, invalidationEvents, InfinispanCacheStoreFactoryProviderFactory.AUTHORIZATION_INVALIDATION_EVENTS);
}
public long getStartupRevision() {
return startupRevision;
}
public boolean isInvalid(String id) {
return invalidations.contains(id);
}
public void registerResourceServerInvalidation(String id) {
cache.resourceServerUpdated(id, invalidations);
ResourceServerAdapter adapter = managedResourceServers.get(id);

View file

@ -1,28 +0,0 @@
package org.keycloak.models.cache.infinispan.authorization.entities;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceServerListQuery extends AbstractRevisioned {
private final Set<String> servers;
public ResourceServerListQuery(Long revision, String id, String serverId) {
super(revision, id);
servers = new HashSet<>();
servers.add(serverId);
}
public ResourceServerListQuery(Long revision, String id, Set<String> servers) {
super(revision, id);
this.servers = servers;
}
public Set<String> getResourceServers() {
return servers;
}
}

View file

@ -17,21 +17,18 @@
package org.keycloak.models.cache.infinispan.entities;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@ -69,8 +66,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
protected boolean serviceAccountsEnabled;
protected int nodeReRegistrationTimeout;
protected Map<String, Integer> registeredNodes;
protected List<String> defaultClientScopesIds;
protected List<String> optionalClientScopesIds;
public CachedClient(Long revision, RealmModel realm, ClientModel model) {
super(revision, model.getId());
@ -107,15 +102,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
nodeReRegistrationTimeout = model.getNodeReRegistrationTimeout();
registeredNodes = new TreeMap<>(model.getRegisteredNodes());
defaultClientScopesIds = new LinkedList<>();
for (ClientScopeModel clientScope : model.getClientScopes(true).values()) {
defaultClientScopesIds.add(clientScope.getId());
}
optionalClientScopesIds = new LinkedList<>();
for (ClientScopeModel clientScope : model.getClientScopes(false).values()) {
optionalClientScopesIds.add(clientScope.getId());
}
}
public String getClientId() {
@ -242,14 +228,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
return registeredNodes;
}
public List<String> getDefaultClientScopesIds() {
return defaultClientScopesIds;
}
public List<String> getOptionalClientScopesIds() {
return optionalClientScopesIds;
}
public Map<String, String> getAuthFlowBindings() {
return authFlowBindings;
}

View file

@ -17,6 +17,16 @@
package org.keycloak.models.cache.infinispan.entities;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
@ -40,17 +50,6 @@ import org.keycloak.models.WebAuthnPolicy;
import org.keycloak.models.cache.infinispan.DefaultLazyLoader;
import org.keycloak.models.cache.infinispan.LazyLoader;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@ -151,7 +150,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
protected Set<String> eventsListeners;
protected Set<String> enabledEventTypes;
protected boolean adminEventsEnabled;
protected Set<String> adminEnabledEventOperations = new HashSet<>();
protected boolean adminEventsDetailsEnabled;
protected String defaultRoleId;
private boolean allowUserManagedAccess;
@ -597,10 +595,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
return adminEventsEnabled;
}
public Set<String> getAdminEnabledEventOperations() {
return adminEnabledEventOperations;
}
public boolean isAdminEventsDetailsEnabled() {
return adminEventsDetailsEnabled;
}

View file

@ -15,7 +15,7 @@ import java.util.stream.Collectors;
public class GroupListQuery extends AbstractRevisioned implements GroupQuery {
private final String realm;
private final String realmName;
private Map<String, Set<String>> searchKeys;
private final Map<String, Set<String>> searchKeys;
public GroupListQuery(Long revisioned, String id, RealmModel realm, String searchKey, Set<String> result) {
super(revisioned, id);
@ -62,13 +62,6 @@ public class GroupListQuery extends AbstractRevisioned implements GroupQuery {
return realm;
}
public Map<String, Set<String>> getSearchKeys() {
if (searchKeys == null) {
searchKeys = new HashMap<>();
}
return searchKeys;
}
@Override
public String toString() {
return "GroupListQuery{" +

View file

@ -58,7 +58,7 @@ public class ClientAddedEvent extends InvalidationEvent implements RealmCacheInv
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientAdded(realmId, clientUuid, clientId, invalidations);
realmCache.clientAdded(realmId, invalidations);
}
@Override

View file

@ -1,66 +0,0 @@
/*
* Copyright 2016 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;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class Consumers {
private Consumers() {
}
public static UserSessionModelsConsumer userSessionModels(InfinispanUserSessionProvider provider, RealmModel realm, boolean offline) {
return new UserSessionModelsConsumer(provider, realm, offline);
}
public static class UserSessionModelsConsumer implements Consumer<Map.Entry<String, SessionEntity>> {
private InfinispanUserSessionProvider provider;
private RealmModel realm;
private boolean offline;
private List<UserSessionModel> sessions = new LinkedList<>();
private UserSessionModelsConsumer(InfinispanUserSessionProvider provider, RealmModel realm, boolean offline) {
this.provider = provider;
this.realm = realm;
this.offline = offline;
}
@Override
public void accept(Map.Entry<String, SessionEntity> entry) {
SessionEntity e = entry.getValue();
sessions.add(provider.wrap(realm, (UserSessionEntity) e, offline));
}
public List<UserSessionModel> getSessions() {
return sessions;
}
}
}

View file

@ -46,8 +46,6 @@ import org.keycloak.sessions.RootAuthenticationSessionModel;
*/
public class InfinispanAuthenticationSessionProvider implements AuthenticationSessionProvider {
private static final Logger log = Logger.getLogger(InfinispanAuthenticationSessionProvider.class);
private final KeycloakSession session;
private final Cache<String, RootAuthenticationSessionEntity> cache;
private final InfinispanKeyGenerator keyGenerator;
@ -142,10 +140,6 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
// ClusterProvider.DCNotify.ALL_DCS);
}
protected void onClientRemovedEvent(String realmId, String clientUuid) {
}
@Override
public void updateNonlocalSessionAuthNotes(AuthenticationSessionCompoundId compoundId, Map<String, String> authNotesFragment) {

View file

@ -28,7 +28,6 @@ import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNote
import org.keycloak.models.sessions.infinispan.entities.AuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
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.KeycloakModelUtils;
@ -69,8 +68,6 @@ public class InfinispanAuthenticationSessionProviderFactory implements Authentic
public static final String REALM_REMOVED_AUTHSESSION_EVENT = "REALM_REMOVED_EVENT_AUTHSESSIONS";
public static final String CLIENT_REMOVED_AUTHSESSION_EVENT = "CLIENT_REMOVED_SESSION_AUTHSESSIONS";
@Override
public void init(Config.Scope config) {
// get auth sessions limit from config or use default if not provided
@ -117,20 +114,12 @@ public class InfinispanAuthenticationSessionProviderFactory implements Authentic
cluster.registerListener(REALM_REMOVED_AUTHSESSION_EVENT, new AbstractAuthSessionClusterListener<RealmRemovedSessionEvent>(sessionFactory) {
@Override
protected void eventReceived(KeycloakSession session, InfinispanAuthenticationSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
protected void eventReceived(InfinispanAuthenticationSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
provider.onRealmRemovedEvent(sessionEvent.getRealmId());
}
});
cluster.registerListener(CLIENT_REMOVED_AUTHSESSION_EVENT, new AbstractAuthSessionClusterListener<ClientRemovedSessionEvent>(sessionFactory) {
@Override
protected void eventReceived(KeycloakSession session, InfinispanAuthenticationSessionProvider provider, ClientRemovedSessionEvent sessionEvent) {
provider.onClientRemovedEvent(sessionEvent.getRealmId(), sessionEvent.getClientUuid());
}
});
log.debug("Registered cluster listeners");
}

View file

@ -18,8 +18,6 @@ package org.keycloak.models.sessions.infinispan;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.commons.api.BasicCache;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.cluster.ClusterProvider;
import org.infinispan.context.Flag;
import org.keycloak.models.KeycloakTransaction;
@ -52,7 +50,7 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
};
public enum CacheOperation {
ADD, ADD_WITH_LIFESPAN, REMOVE, REPLACE, ADD_IF_ABSENT // ADD_IF_ABSENT throws an exception if there is existing value
ADD_WITH_LIFESPAN, REMOVE, REPLACE
}
private boolean active;
@ -93,32 +91,6 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
return active;
}
public <K, V> void put(Cache<K, V> cache, K key, V value) {
log.tracev("Adding cache operation: {0} on {1}", CacheOperation.ADD, key);
Object taskKey = getTaskKey(cache, key);
if (tasks.containsKey(taskKey)) {
throw new IllegalStateException("Can't add session: task in progress for session");
} else {
tasks.put(taskKey, new CacheTaskWithValue<V>(value) {
@Override
public void execute() {
decorateCache(cache).put(key, value);
}
@Override
public String toString() {
return String.format("CacheTaskWithValue: Operation 'put' for key %s", key);
}
@Override
public Operation getOperation() {
return Operation.PUT;
}
});
}
}
public <K, V> void put(BasicCache<K, V> cache, K key, V value, long lifespan, TimeUnit lifespanUnit) {
log.tracev("Adding cache operation: {0} on {1}", CacheOperation.ADD_WITH_LIFESPAN, key);
@ -145,35 +117,6 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
}
}
public <K, V> void putIfAbsent(Cache<K, V> cache, K key, V value) {
log.tracev("Adding cache operation: {0} on {1}", CacheOperation.ADD_IF_ABSENT, key);
Object taskKey = getTaskKey(cache, key);
if (tasks.containsKey(taskKey)) {
throw new IllegalStateException("Can't add session: task in progress for session");
} else {
tasks.put(taskKey, new CacheTaskWithValue<V>(value) {
@Override
public void execute() {
V existing = cache.putIfAbsent(key, value);
if (existing != null) {
throw new IllegalStateException("There is already existing value in cache for key " + key);
}
}
@Override
public String toString() {
return String.format("CacheTaskWithValue: Operation 'putIfAbsent' for key %s", key);
}
@Override
public Operation getOperation() {
return Operation.PUT;
}
});
}
}
public <K, V> void replace(Cache<K, V> cache, K key, V value, long lifespan, TimeUnit lifespanUnit) {
log.tracev("Adding cache operation: {0} on {1}. Lifespan {2} {3}.", CacheOperation.REPLACE, key, lifespan, lifespanUnit);
@ -200,18 +143,6 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
}
}
public <K, V> void notify(ClusterProvider clusterProvider, String taskKey, ClusterEvent event, boolean ignoreSender) {
log.tracev("Adding cache operation SEND_EVENT: {0}", event);
String theTaskKey = taskKey;
int i = 1;
while (tasks.containsKey(theTaskKey)) {
theTaskKey = taskKey + "-" + (i++);
}
tasks.put(taskKey, () -> clusterProvider.notify(taskKey, event, ignoreSender, ClusterProvider.DCNotify.ALL_DCS));
}
public <K, V> void remove(BasicCache<K, V> cache, K key) {
log.tracev("Adding cache operation: {0} on {1}", CacheOperation.REMOVE, key);
@ -278,10 +209,6 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
protected long lifespan;
protected TimeUnit lifespanUnit;
public CacheTaskWithValue(V value) {
this(value, -1, TimeUnit.SECONDS);
}
public CacheTaskWithValue(V value, long lifespan, TimeUnit lifespanUnit) {
this.value = value;
this.lifespan = lifespan;

View file

@ -25,10 +25,10 @@ import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.SingleUseObjectProvider;
import org.keycloak.models.sessions.infinispan.entities.SingleUseObjectValueEntity;
import org.keycloak.connections.infinispan.InfinispanUtil;
/**
* TODO: Check if Boolean can be used as single-use cache argument instead of SingleUseObjectValueEntity. With respect to other single-use cache usecases like "Revoke Refresh Token" .
@ -42,14 +42,11 @@ public class InfinispanSingleUseObjectProvider implements SingleUseObjectProvide
public static final Logger logger = Logger.getLogger(InfinispanSingleUseObjectProvider.class);
private final Supplier<BasicCache<String, SingleUseObjectValueEntity>> singleUseObjectCache;
private final KeycloakSession session;
private final InfinispanKeycloakTransaction tx;
public InfinispanSingleUseObjectProvider(KeycloakSession session, Supplier<BasicCache<String, SingleUseObjectValueEntity>> singleUseObjectCache) {
this.session = session;
this.singleUseObjectCache = singleUseObjectCache;
this.tx = new InfinispanKeycloakTransaction();
session.getTransactionManager().enlistAfterCompletion(tx);
}

View file

@ -112,7 +112,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
new AbstractUserSessionClusterListener<RealmRemovedSessionEvent, UserLoginFailureProvider>(sessionFactory, UserLoginFailureProvider.class) {
@Override
protected void eventReceived(KeycloakSession session, UserLoginFailureProvider provider, RealmRemovedSessionEvent sessionEvent) {
protected void eventReceived(UserLoginFailureProvider provider, RealmRemovedSessionEvent sessionEvent) {
if (provider instanceof InfinispanUserLoginFailureProvider) {
((InfinispanUserLoginFailureProvider) provider).removeAllLocalUserLoginFailuresEvent(sessionEvent.getRealmId());
}
@ -123,7 +123,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
new AbstractUserSessionClusterListener<RemoveAllUserLoginFailuresEvent, UserLoginFailureProvider>(sessionFactory, UserLoginFailureProvider.class) {
@Override
protected void eventReceived(KeycloakSession session, UserLoginFailureProvider provider, RemoveAllUserLoginFailuresEvent sessionEvent) {
protected void eventReceived(UserLoginFailureProvider provider, RemoveAllUserLoginFailuresEvent sessionEvent) {
if (provider instanceof InfinispanUserLoginFailureProvider) {
((InfinispanUserLoginFailureProvider) provider).removeAllLocalUserLoginFailuresEvent(sessionEvent.getRealmId());
}
@ -200,7 +200,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
initializer.initCache();

View file

@ -113,7 +113,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
protected final PersisterLastSessionRefreshStore persisterLastSessionRefreshStore;
protected final RemoteCacheInvoker remoteCacheInvoker;
protected final InfinispanKeyGenerator keyGenerator;
protected final SessionFunction offlineSessionCacheEntryLifespanAdjuster;
@ -153,7 +152,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
this.lastSessionRefreshStore = lastSessionRefreshStore;
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
this.persisterLastSessionRefreshStore = persisterLastSessionRefreshStore;
this.remoteCacheInvoker = remoteCacheInvoker;
this.keyGenerator = keyGenerator;
this.offlineSessionCacheEntryLifespanAdjuster = offlineSessionCacheEntryLifespanAdjuster;
this.offlineClientSessionCacheEntryLifespanAdjuster = offlineClientSessionCacheEntryLifespanAdjuster;
@ -717,10 +715,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
}
}
protected void onClientRemovedEvent(String realmId, String clientUuid) {
// Nothing for now. userSession.getAuthenticatedClientSessions() will check lazily if particular client exists and update userSession on-the-fly.
}
protected void onUserRemoved(RealmModel realm, UserModel user) {
removeUserSessions(realm, user, true);
@ -789,7 +783,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
}
AuthenticatedClientSessionAdapter wrap(UserSessionModel userSession, ClientModel client, AuthenticatedClientSessionEntity entity, boolean offline) {
InfinispanChangelogBasedTransaction<String, UserSessionEntity> userSessionUpdateTx = getTransaction(offline);
InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx = getClientSessionTransaction(offline);
return entity != null ? new AuthenticatedClientSessionAdapter(session, this, entity, client, userSession, clientSessionUpdateTx, offline) : null;
}
@ -1151,7 +1144,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
}
@Override
public CacheOperation getOperation(UserSessionEntity session) {
public CacheOperation getOperation() {
return CacheOperation.REPLACE;
}

View file

@ -48,7 +48,6 @@ import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessi
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.AbstractUserSessionClusterListener;
import org.keycloak.models.sessions.infinispan.events.ClientRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer;
@ -85,8 +84,6 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
public static final String REALM_REMOVED_SESSION_EVENT = "REALM_REMOVED_EVENT_SESSIONS";
public static final String CLIENT_REMOVED_SESSION_EVENT = "CLIENT_REMOVED_SESSION_SESSIONS";
public static final String REMOVE_USER_SESSIONS_EVENT = "REMOVE_USER_SESSIONS_EVENT";
public static final String CONFIG_OFFLINE_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE = "offlineSessionCacheEntryLifespanOverride";
public static final String CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE = "offlineClientSessionCacheEntryLifespanOverride";
@ -255,7 +252,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
new AbstractUserSessionClusterListener<RealmRemovedSessionEvent, UserSessionProvider>(sessionFactory, UserSessionProvider.class) {
@Override
protected void eventReceived(KeycloakSession session, UserSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
protected void eventReceived(UserSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
if (provider instanceof InfinispanUserSessionProvider) {
((InfinispanUserSessionProvider) provider).onRealmRemovedEvent(sessionEvent.getRealmId());
} else if (provider instanceof PersistentUserSessionProvider) {
@ -265,25 +262,11 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
});
cluster.registerListener(CLIENT_REMOVED_SESSION_EVENT,
new AbstractUserSessionClusterListener<ClientRemovedSessionEvent, UserSessionProvider>(sessionFactory, UserSessionProvider.class) {
@Override
protected void eventReceived(KeycloakSession session, UserSessionProvider provider, ClientRemovedSessionEvent sessionEvent) {
if (provider instanceof InfinispanUserSessionProvider) {
((InfinispanUserSessionProvider) provider).onClientRemovedEvent(sessionEvent.getRealmId(), sessionEvent.getClientUuid());
} else if (provider instanceof PersistentUserSessionProvider) {
((PersistentUserSessionProvider) provider).onClientRemovedEvent(sessionEvent.getRealmId(), sessionEvent.getClientUuid());
}
}
});
cluster.registerListener(REMOVE_USER_SESSIONS_EVENT,
new AbstractUserSessionClusterListener<RemoveUserSessionsEvent, UserSessionProvider>(sessionFactory, UserSessionProvider.class) {
@Override
protected void eventReceived(KeycloakSession session, UserSessionProvider provider, RemoveUserSessionsEvent sessionEvent) {
protected void eventReceived(UserSessionProvider provider, RemoveUserSessionsEvent sessionEvent) {
if (provider instanceof InfinispanUserSessionProvider) {
((InfinispanUserSessionProvider) provider).onRemoveUserSessionsEvent(sessionEvent.getRealmId());
} else if (provider instanceof PersistentUserSessionProvider) {
@ -414,7 +397,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors,
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
initializer.initCache();

View file

@ -108,7 +108,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
protected final CrossDCLastSessionRefreshStore lastSessionRefreshStore;
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
protected final RemoteCacheInvoker remoteCacheInvoker;
protected final InfinispanKeyGenerator keyGenerator;
public PersistentUserSessionProvider(KeycloakSession session,
@ -151,7 +150,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
this.lastSessionRefreshStore = lastSessionRefreshStore;
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
this.remoteCacheInvoker = remoteCacheInvoker;
this.keyGenerator = keyGenerator;
session.getTransactionManager().enlistAfterCompletion(clusterEventsSenderTx);
@ -276,10 +274,10 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
return entityWrapper != null ? entityWrapper.getEntity() : null;
}
private Stream<UserSessionModel> getUserSessionsFromPersistenceProviderStream(RealmModel realm, UserModel user, boolean offline) {
private Stream<UserSessionModel> getUserSessionsFromPersistenceProviderStream(RealmModel realm, UserModel user) {
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
return persister.loadUserSessionsStream(realm, user, offline, 0, null)
.map(persistentUserSession -> (UserSessionModel) getUserSession(realm, persistentUserSession.getId(), offline))
return persister.loadUserSessionsStream(realm, user, true, 0, null)
.map(persistentUserSession -> (UserSessionModel) getUserSession(realm, persistentUserSession.getId(), true))
.filter(Objects::nonNull);
}
@ -336,9 +334,9 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
if (predicate.getBrokerSessionId() != null && !offline) {
// we haven't yet migrated the old offline entries, so they don't have a brokerSessionId yet
return Stream.of(persister.loadUserSessionsStreamByBrokerSessionId(realm, predicate.getBrokerSessionId(), offline))
return Stream.of(persister.loadUserSessionsStreamByBrokerSessionId(realm, predicate.getBrokerSessionId(), false))
.filter(predicate.toModelPredicate())
.map(s -> (UserSessionModel) getUserSession(realm, s.getId(), offline))
.map(s -> (UserSessionModel) getUserSession(realm, s.getId(), false))
.filter(Objects::nonNull);
}
@ -590,11 +588,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
}
}
protected void onClientRemovedEvent(String realmId, String clientUuid) {
// Nothing for now. userSession.getAuthenticatedClientSessions() will check lazily if particular client exists and update userSession on-the-fly.
}
protected void onUserRemoved(RealmModel realm, UserModel user) {
removeUserSessions(realm, user, true);
removeUserSessions(realm, user, false);
@ -630,7 +623,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
}
UserSessionAdapter wrap(RealmModel realm, UserSessionEntity entity, boolean offline) {
UserModel user = null;
UserModel user;
if (Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && entity.getNotes().containsKey(SESSION_NOTE_LIGHTWEIGHT_USER)) {
LightweightUserAdapter lua = LightweightUserAdapter.fromString(session, realm, entity.getNotes().get(SESSION_NOTE_LIGHTWEIGHT_USER));
final UserSessionAdapter us = wrap(realm, entity, offline, lua);
@ -704,7 +697,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
UserSessionAdapter userSessionAdapter = (offlineUserSession instanceof UserSessionAdapter) ? (UserSessionAdapter) offlineUserSession :
getOfflineUserSession(offlineUserSession.getRealm(), offlineUserSession.getId());
AuthenticatedClientSessionAdapter offlineClientSession = importClientSession(userSessionAdapter, clientSession, true, false);
AuthenticatedClientSessionAdapter offlineClientSession = importOfflineClientSession(userSessionAdapter, clientSession);
// update timestamp to current time
offlineClientSession.setTimestamp(Time.currentTime());
@ -716,7 +709,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
@Override
public Stream<UserSessionModel> getOfflineUserSessionsStream(RealmModel realm, UserModel user) {
return getUserSessionsFromPersistenceProviderStream(realm, user, true);
return getUserSessionsFromPersistenceProviderStream(realm, user);
}
@Override
@ -862,11 +855,10 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
entity.setAuthenticatedClientSessions(new AuthenticatedClientSessionStore());
entity.setRememberMe(userSession.isRememberMe());
entity.setState(userSession.getState());
if (userSession instanceof OfflineUserSessionModel) {
if (userSession instanceof OfflineUserSessionModel offlineUserSession) {
// this is a hack so that UserModel doesn't have to be available when offline token is imported.
// see related JIRA - KEYCLOAK-5350 and corresponding test
OfflineUserSessionModel oline = (OfflineUserSessionModel) userSession;
entity.setUser(oline.getUserId());
entity.setUser(offlineUserSession.getUserId());
// NOTE: Hack
// We skip calling entity.setLoginUsername(userSession.getLoginUsername())
@ -883,28 +875,15 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
}
private AuthenticatedClientSessionAdapter importClientSession(UserSessionAdapter sessionToImportInto,
AuthenticatedClientSessionModel clientSession,
boolean offline,
boolean checkExpiration) {
private AuthenticatedClientSessionAdapter importOfflineClientSession(UserSessionAdapter sessionToImportInto,
AuthenticatedClientSessionModel clientSession) {
AuthenticatedClientSessionEntity entity = createAuthenticatedClientSessionInstance(sessionToImportInto.getId(), clientSession,
sessionToImportInto.getRealm().getId(), clientSession.getClient().getId(), offline);
sessionToImportInto.getRealm().getId(), clientSession.getClient().getId(), true);
entity.setUserSessionId(sessionToImportInto.getId());
// Update timestamp to same value as userSession. LastSessionRefresh of userSession from DB will have correct value
entity.setTimestamp(sessionToImportInto.getLastSessionRefresh());
if (checkExpiration) {
SessionFunction<AuthenticatedClientSessionEntity> lifespanChecker = offline
? SessionTimeouts::getOfflineClientSessionLifespanMs : SessionTimeouts::getClientSessionLifespanMs;
SessionFunction<AuthenticatedClientSessionEntity> idleTimeoutChecker = offline
? SessionTimeouts::getOfflineClientSessionMaxIdleMs : SessionTimeouts::getClientSessionMaxIdleMs;
if (idleTimeoutChecker.apply(sessionToImportInto.getRealm(), clientSession.getClient(), entity) == SessionTimeouts.ENTRY_EXPIRED_FLAG
|| lifespanChecker.apply(sessionToImportInto.getRealm(), clientSession.getClient(), entity) == SessionTimeouts.ENTRY_EXPIRED_FLAG) {
return null;
}
}
final UUID clientSessionId = entity.getId();
SessionUpdateTask<AuthenticatedClientSessionEntity> createClientSessionTask = Tasks.addIfAbsentSync();
@ -913,10 +892,10 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
AuthenticatedClientSessionStore clientSessions = sessionToImportInto.getEntity().getAuthenticatedClientSessions();
clientSessions.put(clientSession.getClient().getId(), clientSessionId);
SessionUpdateTask<UserSessionEntity> registerClientSessionTask = new ClientSessionPersistentChangelogBasedTransaction.RegisterClientSessionTask(clientSession.getClient().getId(), clientSessionId, offline);
SessionUpdateTask<UserSessionEntity> registerClientSessionTask = new ClientSessionPersistentChangelogBasedTransaction.RegisterClientSessionTask(clientSession.getClient().getId(), clientSessionId, true);
sessionTx.addTask(sessionToImportInto.getId(), registerClientSessionTask);
return new AuthenticatedClientSessionAdapter(session, this, entity, clientSession.getClient(), sessionToImportInto, clientSessionTx, offline);
return new AuthenticatedClientSessionAdapter(session, this, entity, clientSession.getClient(), sessionToImportInto, clientSessionTx, true);
}

View file

@ -1,41 +0,0 @@
/*
* Copyright 2016 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;
import java.io.Serializable;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UserSessionTimestamp implements Serializable {
private String userSessionId;
private int clientSessionTimestamp;
public UserSessionTimestamp(String userSessionId, int clientSessionTimestamp) {
this.userSessionId = userSessionId;
this.clientSessionTimestamp = clientSessionTimestamp;
}
public String getUserSessionId() {
return userSessionId;
}
public int getClientSessionTimestamp() {
return clientSessionTimestamp;
}
}

View file

@ -90,12 +90,11 @@ public class ClientSessionPersistentChangelogBasedTransaction extends Persistent
return wrappedEntity;
} else {
AuthenticatedClientSessionEntity entity = myUpdates.getEntityWrapper().getEntity();
// If entity is scheduled for remove, we don't return it.
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
return task.getOperation() == SessionUpdateTask.CacheOperation.REMOVE;
}).findFirst().isPresent();
@ -192,7 +191,7 @@ public class ClientSessionPersistentChangelogBasedTransaction extends Persistent
}
@Override
public CacheOperation getOperation(UserSessionEntity session) {
public CacheOperation getOperation() {
return CacheOperation.REPLACE;
}

View file

@ -25,7 +25,7 @@ import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessi
public abstract class ClientSessionUpdateTask implements PersistentSessionUpdateTask<AuthenticatedClientSessionEntity> {
@Override
public CacheOperation getOperation(AuthenticatedClientSessionEntity session) {
public CacheOperation getOperation() {
return CacheOperation.REPLACE;
}

View file

@ -40,8 +40,7 @@ public class EmbeddedCachesChangesPerformer<K, V extends SessionEntity> implemen
}
private void runOperationInCluster(K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
V session = sessionWrapper.getEntity();
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
SessionUpdateTask.CacheOperation operation = task.getOperation();
// Don't need to run update of underlying entity. Local updates were already run
//task.runUpdate(session);

View file

@ -149,12 +149,10 @@ public class InfinispanChangelogBasedTransaction<K, V extends SessionEntity> ext
return wrappedEntity;
} else {
V entity = myUpdates.getEntityWrapper().getEntity();
// If entity is scheduled for remove, we don't return it.
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
return task.getOperation() == SessionUpdateTask.CacheOperation.REMOVE;
}).findFirst().isPresent();
@ -190,8 +188,7 @@ public class InfinispanChangelogBasedTransaction<K, V extends SessionEntity> ext
private void runOperationInCluster(K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
V session = sessionWrapper.getEntity();
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
SessionUpdateTask.CacheOperation operation = task.getOperation();
// Don't need to run update of underlying entity. Local updates were already run
//task.runUpdate(session);

View file

@ -122,10 +122,10 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
RealmModel realm = sessionUpdates.getRealm();
UserSessionPersisterProvider userSessionPersister = innerSession.getProvider(UserSessionPersisterProvider.class);
if (merged.getOperation(sessionWrapper.getEntity()) == SessionUpdateTask.CacheOperation.REMOVE) {
if (merged.getOperation() == SessionUpdateTask.CacheOperation.REMOVE) {
AuthenticatedClientSessionEntity entity = (AuthenticatedClientSessionEntity) sessionWrapper.getEntity();
userSessionPersister.removeClientSession(entity.getUserSessionId(), entity.getClientId(), entity.isOffline());
} else if (merged.getOperation(sessionWrapper.getEntity()) == SessionUpdateTask.CacheOperation.ADD || merged.getOperation(sessionWrapper.getEntity()) == SessionUpdateTask.CacheOperation.ADD_IF_ABSENT){
} else if (merged.getOperation() == SessionUpdateTask.CacheOperation.ADD || merged.getOperation() == SessionUpdateTask.CacheOperation.ADD_IF_ABSENT){
AuthenticatedClientSessionEntity entity = (AuthenticatedClientSessionEntity) sessionWrapper.getEntity();
userSessionPersister.createClientSession(new AuthenticatedClientSessionModel() {
@Override
@ -405,7 +405,7 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
};
sessionUpdates.getUpdateTasks().forEach(vSessionUpdateTask -> {
vSessionUpdateTask.runUpdate((V) authenticatedClientSessionEntity);
if (vSessionUpdateTask.getOperation((V) authenticatedClientSessionEntity) == SessionUpdateTask.CacheOperation.REMOVE) {
if (vSessionUpdateTask.getOperation() == SessionUpdateTask.CacheOperation.REMOVE) {
userSessionPersister.removeClientSession(entity.getUserSessionId(), entity.getClientId(), entity.isOffline());
}
});
@ -422,9 +422,9 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
UserSessionPersisterProvider userSessionPersister = innerSession.getProvider(UserSessionPersisterProvider.class);
UserSessionEntity entity = (UserSessionEntity) sessionWrapper.getEntity();
if (merged.getOperation((V) entity) == SessionUpdateTask.CacheOperation.REMOVE) {
if (merged.getOperation() == SessionUpdateTask.CacheOperation.REMOVE) {
userSessionPersister.removeUserSession(entry.getKey().toString(), entity.isOffline());
} else if (merged.getOperation(sessionWrapper.getEntity()) == SessionUpdateTask.CacheOperation.ADD || merged.getOperation(sessionWrapper.getEntity()) == SessionUpdateTask.CacheOperation.ADD_IF_ABSENT){
} else if (merged.getOperation() == SessionUpdateTask.CacheOperation.ADD || merged.getOperation() == SessionUpdateTask.CacheOperation.ADD_IF_ABSENT){
userSessionPersister.createUserSession(new UserSessionModel() {
@Override
public String getId() {
@ -729,7 +729,7 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
};
sessionUpdates.getUpdateTasks().forEach(vSessionUpdateTask -> {
vSessionUpdateTask.runUpdate((V) userSessionEntity);
if (vSessionUpdateTask.getOperation((V)userSessionEntity) == SessionUpdateTask.CacheOperation.REMOVE) {
if (vSessionUpdateTask.getOperation() == SessionUpdateTask.CacheOperation.REMOVE) {
userSessionPersister.removeUserSession(entry.getKey().toString(), entity.isOffline());
}
});

View file

@ -25,7 +25,7 @@ import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
public abstract class LoginFailuresUpdateTask implements SessionUpdateTask<LoginFailureEntity> {
@Override
public CacheOperation getOperation(LoginFailureEntity session) {
public CacheOperation getOperation() {
return CacheOperation.REPLACE;
}

View file

@ -52,7 +52,7 @@ public class MergedUpdate<S extends SessionEntity> implements SessionUpdateTask<
}
@Override
public CacheOperation getOperation(S session) {
public CacheOperation getOperation() {
return operation;
}
@ -79,7 +79,7 @@ public class MergedUpdate<S extends SessionEntity> implements SessionUpdateTask<
S session = sessionWrapper.getEntity();
for (SessionUpdateTask<S> child : childUpdates) {
if (result == null) {
CacheOperation operation = child.getOperation(session);
CacheOperation operation = child.getOperation();
if (lifespanMs == SessionTimeouts.ENTRY_EXPIRED_FLAG || maxIdleTimeMs == SessionTimeouts.ENTRY_EXPIRED_FLAG) {
operation = CacheOperation.REMOVE;
@ -91,9 +91,9 @@ public class MergedUpdate<S extends SessionEntity> implements SessionUpdateTask<
} else {
// Merge the operations. REMOVE is special case as other operations are not needed then.
CacheOperation mergedOp = result.getOperation(session).merge(child.getOperation(session), session);
CacheOperation mergedOp = result.getOperation().merge(child.getOperation(), session);
if (mergedOp == CacheOperation.REMOVE) {
result = new MergedUpdate<>(child.getOperation(session), child.getCrossDCMessageStatus(sessionWrapper), lifespanMs, maxIdleTimeMs);
result = new MergedUpdate<>(child.getOperation(), child.getCrossDCMessageStatus(sessionWrapper), lifespanMs, maxIdleTimeMs);
result.childUpdates.add(child);
return result;
}

View file

@ -164,11 +164,9 @@ abstract public class PersistentSessionsChangelogBasedTransaction<K, V extends S
V entity = myUpdates.getEntityWrapper().getEntity();
// If entity is scheduled for remove, we don't return it.
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
}).findFirst().isPresent();
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream()
.map(SessionUpdateTask::getOperation)
.anyMatch(SessionUpdateTask.CacheOperation.REMOVE::equals);
return scheduledForRemove ? null : myUpdates.getEntityWrapper();
}

View file

@ -43,7 +43,7 @@ public class SessionEntityWrapper<S extends SessionEntity> {
private static final Logger log = Logger.getLogger(SessionEntityWrapper.class);
private UUID version;
private final UUID version;
private final S entity;
private final Map<String, String> localMetadata;
@ -91,10 +91,6 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return version;
}
public void setVersion(UUID version) {
this.version = version;
}
public S getEntity() {
return entity;
}
@ -116,13 +112,6 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return localMetadata.get(key);
}
public void putLocalMetadataNote(String key, String value) {
if (isForTransport()) {
throw new IllegalStateException("This entity is only intended for transport");
}
localMetadata.put(key, value);
}
public Integer getLocalMetadataNoteInt(String key) {
String note = getLocalMetadataNote(key);
return note==null ? null : Integer.valueOf(note);

View file

@ -26,7 +26,7 @@ public interface SessionUpdateTask<S extends SessionEntity> {
void runUpdate(S entity);
CacheOperation getOperation(S entity);
CacheOperation getOperation();
CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper<S> sessionWrapper);

View file

@ -32,7 +32,7 @@ public class Tasks {
}
@Override
public CacheOperation getOperation(SessionEntity entity) {
public CacheOperation getOperation() {
return CacheOperation.ADD_IF_ABSENT;
}
@ -48,7 +48,7 @@ public class Tasks {
}
@Override
public CacheOperation getOperation(SessionEntity entity) {
public CacheOperation getOperation() {
return CacheOperation.REMOVE;
}
@ -63,13 +63,13 @@ public class Tasks {
}
};
private static final SessionUpdateTask<? extends SessionEntity> OFFLINE_REMOVE_SYNC = new PersistentSessionUpdateTask<SessionEntity>() {
private static final SessionUpdateTask<? extends SessionEntity> OFFLINE_REMOVE_SYNC = new PersistentSessionUpdateTask<>() {
@Override
public void runUpdate(SessionEntity entity) {
}
@Override
public CacheOperation getOperation(SessionEntity entity) {
public CacheOperation getOperation() {
return CacheOperation.REMOVE;
}

View file

@ -81,14 +81,10 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe
return wrappedEntity;
} else {
UserSessionEntity entity = myUpdates.getEntityWrapper().getEntity();
// If entity is scheduled for remove, we don't return it.
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
}).findFirst().isPresent();
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream()
.map(SessionUpdateTask::getOperation)
.anyMatch(SessionUpdateTask.CacheOperation.REMOVE::equals);
return scheduledForRemove ? null : myUpdates.getEntityWrapper();
}
@ -133,15 +129,11 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe
if (myUpdates == null) {
return false;
}
V entity = myUpdates.getEntityWrapper().getEntity();
// If entity is scheduled for remove, we don't return it.
boolean scheduledForRemove = myUpdates.getUpdateTasks()
.stream()
.anyMatch(task -> task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE);
return scheduledForRemove;
return myUpdates.getUpdateTasks()
.stream()
.anyMatch(task -> task.getOperation() == SessionUpdateTask.CacheOperation.REMOVE);
}
}

View file

@ -25,7 +25,7 @@ import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
public abstract class UserSessionUpdateTask implements PersistentSessionUpdateTask<UserSessionEntity> {
@Override
public CacheOperation getOperation(UserSessionEntity session) {
public CacheOperation getOperation() {
return CacheOperation.REPLACE;
}

View file

@ -55,10 +55,10 @@ public abstract class AbstractAuthSessionClusterListener <SE extends SessionClus
log.debugf("Received authentication session event '%s'", sessionEvent.toString());
eventReceived(session, provider, sessionEvent);
eventReceived(provider, sessionEvent);
});
}
protected abstract void eventReceived(KeycloakSession session, InfinispanAuthenticationSessionProvider provider, SE sessionEvent);
protected abstract void eventReceived(InfinispanAuthenticationSessionProvider provider, SE sessionEvent);
}

View file

@ -57,7 +57,7 @@ public abstract class AbstractUserSessionClusterListener<SE extends SessionClust
log.debugf("Received user session event '%s'. Should resend event: %b", sessionEvent.toString(), shouldResendEvent);
}
eventReceived(session, provider, sessionEvent);
eventReceived(provider, sessionEvent);
if (shouldResendEvent) {
session.getProvider(ClusterProvider.class).notify(sessionEvent.getEventKey(), event, true, ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC);
@ -66,7 +66,7 @@ public abstract class AbstractUserSessionClusterListener<SE extends SessionClust
});
}
protected abstract void eventReceived(KeycloakSession session, T provider, SE sessionEvent);
protected abstract void eventReceived(T provider, SE sessionEvent);
private boolean shouldResendEvent(KeycloakSession session, SessionClusterEvent event) {

View file

@ -1,97 +0,0 @@
/*
* Copyright 2016 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.events;
import org.keycloak.models.KeycloakSession;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ClientRemovedSessionEvent.ExternalizerImpl.class)
public class ClientRemovedSessionEvent extends SessionClusterEvent {
private String clientUuid;
public static ClientRemovedSessionEvent create(KeycloakSession session, String eventKey, String realmId, boolean resendingEvent, String clientUuid) {
ClientRemovedSessionEvent event = ClientRemovedSessionEvent.createEvent(ClientRemovedSessionEvent.class, eventKey, session, realmId, resendingEvent);
event.clientUuid = clientUuid;
return event;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientRemovedSessionEvent that = (ClientRemovedSessionEvent) o;
return Objects.equals(clientUuid, that.clientUuid);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid);
}
@Override
public String toString() {
return String.format("ClientRemovedSessionEvent [ realmId=%s , clientUuid=%s ]", getRealmId(), clientUuid);
}
public String getClientUuid() {
return clientUuid;
}
public static class ExternalizerImpl implements Externalizer<ClientRemovedSessionEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientRemovedSessionEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
MarshallUtil.marshallString(obj.clientUuid, output);
}
@Override
public ClientRemovedSessionEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientRemovedSessionEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientRemovedSessionEvent res = new ClientRemovedSessionEvent();
res.unmarshallFrom(input);
res.clientUuid = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -38,14 +38,12 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
protected final KeycloakSessionFactory sessionFactory;
protected final Cache<String, Serializable> workCache;
protected final SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader;
protected final int sessionsPerSegment;
protected final String stateKey;
public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader, String stateKeySuffix, int sessionsPerSegment) {
public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader, String stateKeySuffix) {
this.sessionFactory = sessionFactory;
this.workCache = workCache;
this.sessionLoader = sessionLoader;
this.sessionsPerSegment = sessionsPerSegment;
this.stateKey = STATE_KEY_PREFIX + stateKeySuffix;
}
@ -59,8 +57,7 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
@Override
protected boolean isCoordinator() {
Transport transport = workCache.getCacheManager().getTransport();
return transport == null || transport.isCoordinator();
return workCache.getCacheManager().isCoordinator();
}
@Override

View file

@ -28,9 +28,6 @@ public abstract class CacheInitializer {
private static final Logger log = Logger.getLogger(CacheInitializer.class);
public void initCache() {
}
public void loadSessions() {
Instant loadingMustContinueBy = Instant.now().plusSeconds(getStalledTimeoutInSeconds());
boolean loadingStalledInPreviousStep = false;

View file

@ -46,14 +46,13 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
// Effectively no timeout
private final int stalledTimeoutInSeconds;
public InfinispanCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader sessionLoader, String stateKeySuffix, int sessionsPerSegment, int maxErrors, int stalledTimeoutInSeconds) {
super(sessionFactory, workCache, sessionLoader, stateKeySuffix, sessionsPerSegment);
public InfinispanCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader sessionLoader, String stateKeySuffix, int maxErrors, int stalledTimeoutInSeconds) {
super(sessionFactory, workCache, sessionLoader, stateKeySuffix);
this.maxErrors = maxErrors;
this.stalledTimeoutInSeconds = stalledTimeoutInSeconds;
}
@Override
public void initCache() {
// due to lazy initialization, this might be called from multiple threads simultaneously, therefore, synchronize
synchronized (workCache) {
@ -72,19 +71,10 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
InitializerState state = getStateFromCache();
SessionLoader.LoaderContext[] ctx = new SessionLoader.LoaderContext[1];
if (state == null) {
// Rather use separate transactions for update and counting
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
@Override
public void run(KeycloakSession session) {
sessionLoader.init(session);
}
});
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
@Override
public void run(KeycloakSession session) {
ctx[0] = sessionLoader.computeLoaderContext(session);
ctx[0] = sessionLoader.computeLoaderContext();
}
});
@ -94,7 +84,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
@Override
public void run(KeycloakSession session) {
ctx[0] = sessionLoader.computeLoaderContext(session);
ctx[0] = sessionLoader.computeLoaderContext();
}
});
@ -115,8 +105,6 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
int errors = 0;
int segmentToLoad = 0;
SessionLoader.WorkerResult previousResult = null;
SessionLoader.WorkerResult nextResult = null;
int distributedWorkersCount = 1;
while (segmentToLoad < state.getSegmentsCount()) {
@ -132,7 +120,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
final Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>();
for (Integer segment : segments) {
SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(loaderCtx, segment, segment - segmentToLoad, previousResult);
SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(segment);
SessionInitializerWorker worker = new SessionInitializerWorker();
worker.setWorkerEnvironment(loaderCtx, workerCtx, sessionLoader);
@ -144,15 +132,14 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
// Check the results
for (SessionLoader.WorkerResult result : results) {
if (result.isSuccess()) {
state.markSegmentFinished(result.getSegment());
if (result.getSegment() == segmentToLoad + distributedWorkersCount - 1) {
if (result.success()) {
state.markSegmentFinished(result.segment());
if (result.segment() == segmentToLoad + distributedWorkersCount - 1) {
// last result for next iteration when complete
nextResult = result;
}
} else {
if (log.isTraceEnabled()) {
log.tracef("Segment %d failed to compute", result.getSegment());
log.tracef("Segment %d failed to compute", result.segment());
}
anyFailure = true;
}
@ -165,8 +152,6 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
if (!anyFailure) {
// everything is OK, prepare the new row
segmentToLoad += distributedWorkersCount;
previousResult = nextResult;
nextResult = null;
if (log.isTraceEnabled()) {
log.debugf("New initializer state is: %s", state);
}
@ -177,7 +162,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
saveStateToCache(state);
// Loader callback after the task is finished
this.sessionLoader.afterAllSessionsLoaded(this);
this.sessionLoader.afterAllSessionsLoaded();
}
}

View file

@ -41,15 +41,6 @@ public class OfflinePersistentLoaderContext extends SessionLoader.LoaderContext
}
public int getSessionsTotal() {
return sessionsTotal;
}
public int getSessionsPerSegment() {
return sessionsPerSegment;
}
@Override
public String toString() {
return new StringBuilder("OfflinePersistentLoaderContext [ ")

View file

@ -1,35 +0,0 @@
/*
* 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.initializer;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class OfflinePersistentWorkerContext extends SessionLoader.WorkerContext {
private final String lastSessionId;
public OfflinePersistentWorkerContext(int segment, int workerId, String lastSessionId) {
super(segment, workerId);
this.lastSessionId = lastSessionId;
}
public String getLastSessionId() {
return lastSessionId;
}
}

View file

@ -1,36 +0,0 @@
/*
* 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.initializer;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class OfflinePersistentWorkerResult extends SessionLoader.WorkerResult {
private final String lastSessionId;
public OfflinePersistentWorkerResult(boolean success, int segment, int workerId, String lastSessionId) {
super(success, segment, workerId);
this.lastSessionId = lastSessionId;
}
public String getLastSessionId() {
return lastSessionId;
}
}

View file

@ -28,15 +28,6 @@ public interface SessionLoader<LOADER_CONTEXT extends SessionLoader.LoaderContex
WORKER_CONTEXT extends SessionLoader.WorkerContext,
WORKER_RESULT extends SessionLoader.WorkerResult> extends Serializable {
/**
* Will be triggered just once on cluster coordinator node to perform some generic initialization tasks (Eg. update DB before starting load).
*
* NOTE: This shouldn't be used for the initialization of loader instance itself!
*
* @param session
*/
void init(KeycloakSession session);
/**
*
@ -45,22 +36,18 @@ public interface SessionLoader<LOADER_CONTEXT extends SessionLoader.LoaderContex
*
* This method could be expensive to call, so the "computed" loaderContext object is passed among workers/loaders and needs to be serializable
*
* @param session
* @return
*/
LOADER_CONTEXT computeLoaderContext(KeycloakSession session);
LOADER_CONTEXT computeLoaderContext();
/**
* Compute the worker context for current iteration
*
* @param loaderCtx global loader context
* @param segment the current segment (page) to compute
* @param workerId ID of worker for current worker iteration. Usually the number 0-8 (with single cluster node)
* @param previousResult last workerResult from previous computation. Can be empty list in case of the operation is triggered for the 1st time
* @return
*/
WORKER_CONTEXT computeWorkerContext(LOADER_CONTEXT loaderCtx, int segment, int workerId, WORKER_RESULT previousResult);
WORKER_CONTEXT computeWorkerContext(int segment);
/**
@ -74,21 +61,10 @@ public interface SessionLoader<LOADER_CONTEXT extends SessionLoader.LoaderContex
WORKER_RESULT loadSessions(KeycloakSession session, LOADER_CONTEXT loaderContext, WORKER_CONTEXT workerContext);
/**
* Called when it's not possible to compute current iteration and load session for some reason (EG. infinispan not yet fully initialized)
*
* @param loaderContext
* @param workerContext
* @return
*/
WORKER_RESULT createFailedWorkerResult(LOADER_CONTEXT loaderContext, WORKER_CONTEXT workerContext);
/**
* Callback triggered on cluster coordinator once it recognize that all sessions were successfully loaded
*
* @param initializer
*/
void afterAllSessionsLoaded(BaseCacheInitializer initializer);
void afterAllSessionsLoaded();
/**
@ -115,58 +91,13 @@ public interface SessionLoader<LOADER_CONTEXT extends SessionLoader.LoaderContex
* Object, which is computed before each worker iteration and contains some data to be used by the corresponding worker iteration.
* For example info about which segment/page should be loaded by current worker.
*/
class WorkerContext implements Serializable {
private final int segment;
private final int workerId;
public WorkerContext(int segment, int workerId) {
this.segment = segment;
this.workerId = workerId;
}
public int getSegment() {
return this.segment;
}
public int getWorkerId() {
return this.workerId;
}
record WorkerContext(int segment) implements Serializable {
}
/**
* Result of single worker iteration
*/
class WorkerResult implements Serializable {
private final boolean success;
private final int segment;
private final int workerId;
public WorkerResult(boolean success, int segment, int workerId) {
this.success = success;
this.segment = segment;
this.workerId = workerId;
}
public boolean isSuccess() {
return success;
}
public int getSegment() {
return segment;
}
public int getWorkerId() {
return workerId;
}
record WorkerResult(boolean success, int segment) implements Serializable {
}
}

View file

@ -64,9 +64,7 @@ public class RemoteCacheInvoker {
return;
}
V session = sessionWrapper.getEntity();
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
SessionUpdateTask.CacheOperation operation = task.getOperation();
SessionUpdateTask.CrossDCMessageStatus status = task.getCrossDCMessageStatus(sessionWrapper);
if (status == SessionUpdateTask.CrossDCMessageStatus.NOT_NEEDED) {
@ -106,8 +104,7 @@ public class RemoteCacheInvoker {
private <K, V extends SessionEntity> void runOnRemoteCache(TopologyInfo topology, RemoteCache<K, SessionEntityWrapper<V>> remoteCache, long maxIdleMs, K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
final V session = sessionWrapper.getEntity();
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
SessionUpdateTask.CacheOperation operation = task.getOperation();
switch (operation) {
case REMOVE:

View file

@ -97,7 +97,7 @@ public class RemoteCacheSessionListener<K, V extends SessionEntity> {
// Doesn't work due https://issues.jboss.org/browse/ISPN-9323. Needs to explicitly retrieve and create it
//cache.get(key);
createRemoteEntityInCache(key, event.getVersion());
createRemoteEntityInCache(key);
});
}
@ -119,7 +119,7 @@ public class RemoteCacheSessionListener<K, V extends SessionEntity> {
}
protected void createRemoteEntityInCache(K key, long eventVersion) {
protected void createRemoteEntityInCache(K key) {
VersionedValue<SessionEntityWrapper<V>> remoteSessionVersioned = remoteCache.getWithMetadata(key);
// Maybe can happen under some circumstances that remoteCache doesn't yet contain the value sent in the event (maybe just theoretically...)
@ -249,18 +249,6 @@ public class RemoteCacheSessionListener<K, V extends SessionEntity> {
return result;
}
@ClientListener(includeCurrentState = true)
public static class FetchInitialStateCacheListener extends RemoteCacheSessionListener {
}
@ClientListener(includeCurrentState = false)
public static class DontFetchInitialStateCacheListener extends RemoteCacheSessionListener {
}
public static <K, V extends SessionEntity> RemoteCacheSessionListener createListener(KeycloakSession session, Cache<K, SessionEntityWrapper<V>> cache, RemoteCache<K, SessionEntityWrapper<V>> remoteCache,
SessionFunction<V> lifespanMsLoader, SessionFunction<V> maxIdleTimeMsLoader) {
/*boolean isCoordinator = InfinispanUtil.isCoordinator(cache);

View file

@ -32,7 +32,6 @@ import org.keycloak.common.util.Retry;
import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.sessions.infinispan.initializer.BaseCacheInitializer;
import org.keycloak.models.sessions.infinispan.initializer.SessionLoader;
/**
@ -52,27 +51,17 @@ public class RemoteCacheSessionsLoader implements SessionLoader<RemoteCacheSessi
@Override
public void init(KeycloakSession session) {
}
@Override
public RemoteCacheSessionsLoaderContext computeLoaderContext(KeycloakSession session) {
public RemoteCacheSessionsLoaderContext computeLoaderContext() {
return new RemoteCacheSessionsLoaderContext(sessionsPerSegment);
}
@Override
public WorkerContext computeWorkerContext(RemoteCacheSessionsLoaderContext loaderCtx, int segment, int workerId, WorkerResult previousResult) {
return new WorkerContext(segment, workerId);
public WorkerContext computeWorkerContext(int segment) {
return new WorkerContext(segment);
}
@Override
public WorkerResult createFailedWorkerResult(RemoteCacheSessionsLoaderContext loaderContext, WorkerContext workerContext) {
return new WorkerResult(false, workerContext.getSegment(), workerContext.getWorkerId());
}
@Override
public WorkerResult loadSessions(KeycloakSession session, RemoteCacheSessionsLoaderContext loaderContext, WorkerContext ctx) {
Cache<Object, Object> cache = getCache(session);
@ -142,13 +131,13 @@ public class RemoteCacheSessionsLoader implements SessionLoader<RemoteCacheSessi
insertSessions(decoratedCache, toInsertImmortal, maxIdleImmortal, -1);
}
} catch (RuntimeException e) {
log.warnf(e, "Error loading sessions from remote cache '%s' for segment '%d'", remoteCache.getName(), ctx.getSegment());
log.warnf(e, "Error loading sessions from remote cache '%s' for segment '%d'", remoteCache.getName(), ctx.segment());
throw e;
}
log.debugf("Successfully finished loading sessions from cache '%s' . Segment: %d, Count of sessions loaded: %d", cache.getName(), ctx.getSegment(), countLoaded);
log.debugf("Successfully finished loading sessions from cache '%s' . Segment: %d, Count of sessions loaded: %d", cache.getName(), ctx.segment(), countLoaded);
return new WorkerResult(true, ctx.getSegment(), ctx.getWorkerId());
return new WorkerResult(true, ctx.segment());
}
private void insertSessions(Cache<Object, Object> cache, Map<Object, Object> entries, int maxIdle, int lifespan) {
@ -169,7 +158,7 @@ public class RemoteCacheSessionsLoader implements SessionLoader<RemoteCacheSessi
}
@Override
public void afterAllSessionsLoaded(BaseCacheInitializer initializer) {
public void afterAllSessionsLoaded() {
}

View file

@ -33,17 +33,6 @@ public class RemoteCacheSessionsLoaderContext extends SessionLoader.LoaderContex
}
private static int computeSegmentsCount(int ispnSegments) {
// No support by remote ISPN cache for segments. This can happen if remoteCache is local (non-clustered)
if (ispnSegments < 0) {
return 1;
}
// always use the same number of ISPN segments to avoid touching multiple segments at a time
return ispnSegments;
}
public int getSessionsPerSegment() {
return sessionsPerSegment;
}

View file

@ -1,108 +0,0 @@
/*
* 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.stream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Map;
import java.util.UUID;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(AuthenticatedClientSessionPredicate.ExternalizerImpl.class)
public class AuthenticatedClientSessionPredicate implements Predicate<Map.Entry<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>>> {
private final String realm;
private Integer expired;
private AuthenticatedClientSessionPredicate(String realm) {
this.realm = realm;
}
/**
* Creates a client session predicate.
* @param realm
* @return
*/
public static AuthenticatedClientSessionPredicate create(String realm) {
return new AuthenticatedClientSessionPredicate(realm);
}
public AuthenticatedClientSessionPredicate expired(Integer expired) {
this.expired = expired;
return this;
}
@Override
public boolean test(Map.Entry<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> entry) {
AuthenticatedClientSessionEntity entity = entry.getValue().getEntity();
if (!realm.equals(entity.getRealmId())) {
return false;
}
if (expired != null && entity.getTimestamp() > expired) {
return false;
}
return true;
}
public static class ExternalizerImpl implements Externalizer<AuthenticatedClientSessionPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, AuthenticatedClientSessionPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realm, output);
KeycloakMarshallUtil.marshall(obj.expired, output);
}
@Override
public AuthenticatedClientSessionPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticatedClientSessionPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
AuthenticatedClientSessionPredicate res = new AuthenticatedClientSessionPredicate(MarshallUtil.unmarshallString(input));
res.expired(KeycloakMarshallUtil.unmarshallInteger(input));
return res;
}
}
}

View file

@ -1,55 +0,0 @@
/*
* Copyright 2016 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.stream;
import org.keycloak.models.sessions.infinispan.UserSessionTimestamp;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import java.io.Serializable;
import java.util.Comparator;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class Comparators {
public static Comparator<UserSessionTimestamp> userSessionTimestamp() {
return new UserSessionTimestampComparator();
}
private static class UserSessionTimestampComparator implements Comparator<UserSessionTimestamp>, Serializable {
@Override
public int compare(UserSessionTimestamp u1, UserSessionTimestamp u2) {
return u1.getClientSessionTimestamp() - u2.getClientSessionTimestamp();
}
}
public static Comparator<UserSessionEntity> userSessionLastSessionRefresh() {
return new UserSessionLastSessionRefreshComparator();
}
private static class UserSessionLastSessionRefreshComparator implements Comparator<UserSessionEntity>, Serializable {
@Override
public int compare(UserSessionEntity u1, UserSessionEntity u2) {
return u1.getLastSessionRefresh() - u2.getLastSessionRefresh();
}
}
}

View file

@ -18,17 +18,14 @@
package org.keycloak.models.sessions.infinispan.stream;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Stream;
@ -37,72 +34,15 @@ import java.util.stream.Stream;
*/
public class Mappers {
public static Function<Map.Entry<String, SessionEntityWrapper>, Map.Entry<String, SessionEntity>> unwrap() {
return new SessionUnwrap();
}
public static Function<Map.Entry<String, SessionEntityWrapper<UserSessionEntity>>, String> sessionId() {
return new SessionIdMapper();
}
public static Function<Map.Entry<String, SessionEntityWrapper>, SessionEntity> sessionEntity() {
return new SessionEntityMapper();
}
public static Function<Map.Entry<String, SessionEntityWrapper<UserSessionEntity>>, UserSessionEntity> userSessionEntity() {
return new UserSessionEntityMapper();
}
public static Function<Map.Entry<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>>, AuthenticatedClientSessionEntity> clientSessionEntity() {
return new AuthenticatedClientSessionEntityMapper();
}
public static Function<Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>>, LoginFailureKey> loginFailureId() {
return new LoginFailureIdMapper();
}
private static class SessionUnwrap implements Function<Map.Entry<String, SessionEntityWrapper>, Map.Entry<String, SessionEntity>>, Serializable {
@Override
public Map.Entry<String, SessionEntity> apply(Map.Entry<String, SessionEntityWrapper> wrapperEntry) {
return new Map.Entry<String, SessionEntity>() {
@Override
public String getKey() {
return wrapperEntry.getKey();
}
@Override
public SessionEntity getValue() {
return wrapperEntry.getValue().getEntity();
}
@Override
public SessionEntity setValue(SessionEntity value) {
throw new IllegalStateException("Unsupported operation");
}
};
}
}
private static class SessionIdMapper implements Function<Map.Entry<String, SessionEntityWrapper<UserSessionEntity>>, String>, Serializable {
@Override
public String apply(Map.Entry<String, SessionEntityWrapper<UserSessionEntity>> entry) {
return entry.getKey();
}
}
private static class SessionEntityMapper implements Function<Map.Entry<String, SessionEntityWrapper>, SessionEntity>, Serializable {
@Override
public SessionEntity apply(Map.Entry<String, SessionEntityWrapper> entry) {
return entry.getValue().getEntity();
}
}
private static class UserSessionEntityMapper implements Function<Map.Entry<String, SessionEntityWrapper<UserSessionEntity>>, UserSessionEntity>, Serializable {
@Override
@ -112,15 +52,6 @@ public class Mappers {
}
private static class AuthenticatedClientSessionEntityMapper implements Function<Map.Entry<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>>, AuthenticatedClientSessionEntity>, Serializable {
@Override
public AuthenticatedClientSessionEntity apply(Map.Entry<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> entry) {
return entry.getValue().getEntity();
}
}
private static class LoginFailureIdMapper implements Function<Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>>, LoginFailureKey>, Serializable {
@Override
public LoginFailureKey apply(Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> entry) {

View file

@ -22,7 +22,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
@ -40,8 +39,6 @@ import org.jboss.logging.Logger;
*/
public class KeycloakMarshallUtil {
private static final Logger log = Logger.getLogger(KeycloakMarshallUtil.class);
public static final Externalizer<String> STRING_EXT = new StringExternalizer();
public static final Externalizer<UUID> UUID_EXT = new Externalizer<UUID>() {
@ -174,14 +171,6 @@ public class KeycloakMarshallUtil {
}
public static class HashSetBuilder<E> implements MarshallUtil.CollectionBuilder<E, HashSet<E>> {
@Override
public HashSet<E> build(int size) {
return new HashSet<>(size);
}
}
private static class StringExternalizer implements Externalizer<String> {

View file

@ -37,11 +37,6 @@ public class SessionTimeouts {
*/
public static final long ENTRY_EXPIRED_FLAG = -2l;
/**
* This is used just if timeouts are not set on the realm (usually happens just during tests when realm is created manually with the model API)
*/
public static final int MINIMAL_EXPIRATION_SEC = 300;
/**
* Get the maximum lifespan, which this userSession can remain in the infinispan cache.
* Returned value will be used as "lifespan" when calling put/replace operation in the infinispan cache for this entity

View file

@ -103,8 +103,7 @@ public class RemoteCacheSessionsLoaderTest {
// Just to be able to test serializability
RemoteCacheSessionsLoader loader = new CustomLoader(cacheName, 64, cache2, remoteCache);
loader.init(null);
RemoteCacheSessionsLoaderContext ctx = loader.computeLoaderContext(null);
RemoteCacheSessionsLoaderContext ctx = loader.computeLoaderContext();
Assert.assertEquals(ctx.getSessionsPerSegment(), 64);
int totalCount = 0;
@ -113,7 +112,7 @@ public class RemoteCacheSessionsLoaderTest {
Set<String> visitedKeys = new HashSet<>();
for (int currentSegment=0 ; currentSegment<ctx.getSegmentsCount() ; currentSegment++) {
logger.infof("Loading segment %d", currentSegment);
loader.loadSessions(null, ctx, new SessionLoader.WorkerContext(currentSegment, currentSegment));
loader.loadSessions(null, ctx, new SessionLoader.WorkerContext(currentSegment));
logger.infof("Loaded %d keys for segment %d", cache2.keySet().size(), currentSegment);
totalCount = totalCount + cache2.keySet().size();