Remove unused code from model/infinispan module
Closes #29137 Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
parent
7775e4ad18
commit
4c6f3ce35d
56 changed files with 115 additions and 1038 deletions
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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{" +
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 [ ")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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> {
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue