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.manager.EmbeddedCacheManager;
|
||||||
import org.infinispan.persistence.manager.PersistenceManager;
|
import org.infinispan.persistence.manager.PersistenceManager;
|
||||||
import org.infinispan.persistence.remote.RemoteStore;
|
import org.infinispan.persistence.remote.RemoteStore;
|
||||||
import org.infinispan.remoting.transport.Transport;
|
|
||||||
import org.infinispan.remoting.transport.jgroups.JGroupsTransport;
|
import org.infinispan.remoting.transport.jgroups.JGroupsTransport;
|
||||||
import org.infinispan.util.EmbeddedTimeService;
|
import org.infinispan.util.EmbeddedTimeService;
|
||||||
import org.jboss.logging.Logger;
|
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.
|
* 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) {
|
protected void bumpVersion(String id) {
|
||||||
long next = counter.next();
|
long next = counter.next();
|
||||||
Object rev = revisions.put(id, next);
|
revisions.put(id, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRevisioned(Revisioned object, long startupRevision) {
|
public void addRevisioned(Revisioned object, long startupRevision) {
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class RealmCacheManager extends CacheManager {
|
||||||
addInvalidations(InGroupPredicate.create().group(groupId), invalidations);
|
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));
|
invalidations.add(RealmCacheSession.getRealmClientsQueryCacheKey(realmId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,6 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
protected Set<String> invalidations = new HashSet<>();
|
protected Set<String> invalidations = new HashSet<>();
|
||||||
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
|
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
|
||||||
|
|
||||||
protected boolean clearAll;
|
|
||||||
protected final long startupRevision;
|
protected final long startupRevision;
|
||||||
private final StoreManagers datastoreProvider;
|
private final StoreManagers datastoreProvider;
|
||||||
|
|
||||||
|
@ -135,14 +134,6 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
|
session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStartupRevision() {
|
|
||||||
return startupRevision;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInvalid(String id) {
|
|
||||||
return invalidations.contains(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
|
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
|
||||||
|
@ -355,9 +346,6 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
@Override
|
@Override
|
||||||
public void commit() {
|
public void commit() {
|
||||||
try {
|
try {
|
||||||
if (clearAll) {
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
runInvalidations();
|
runInvalidations();
|
||||||
transactionActive = false;
|
transactionActive = false;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -551,7 +539,7 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
listInvalidations.add(realm.getId());
|
listInvalidations.add(realm.getId());
|
||||||
|
|
||||||
invalidationEvents.add(ClientAddedEvent.create(client.getId(), client.getClientId(), 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;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class UserAdapter implements CachedUserModel {
|
||||||
@Override
|
@Override
|
||||||
public UserModel getDelegateForUpdate() {
|
public UserModel getDelegateForUpdate() {
|
||||||
if (updated == null) {
|
if (updated == null) {
|
||||||
userProviderCache.registerUserInvalidation(realm, cached);
|
userProviderCache.registerUserInvalidation(cached);
|
||||||
updated = modelSupplier.get();
|
updated = modelSupplier.get();
|
||||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
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);
|
private static final Logger logger = Logger.getLogger(UserCacheManager.class);
|
||||||
|
|
||||||
protected volatile boolean enabled = true;
|
|
||||||
|
|
||||||
public UserCacheManager(Cache<String, Revisioned> cache, Cache<String, Long> revisions) {
|
public UserCacheManager(Cache<String, Revisioned> cache, Cache<String, Long> revisions) {
|
||||||
super(cache, revisions);
|
super(cache, revisions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class UserCacheSession implements UserCache, OnCreateComponent, OnUpdateC
|
||||||
return delegate;
|
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);
|
cache.userUpdatedInvalidations(user.getId(), user.getUsername(), user.getEmail(), user.getRealm(), invalidations);
|
||||||
invalidationEvents.add(UserUpdatedEvent.create(user.getId(), user.getUsername(), user.getEmail(), user.getRealm()));
|
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
|
// although we do set a timeout, Infinispan has no guarantees when the user will be evicted
|
||||||
// its also hard to test stuff
|
// its also hard to test stuff
|
||||||
if (model.shouldInvalidate(cached)) {
|
if (model.shouldInvalidate(cached)) {
|
||||||
registerUserInvalidation(realm, cached);
|
registerUserInvalidation(cached);
|
||||||
return getDelegate().getUserById(realm, cached.getId());
|
return getDelegate().getUserById(realm, cached.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,6 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
protected Set<String> invalidations = new HashSet<>();
|
protected Set<String> invalidations = new HashSet<>();
|
||||||
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
|
protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
|
||||||
|
|
||||||
protected boolean clearAll;
|
|
||||||
protected final long startupRevision;
|
protected final long startupRevision;
|
||||||
protected StoreFactory delegate;
|
protected StoreFactory delegate;
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
@ -250,16 +249,6 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
|
||||||
cache.sendInvalidationEvents(session, invalidationEvents, InfinispanCacheStoreFactoryProviderFactory.AUTHORIZATION_INVALIDATION_EVENTS);
|
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) {
|
public void registerResourceServerInvalidation(String id) {
|
||||||
cache.resourceServerUpdated(id, invalidations);
|
cache.resourceServerUpdated(id, invalidations);
|
||||||
ResourceServerAdapter adapter = managedResourceServers.get(id);
|
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;
|
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.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.stream.Collectors;
|
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>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -69,8 +66,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
|
||||||
protected boolean serviceAccountsEnabled;
|
protected boolean serviceAccountsEnabled;
|
||||||
protected int nodeReRegistrationTimeout;
|
protected int nodeReRegistrationTimeout;
|
||||||
protected Map<String, Integer> registeredNodes;
|
protected Map<String, Integer> registeredNodes;
|
||||||
protected List<String> defaultClientScopesIds;
|
|
||||||
protected List<String> optionalClientScopesIds;
|
|
||||||
|
|
||||||
public CachedClient(Long revision, RealmModel realm, ClientModel model) {
|
public CachedClient(Long revision, RealmModel realm, ClientModel model) {
|
||||||
super(revision, model.getId());
|
super(revision, model.getId());
|
||||||
|
@ -107,15 +102,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
|
||||||
|
|
||||||
nodeReRegistrationTimeout = model.getNodeReRegistrationTimeout();
|
nodeReRegistrationTimeout = model.getNodeReRegistrationTimeout();
|
||||||
registeredNodes = new TreeMap<>(model.getRegisteredNodes());
|
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() {
|
public String getClientId() {
|
||||||
|
@ -242,14 +228,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
|
||||||
return registeredNodes;
|
return registeredNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getDefaultClientScopesIds() {
|
|
||||||
return defaultClientScopesIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getOptionalClientScopesIds() {
|
|
||||||
return optionalClientScopesIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getAuthFlowBindings() {
|
public Map<String, String> getAuthFlowBindings() {
|
||||||
return authFlowBindings;
|
return authFlowBindings;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,16 @@
|
||||||
|
|
||||||
package org.keycloak.models.cache.infinispan.entities;
|
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.enums.SslRequired;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.component.ComponentModel;
|
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.DefaultLazyLoader;
|
||||||
import org.keycloak.models.cache.infinispan.LazyLoader;
|
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>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -151,7 +150,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
protected Set<String> eventsListeners;
|
protected Set<String> eventsListeners;
|
||||||
protected Set<String> enabledEventTypes;
|
protected Set<String> enabledEventTypes;
|
||||||
protected boolean adminEventsEnabled;
|
protected boolean adminEventsEnabled;
|
||||||
protected Set<String> adminEnabledEventOperations = new HashSet<>();
|
|
||||||
protected boolean adminEventsDetailsEnabled;
|
protected boolean adminEventsDetailsEnabled;
|
||||||
protected String defaultRoleId;
|
protected String defaultRoleId;
|
||||||
private boolean allowUserManagedAccess;
|
private boolean allowUserManagedAccess;
|
||||||
|
@ -597,10 +595,6 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
return adminEventsEnabled;
|
return adminEventsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getAdminEnabledEventOperations() {
|
|
||||||
return adminEnabledEventOperations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAdminEventsDetailsEnabled() {
|
public boolean isAdminEventsDetailsEnabled() {
|
||||||
return adminEventsDetailsEnabled;
|
return adminEventsDetailsEnabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import java.util.stream.Collectors;
|
||||||
public class GroupListQuery extends AbstractRevisioned implements GroupQuery {
|
public class GroupListQuery extends AbstractRevisioned implements GroupQuery {
|
||||||
private final String realm;
|
private final String realm;
|
||||||
private final String realmName;
|
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) {
|
public GroupListQuery(Long revisioned, String id, RealmModel realm, String searchKey, Set<String> result) {
|
||||||
super(revisioned, id);
|
super(revisioned, id);
|
||||||
|
@ -62,13 +62,6 @@ public class GroupListQuery extends AbstractRevisioned implements GroupQuery {
|
||||||
return realm;
|
return realm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Set<String>> getSearchKeys() {
|
|
||||||
if (searchKeys == null) {
|
|
||||||
searchKeys = new HashMap<>();
|
|
||||||
}
|
|
||||||
return searchKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "GroupListQuery{" +
|
return "GroupListQuery{" +
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class ClientAddedEvent extends InvalidationEvent implements RealmCacheInv
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
|
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
|
||||||
realmCache.clientAdded(realmId, clientUuid, clientId, invalidations);
|
realmCache.clientAdded(realmId, invalidations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
public class InfinispanAuthenticationSessionProvider implements AuthenticationSessionProvider {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(InfinispanAuthenticationSessionProvider.class);
|
|
||||||
|
|
||||||
private final KeycloakSession session;
|
private final KeycloakSession session;
|
||||||
private final Cache<String, RootAuthenticationSessionEntity> cache;
|
private final Cache<String, RootAuthenticationSessionEntity> cache;
|
||||||
private final InfinispanKeyGenerator keyGenerator;
|
private final InfinispanKeyGenerator keyGenerator;
|
||||||
|
@ -142,10 +140,6 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
|
||||||
// ClusterProvider.DCNotify.ALL_DCS);
|
// ClusterProvider.DCNotify.ALL_DCS);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onClientRemovedEvent(String realmId, String clientUuid) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateNonlocalSessionAuthNotes(AuthenticationSessionCompoundId compoundId, Map<String, String> authNotesFragment) {
|
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.AuthenticationSessionEntity;
|
||||||
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
|
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
|
||||||
import org.keycloak.models.sessions.infinispan.events.AbstractAuthSessionClusterListener;
|
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.events.RealmRemovedSessionEvent;
|
||||||
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
|
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
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 REALM_REMOVED_AUTHSESSION_EVENT = "REALM_REMOVED_EVENT_AUTHSESSIONS";
|
||||||
|
|
||||||
public static final String CLIENT_REMOVED_AUTHSESSION_EVENT = "CLIENT_REMOVED_SESSION_AUTHSESSIONS";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
// get auth sessions limit from config or use default if not provided
|
// 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) {
|
cluster.registerListener(REALM_REMOVED_AUTHSESSION_EVENT, new AbstractAuthSessionClusterListener<RealmRemovedSessionEvent>(sessionFactory) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void eventReceived(KeycloakSession session, InfinispanAuthenticationSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
|
protected void eventReceived(InfinispanAuthenticationSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
|
||||||
provider.onRealmRemovedEvent(sessionEvent.getRealmId());
|
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");
|
log.debug("Registered cluster listeners");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@ package org.keycloak.models.sessions.infinispan;
|
||||||
|
|
||||||
import org.infinispan.client.hotrod.RemoteCache;
|
import org.infinispan.client.hotrod.RemoteCache;
|
||||||
import org.infinispan.commons.api.BasicCache;
|
import org.infinispan.commons.api.BasicCache;
|
||||||
import org.keycloak.cluster.ClusterEvent;
|
|
||||||
import org.keycloak.cluster.ClusterProvider;
|
|
||||||
import org.infinispan.context.Flag;
|
import org.infinispan.context.Flag;
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
|
|
||||||
|
@ -52,7 +50,7 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
|
||||||
};
|
};
|
||||||
|
|
||||||
public enum CacheOperation {
|
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;
|
private boolean active;
|
||||||
|
@ -93,32 +91,6 @@ public class InfinispanKeycloakTransaction implements KeycloakTransaction {
|
||||||
return active;
|
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) {
|
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);
|
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) {
|
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);
|
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) {
|
public <K, V> void remove(BasicCache<K, V> cache, K key) {
|
||||||
log.tracev("Adding cache operation: {0} on {1}", CacheOperation.REMOVE, 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 long lifespan;
|
||||||
protected TimeUnit lifespanUnit;
|
protected TimeUnit lifespanUnit;
|
||||||
|
|
||||||
public CacheTaskWithValue(V value) {
|
|
||||||
this(value, -1, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CacheTaskWithValue(V value, long lifespan, TimeUnit lifespanUnit) {
|
public CacheTaskWithValue(V value, long lifespan, TimeUnit lifespanUnit) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.lifespan = lifespan;
|
this.lifespan = lifespan;
|
||||||
|
|
|
@ -25,10 +25,10 @@ import org.infinispan.client.hotrod.exceptions.HotRodClientException;
|
||||||
import org.infinispan.commons.api.BasicCache;
|
import org.infinispan.commons.api.BasicCache;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
import org.keycloak.connections.infinispan.InfinispanUtil;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.SingleUseObjectProvider;
|
import org.keycloak.models.SingleUseObjectProvider;
|
||||||
import org.keycloak.models.sessions.infinispan.entities.SingleUseObjectValueEntity;
|
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" .
|
* 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);
|
public static final Logger logger = Logger.getLogger(InfinispanSingleUseObjectProvider.class);
|
||||||
|
|
||||||
private final Supplier<BasicCache<String, SingleUseObjectValueEntity>> singleUseObjectCache;
|
private final Supplier<BasicCache<String, SingleUseObjectValueEntity>> singleUseObjectCache;
|
||||||
private final KeycloakSession session;
|
|
||||||
private final InfinispanKeycloakTransaction tx;
|
private final InfinispanKeycloakTransaction tx;
|
||||||
|
|
||||||
public InfinispanSingleUseObjectProvider(KeycloakSession session, Supplier<BasicCache<String, SingleUseObjectValueEntity>> singleUseObjectCache) {
|
public InfinispanSingleUseObjectProvider(KeycloakSession session, Supplier<BasicCache<String, SingleUseObjectValueEntity>> singleUseObjectCache) {
|
||||||
this.session = session;
|
|
||||||
this.singleUseObjectCache = singleUseObjectCache;
|
this.singleUseObjectCache = singleUseObjectCache;
|
||||||
this.tx = new InfinispanKeycloakTransaction();
|
this.tx = new InfinispanKeycloakTransaction();
|
||||||
|
|
||||||
session.getTransactionManager().enlistAfterCompletion(tx);
|
session.getTransactionManager().enlistAfterCompletion(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
|
||||||
new AbstractUserSessionClusterListener<RealmRemovedSessionEvent, UserLoginFailureProvider>(sessionFactory, UserLoginFailureProvider.class) {
|
new AbstractUserSessionClusterListener<RealmRemovedSessionEvent, UserLoginFailureProvider>(sessionFactory, UserLoginFailureProvider.class) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void eventReceived(KeycloakSession session, UserLoginFailureProvider provider, RealmRemovedSessionEvent sessionEvent) {
|
protected void eventReceived(UserLoginFailureProvider provider, RealmRemovedSessionEvent sessionEvent) {
|
||||||
if (provider instanceof InfinispanUserLoginFailureProvider) {
|
if (provider instanceof InfinispanUserLoginFailureProvider) {
|
||||||
((InfinispanUserLoginFailureProvider) provider).removeAllLocalUserLoginFailuresEvent(sessionEvent.getRealmId());
|
((InfinispanUserLoginFailureProvider) provider).removeAllLocalUserLoginFailuresEvent(sessionEvent.getRealmId());
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
|
||||||
new AbstractUserSessionClusterListener<RemoveAllUserLoginFailuresEvent, UserLoginFailureProvider>(sessionFactory, UserLoginFailureProvider.class) {
|
new AbstractUserSessionClusterListener<RemoveAllUserLoginFailuresEvent, UserLoginFailureProvider>(sessionFactory, UserLoginFailureProvider.class) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void eventReceived(KeycloakSession session, UserLoginFailureProvider provider, RemoveAllUserLoginFailuresEvent sessionEvent) {
|
protected void eventReceived(UserLoginFailureProvider provider, RemoveAllUserLoginFailuresEvent sessionEvent) {
|
||||||
if (provider instanceof InfinispanUserLoginFailureProvider) {
|
if (provider instanceof InfinispanUserLoginFailureProvider) {
|
||||||
((InfinispanUserLoginFailureProvider) provider).removeAllLocalUserLoginFailuresEvent(sessionEvent.getRealmId());
|
((InfinispanUserLoginFailureProvider) provider).removeAllLocalUserLoginFailuresEvent(sessionEvent.getRealmId());
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
|
||||||
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);
|
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);
|
||||||
|
|
||||||
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
|
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
|
||||||
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors,
|
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
|
||||||
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
|
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
|
||||||
|
|
||||||
initializer.initCache();
|
initializer.initCache();
|
||||||
|
|
|
@ -113,7 +113,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
|
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
|
||||||
protected final PersisterLastSessionRefreshStore persisterLastSessionRefreshStore;
|
protected final PersisterLastSessionRefreshStore persisterLastSessionRefreshStore;
|
||||||
|
|
||||||
protected final RemoteCacheInvoker remoteCacheInvoker;
|
|
||||||
protected final InfinispanKeyGenerator keyGenerator;
|
protected final InfinispanKeyGenerator keyGenerator;
|
||||||
|
|
||||||
protected final SessionFunction offlineSessionCacheEntryLifespanAdjuster;
|
protected final SessionFunction offlineSessionCacheEntryLifespanAdjuster;
|
||||||
|
@ -153,7 +152,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
this.lastSessionRefreshStore = lastSessionRefreshStore;
|
this.lastSessionRefreshStore = lastSessionRefreshStore;
|
||||||
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
|
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
|
||||||
this.persisterLastSessionRefreshStore = persisterLastSessionRefreshStore;
|
this.persisterLastSessionRefreshStore = persisterLastSessionRefreshStore;
|
||||||
this.remoteCacheInvoker = remoteCacheInvoker;
|
|
||||||
this.keyGenerator = keyGenerator;
|
this.keyGenerator = keyGenerator;
|
||||||
this.offlineSessionCacheEntryLifespanAdjuster = offlineSessionCacheEntryLifespanAdjuster;
|
this.offlineSessionCacheEntryLifespanAdjuster = offlineSessionCacheEntryLifespanAdjuster;
|
||||||
this.offlineClientSessionCacheEntryLifespanAdjuster = offlineClientSessionCacheEntryLifespanAdjuster;
|
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) {
|
protected void onUserRemoved(RealmModel realm, UserModel user) {
|
||||||
removeUserSessions(realm, user, true);
|
removeUserSessions(realm, user, true);
|
||||||
|
@ -789,7 +783,6 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticatedClientSessionAdapter wrap(UserSessionModel userSession, ClientModel client, AuthenticatedClientSessionEntity entity, boolean offline) {
|
AuthenticatedClientSessionAdapter wrap(UserSessionModel userSession, ClientModel client, AuthenticatedClientSessionEntity entity, boolean offline) {
|
||||||
InfinispanChangelogBasedTransaction<String, UserSessionEntity> userSessionUpdateTx = getTransaction(offline);
|
|
||||||
InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx = getClientSessionTransaction(offline);
|
InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx = getClientSessionTransaction(offline);
|
||||||
return entity != null ? new AuthenticatedClientSessionAdapter(session, this, entity, client, userSession, clientSessionUpdateTx, offline) : null;
|
return entity != null ? new AuthenticatedClientSessionAdapter(session, this, entity, client, userSession, clientSessionUpdateTx, offline) : null;
|
||||||
}
|
}
|
||||||
|
@ -1151,7 +1144,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(UserSessionEntity session) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REPLACE;
|
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.SessionEntity;
|
||||||
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||||
import org.keycloak.models.sessions.infinispan.events.AbstractUserSessionClusterListener;
|
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.RealmRemovedSessionEvent;
|
||||||
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
|
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
|
||||||
import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer;
|
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 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 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_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE = "offlineSessionCacheEntryLifespanOverride";
|
||||||
public static final String CONFIG_OFFLINE_CLIENT_SESSION_CACHE_ENTRY_LIFESPAN_OVERRIDE = "offlineClientSessionCacheEntryLifespanOverride";
|
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) {
|
new AbstractUserSessionClusterListener<RealmRemovedSessionEvent, UserSessionProvider>(sessionFactory, UserSessionProvider.class) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void eventReceived(KeycloakSession session, UserSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
|
protected void eventReceived(UserSessionProvider provider, RealmRemovedSessionEvent sessionEvent) {
|
||||||
if (provider instanceof InfinispanUserSessionProvider) {
|
if (provider instanceof InfinispanUserSessionProvider) {
|
||||||
((InfinispanUserSessionProvider) provider).onRealmRemovedEvent(sessionEvent.getRealmId());
|
((InfinispanUserSessionProvider) provider).onRealmRemovedEvent(sessionEvent.getRealmId());
|
||||||
} else if (provider instanceof PersistentUserSessionProvider) {
|
} 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,
|
cluster.registerListener(REMOVE_USER_SESSIONS_EVENT,
|
||||||
new AbstractUserSessionClusterListener<RemoveUserSessionsEvent, UserSessionProvider>(sessionFactory, UserSessionProvider.class) {
|
new AbstractUserSessionClusterListener<RemoveUserSessionsEvent, UserSessionProvider>(sessionFactory, UserSessionProvider.class) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void eventReceived(KeycloakSession session, UserSessionProvider provider, RemoveUserSessionsEvent sessionEvent) {
|
protected void eventReceived(UserSessionProvider provider, RemoveUserSessionsEvent sessionEvent) {
|
||||||
if (provider instanceof InfinispanUserSessionProvider) {
|
if (provider instanceof InfinispanUserSessionProvider) {
|
||||||
((InfinispanUserSessionProvider) provider).onRemoveUserSessionsEvent(sessionEvent.getRealmId());
|
((InfinispanUserSessionProvider) provider).onRemoveUserSessionsEvent(sessionEvent.getRealmId());
|
||||||
} else if (provider instanceof PersistentUserSessionProvider) {
|
} else if (provider instanceof PersistentUserSessionProvider) {
|
||||||
|
@ -414,7 +397,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
|
||||||
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);
|
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);
|
||||||
|
|
||||||
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
|
InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache,
|
||||||
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors,
|
new RemoteCacheSessionsLoader(cacheName, sessionsPerSegment), "remoteCacheLoad::" + cacheName, maxErrors,
|
||||||
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
|
getStalledTimeoutInSeconds(defaultStateTransferTimeout));
|
||||||
|
|
||||||
initializer.initCache();
|
initializer.initCache();
|
||||||
|
|
|
@ -108,7 +108,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
protected final CrossDCLastSessionRefreshStore lastSessionRefreshStore;
|
protected final CrossDCLastSessionRefreshStore lastSessionRefreshStore;
|
||||||
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
|
protected final CrossDCLastSessionRefreshStore offlineLastSessionRefreshStore;
|
||||||
|
|
||||||
protected final RemoteCacheInvoker remoteCacheInvoker;
|
|
||||||
protected final InfinispanKeyGenerator keyGenerator;
|
protected final InfinispanKeyGenerator keyGenerator;
|
||||||
|
|
||||||
public PersistentUserSessionProvider(KeycloakSession session,
|
public PersistentUserSessionProvider(KeycloakSession session,
|
||||||
|
@ -151,7 +150,6 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
|
|
||||||
this.lastSessionRefreshStore = lastSessionRefreshStore;
|
this.lastSessionRefreshStore = lastSessionRefreshStore;
|
||||||
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
|
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
|
||||||
this.remoteCacheInvoker = remoteCacheInvoker;
|
|
||||||
this.keyGenerator = keyGenerator;
|
this.keyGenerator = keyGenerator;
|
||||||
|
|
||||||
session.getTransactionManager().enlistAfterCompletion(clusterEventsSenderTx);
|
session.getTransactionManager().enlistAfterCompletion(clusterEventsSenderTx);
|
||||||
|
@ -276,10 +274,10 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
return entityWrapper != null ? entityWrapper.getEntity() : null;
|
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);
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
return persister.loadUserSessionsStream(realm, user, offline, 0, null)
|
return persister.loadUserSessionsStream(realm, user, true, 0, null)
|
||||||
.map(persistentUserSession -> (UserSessionModel) getUserSession(realm, persistentUserSession.getId(), offline))
|
.map(persistentUserSession -> (UserSessionModel) getUserSession(realm, persistentUserSession.getId(), true))
|
||||||
.filter(Objects::nonNull);
|
.filter(Objects::nonNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,9 +334,9 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
|
|
||||||
if (predicate.getBrokerSessionId() != null && !offline) {
|
if (predicate.getBrokerSessionId() != null && !offline) {
|
||||||
// we haven't yet migrated the old offline entries, so they don't have a brokerSessionId yet
|
// 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())
|
.filter(predicate.toModelPredicate())
|
||||||
.map(s -> (UserSessionModel) getUserSession(realm, s.getId(), offline))
|
.map(s -> (UserSessionModel) getUserSession(realm, s.getId(), false))
|
||||||
.filter(Objects::nonNull);
|
.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) {
|
protected void onUserRemoved(RealmModel realm, UserModel user) {
|
||||||
removeUserSessions(realm, user, true);
|
removeUserSessions(realm, user, true);
|
||||||
removeUserSessions(realm, user, false);
|
removeUserSessions(realm, user, false);
|
||||||
|
@ -630,7 +623,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
}
|
}
|
||||||
|
|
||||||
UserSessionAdapter wrap(RealmModel realm, UserSessionEntity entity, boolean offline) {
|
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)) {
|
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));
|
LightweightUserAdapter lua = LightweightUserAdapter.fromString(session, realm, entity.getNotes().get(SESSION_NOTE_LIGHTWEIGHT_USER));
|
||||||
final UserSessionAdapter us = wrap(realm, entity, offline, lua);
|
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 :
|
UserSessionAdapter userSessionAdapter = (offlineUserSession instanceof UserSessionAdapter) ? (UserSessionAdapter) offlineUserSession :
|
||||||
getOfflineUserSession(offlineUserSession.getRealm(), offlineUserSession.getId());
|
getOfflineUserSession(offlineUserSession.getRealm(), offlineUserSession.getId());
|
||||||
|
|
||||||
AuthenticatedClientSessionAdapter offlineClientSession = importClientSession(userSessionAdapter, clientSession, true, false);
|
AuthenticatedClientSessionAdapter offlineClientSession = importOfflineClientSession(userSessionAdapter, clientSession);
|
||||||
|
|
||||||
// update timestamp to current time
|
// update timestamp to current time
|
||||||
offlineClientSession.setTimestamp(Time.currentTime());
|
offlineClientSession.setTimestamp(Time.currentTime());
|
||||||
|
@ -716,7 +709,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserSessionModel> getOfflineUserSessionsStream(RealmModel realm, UserModel user) {
|
public Stream<UserSessionModel> getOfflineUserSessionsStream(RealmModel realm, UserModel user) {
|
||||||
return getUserSessionsFromPersistenceProviderStream(realm, user, true);
|
return getUserSessionsFromPersistenceProviderStream(realm, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -862,11 +855,10 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
entity.setAuthenticatedClientSessions(new AuthenticatedClientSessionStore());
|
entity.setAuthenticatedClientSessions(new AuthenticatedClientSessionStore());
|
||||||
entity.setRememberMe(userSession.isRememberMe());
|
entity.setRememberMe(userSession.isRememberMe());
|
||||||
entity.setState(userSession.getState());
|
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.
|
// 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
|
// see related JIRA - KEYCLOAK-5350 and corresponding test
|
||||||
OfflineUserSessionModel oline = (OfflineUserSessionModel) userSession;
|
entity.setUser(offlineUserSession.getUserId());
|
||||||
entity.setUser(oline.getUserId());
|
|
||||||
// NOTE: Hack
|
// NOTE: Hack
|
||||||
// We skip calling entity.setLoginUsername(userSession.getLoginUsername())
|
// We skip calling entity.setLoginUsername(userSession.getLoginUsername())
|
||||||
|
|
||||||
|
@ -883,28 +875,15 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AuthenticatedClientSessionAdapter importClientSession(UserSessionAdapter sessionToImportInto,
|
private AuthenticatedClientSessionAdapter importOfflineClientSession(UserSessionAdapter sessionToImportInto,
|
||||||
AuthenticatedClientSessionModel clientSession,
|
AuthenticatedClientSessionModel clientSession) {
|
||||||
boolean offline,
|
|
||||||
boolean checkExpiration) {
|
|
||||||
AuthenticatedClientSessionEntity entity = createAuthenticatedClientSessionInstance(sessionToImportInto.getId(), 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());
|
entity.setUserSessionId(sessionToImportInto.getId());
|
||||||
|
|
||||||
// Update timestamp to same value as userSession. LastSessionRefresh of userSession from DB will have correct value
|
// Update timestamp to same value as userSession. LastSessionRefresh of userSession from DB will have correct value
|
||||||
entity.setTimestamp(sessionToImportInto.getLastSessionRefresh());
|
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();
|
final UUID clientSessionId = entity.getId();
|
||||||
|
|
||||||
SessionUpdateTask<AuthenticatedClientSessionEntity> createClientSessionTask = Tasks.addIfAbsentSync();
|
SessionUpdateTask<AuthenticatedClientSessionEntity> createClientSessionTask = Tasks.addIfAbsentSync();
|
||||||
|
@ -913,10 +892,10 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
|
||||||
AuthenticatedClientSessionStore clientSessions = sessionToImportInto.getEntity().getAuthenticatedClientSessions();
|
AuthenticatedClientSessionStore clientSessions = sessionToImportInto.getEntity().getAuthenticatedClientSessions();
|
||||||
clientSessions.put(clientSession.getClient().getId(), clientSessionId);
|
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);
|
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;
|
return wrappedEntity;
|
||||||
} else {
|
} else {
|
||||||
AuthenticatedClientSessionEntity entity = myUpdates.getEntityWrapper().getEntity();
|
|
||||||
|
|
||||||
// If entity is scheduled for remove, we don't return it.
|
// If entity is scheduled for remove, we don't return it.
|
||||||
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
|
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
|
||||||
|
|
||||||
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
|
return task.getOperation() == SessionUpdateTask.CacheOperation.REMOVE;
|
||||||
|
|
||||||
}).findFirst().isPresent();
|
}).findFirst().isPresent();
|
||||||
|
|
||||||
|
@ -192,7 +191,7 @@ public class ClientSessionPersistentChangelogBasedTransaction extends Persistent
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(UserSessionEntity session) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REPLACE;
|
return CacheOperation.REPLACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessi
|
||||||
public abstract class ClientSessionUpdateTask implements PersistentSessionUpdateTask<AuthenticatedClientSessionEntity> {
|
public abstract class ClientSessionUpdateTask implements PersistentSessionUpdateTask<AuthenticatedClientSessionEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(AuthenticatedClientSessionEntity session) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REPLACE;
|
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) {
|
private void runOperationInCluster(K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
|
||||||
V session = sessionWrapper.getEntity();
|
SessionUpdateTask.CacheOperation operation = task.getOperation();
|
||||||
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
|
|
||||||
|
|
||||||
// Don't need to run update of underlying entity. Local updates were already run
|
// Don't need to run update of underlying entity. Local updates were already run
|
||||||
//task.runUpdate(session);
|
//task.runUpdate(session);
|
||||||
|
|
|
@ -149,12 +149,10 @@ public class InfinispanChangelogBasedTransaction<K, V extends SessionEntity> ext
|
||||||
|
|
||||||
return wrappedEntity;
|
return wrappedEntity;
|
||||||
} else {
|
} else {
|
||||||
V entity = myUpdates.getEntityWrapper().getEntity();
|
|
||||||
|
|
||||||
// If entity is scheduled for remove, we don't return it.
|
// If entity is scheduled for remove, we don't return it.
|
||||||
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
|
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
|
||||||
|
|
||||||
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
|
return task.getOperation() == SessionUpdateTask.CacheOperation.REMOVE;
|
||||||
|
|
||||||
}).findFirst().isPresent();
|
}).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) {
|
private void runOperationInCluster(K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
|
||||||
V session = sessionWrapper.getEntity();
|
SessionUpdateTask.CacheOperation operation = task.getOperation();
|
||||||
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
|
|
||||||
|
|
||||||
// Don't need to run update of underlying entity. Local updates were already run
|
// Don't need to run update of underlying entity. Local updates were already run
|
||||||
//task.runUpdate(session);
|
//task.runUpdate(session);
|
||||||
|
|
|
@ -122,10 +122,10 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
|
||||||
RealmModel realm = sessionUpdates.getRealm();
|
RealmModel realm = sessionUpdates.getRealm();
|
||||||
UserSessionPersisterProvider userSessionPersister = innerSession.getProvider(UserSessionPersisterProvider.class);
|
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();
|
AuthenticatedClientSessionEntity entity = (AuthenticatedClientSessionEntity) sessionWrapper.getEntity();
|
||||||
userSessionPersister.removeClientSession(entity.getUserSessionId(), entity.getClientId(), entity.isOffline());
|
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();
|
AuthenticatedClientSessionEntity entity = (AuthenticatedClientSessionEntity) sessionWrapper.getEntity();
|
||||||
userSessionPersister.createClientSession(new AuthenticatedClientSessionModel() {
|
userSessionPersister.createClientSession(new AuthenticatedClientSessionModel() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -405,7 +405,7 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
|
||||||
};
|
};
|
||||||
sessionUpdates.getUpdateTasks().forEach(vSessionUpdateTask -> {
|
sessionUpdates.getUpdateTasks().forEach(vSessionUpdateTask -> {
|
||||||
vSessionUpdateTask.runUpdate((V) authenticatedClientSessionEntity);
|
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());
|
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);
|
UserSessionPersisterProvider userSessionPersister = innerSession.getProvider(UserSessionPersisterProvider.class);
|
||||||
UserSessionEntity entity = (UserSessionEntity) sessionWrapper.getEntity();
|
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());
|
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() {
|
userSessionPersister.createUserSession(new UserSessionModel() {
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
@ -729,7 +729,7 @@ public class JpaChangesPerformer<K, V extends SessionEntity> implements SessionC
|
||||||
};
|
};
|
||||||
sessionUpdates.getUpdateTasks().forEach(vSessionUpdateTask -> {
|
sessionUpdates.getUpdateTasks().forEach(vSessionUpdateTask -> {
|
||||||
vSessionUpdateTask.runUpdate((V) userSessionEntity);
|
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());
|
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> {
|
public abstract class LoginFailuresUpdateTask implements SessionUpdateTask<LoginFailureEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(LoginFailureEntity session) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REPLACE;
|
return CacheOperation.REPLACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class MergedUpdate<S extends SessionEntity> implements SessionUpdateTask<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(S session) {
|
public CacheOperation getOperation() {
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ public class MergedUpdate<S extends SessionEntity> implements SessionUpdateTask<
|
||||||
S session = sessionWrapper.getEntity();
|
S session = sessionWrapper.getEntity();
|
||||||
for (SessionUpdateTask<S> child : childUpdates) {
|
for (SessionUpdateTask<S> child : childUpdates) {
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
CacheOperation operation = child.getOperation(session);
|
CacheOperation operation = child.getOperation();
|
||||||
|
|
||||||
if (lifespanMs == SessionTimeouts.ENTRY_EXPIRED_FLAG || maxIdleTimeMs == SessionTimeouts.ENTRY_EXPIRED_FLAG) {
|
if (lifespanMs == SessionTimeouts.ENTRY_EXPIRED_FLAG || maxIdleTimeMs == SessionTimeouts.ENTRY_EXPIRED_FLAG) {
|
||||||
operation = CacheOperation.REMOVE;
|
operation = CacheOperation.REMOVE;
|
||||||
|
@ -91,9 +91,9 @@ public class MergedUpdate<S extends SessionEntity> implements SessionUpdateTask<
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Merge the operations. REMOVE is special case as other operations are not needed then.
|
// 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) {
|
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);
|
result.childUpdates.add(child);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,11 +164,9 @@ abstract public class PersistentSessionsChangelogBasedTransaction<K, V extends S
|
||||||
V entity = myUpdates.getEntityWrapper().getEntity();
|
V entity = myUpdates.getEntityWrapper().getEntity();
|
||||||
|
|
||||||
// If entity is scheduled for remove, we don't return it.
|
// If entity is scheduled for remove, we don't return it.
|
||||||
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
|
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream()
|
||||||
|
.map(SessionUpdateTask::getOperation)
|
||||||
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
|
.anyMatch(SessionUpdateTask.CacheOperation.REMOVE::equals);
|
||||||
|
|
||||||
}).findFirst().isPresent();
|
|
||||||
|
|
||||||
return scheduledForRemove ? null : myUpdates.getEntityWrapper();
|
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 static final Logger log = Logger.getLogger(SessionEntityWrapper.class);
|
||||||
|
|
||||||
private UUID version;
|
private final UUID version;
|
||||||
private final S entity;
|
private final S entity;
|
||||||
private final Map<String, String> localMetadata;
|
private final Map<String, String> localMetadata;
|
||||||
|
|
||||||
|
@ -91,10 +91,6 @@ public class SessionEntityWrapper<S extends SessionEntity> {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersion(UUID version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public S getEntity() {
|
public S getEntity() {
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
@ -116,13 +112,6 @@ public class SessionEntityWrapper<S extends SessionEntity> {
|
||||||
return localMetadata.get(key);
|
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) {
|
public Integer getLocalMetadataNoteInt(String key) {
|
||||||
String note = getLocalMetadataNote(key);
|
String note = getLocalMetadataNote(key);
|
||||||
return note==null ? null : Integer.valueOf(note);
|
return note==null ? null : Integer.valueOf(note);
|
||||||
|
|
|
@ -26,7 +26,7 @@ public interface SessionUpdateTask<S extends SessionEntity> {
|
||||||
|
|
||||||
void runUpdate(S entity);
|
void runUpdate(S entity);
|
||||||
|
|
||||||
CacheOperation getOperation(S entity);
|
CacheOperation getOperation();
|
||||||
|
|
||||||
CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper<S> sessionWrapper);
|
CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper<S> sessionWrapper);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class Tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(SessionEntity entity) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.ADD_IF_ABSENT;
|
return CacheOperation.ADD_IF_ABSENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public class Tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(SessionEntity entity) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REMOVE;
|
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
|
@Override
|
||||||
public void runUpdate(SessionEntity entity) {
|
public void runUpdate(SessionEntity entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(SessionEntity entity) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REMOVE;
|
return CacheOperation.REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,14 +81,10 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe
|
||||||
|
|
||||||
return wrappedEntity;
|
return wrappedEntity;
|
||||||
} else {
|
} else {
|
||||||
UserSessionEntity entity = myUpdates.getEntityWrapper().getEntity();
|
|
||||||
|
|
||||||
// If entity is scheduled for remove, we don't return it.
|
// If entity is scheduled for remove, we don't return it.
|
||||||
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
|
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream()
|
||||||
|
.map(SessionUpdateTask::getOperation)
|
||||||
return task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE;
|
.anyMatch(SessionUpdateTask.CacheOperation.REMOVE::equals);
|
||||||
|
|
||||||
}).findFirst().isPresent();
|
|
||||||
|
|
||||||
return scheduledForRemove ? null : myUpdates.getEntityWrapper();
|
return scheduledForRemove ? null : myUpdates.getEntityWrapper();
|
||||||
}
|
}
|
||||||
|
@ -133,15 +129,11 @@ public class UserSessionPersistentChangelogBasedTransaction extends PersistentSe
|
||||||
if (myUpdates == null) {
|
if (myUpdates == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
V entity = myUpdates.getEntityWrapper().getEntity();
|
|
||||||
|
|
||||||
// If entity is scheduled for remove, we don't return it.
|
// If entity is scheduled for remove, we don't return it.
|
||||||
boolean scheduledForRemove = myUpdates.getUpdateTasks()
|
|
||||||
|
return myUpdates.getUpdateTasks()
|
||||||
.stream()
|
.stream()
|
||||||
.anyMatch(task -> task.getOperation(entity) == SessionUpdateTask.CacheOperation.REMOVE);
|
.anyMatch(task -> task.getOperation() == SessionUpdateTask.CacheOperation.REMOVE);
|
||||||
|
|
||||||
return scheduledForRemove;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||||
public abstract class UserSessionUpdateTask implements PersistentSessionUpdateTask<UserSessionEntity> {
|
public abstract class UserSessionUpdateTask implements PersistentSessionUpdateTask<UserSessionEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CacheOperation getOperation(UserSessionEntity session) {
|
public CacheOperation getOperation() {
|
||||||
return CacheOperation.REPLACE;
|
return CacheOperation.REPLACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,10 +55,10 @@ public abstract class AbstractAuthSessionClusterListener <SE extends SessionClus
|
||||||
|
|
||||||
log.debugf("Received authentication session event '%s'", sessionEvent.toString());
|
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);
|
log.debugf("Received user session event '%s'. Should resend event: %b", sessionEvent.toString(), shouldResendEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
eventReceived(session, provider, sessionEvent);
|
eventReceived(provider, sessionEvent);
|
||||||
|
|
||||||
if (shouldResendEvent) {
|
if (shouldResendEvent) {
|
||||||
session.getProvider(ClusterProvider.class).notify(sessionEvent.getEventKey(), event, true, ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC);
|
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) {
|
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 KeycloakSessionFactory sessionFactory;
|
||||||
protected final Cache<String, Serializable> workCache;
|
protected final Cache<String, Serializable> workCache;
|
||||||
protected final SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader;
|
protected final SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader;
|
||||||
protected final int sessionsPerSegment;
|
|
||||||
protected final String stateKey;
|
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.sessionFactory = sessionFactory;
|
||||||
this.workCache = workCache;
|
this.workCache = workCache;
|
||||||
this.sessionLoader = sessionLoader;
|
this.sessionLoader = sessionLoader;
|
||||||
this.sessionsPerSegment = sessionsPerSegment;
|
|
||||||
this.stateKey = STATE_KEY_PREFIX + stateKeySuffix;
|
this.stateKey = STATE_KEY_PREFIX + stateKeySuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +57,7 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isCoordinator() {
|
protected boolean isCoordinator() {
|
||||||
Transport transport = workCache.getCacheManager().getTransport();
|
return workCache.getCacheManager().isCoordinator();
|
||||||
return transport == null || transport.isCoordinator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,9 +28,6 @@ public abstract class CacheInitializer {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(CacheInitializer.class);
|
private static final Logger log = Logger.getLogger(CacheInitializer.class);
|
||||||
|
|
||||||
public void initCache() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadSessions() {
|
public void loadSessions() {
|
||||||
Instant loadingMustContinueBy = Instant.now().plusSeconds(getStalledTimeoutInSeconds());
|
Instant loadingMustContinueBy = Instant.now().plusSeconds(getStalledTimeoutInSeconds());
|
||||||
boolean loadingStalledInPreviousStep = false;
|
boolean loadingStalledInPreviousStep = false;
|
||||||
|
|
|
@ -46,14 +46,13 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
// Effectively no timeout
|
// Effectively no timeout
|
||||||
private final int stalledTimeoutInSeconds;
|
private final int stalledTimeoutInSeconds;
|
||||||
|
|
||||||
public InfinispanCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader sessionLoader, String stateKeySuffix, int sessionsPerSegment, int maxErrors, int stalledTimeoutInSeconds) {
|
public InfinispanCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader sessionLoader, String stateKeySuffix, int maxErrors, int stalledTimeoutInSeconds) {
|
||||||
super(sessionFactory, workCache, sessionLoader, stateKeySuffix, sessionsPerSegment);
|
super(sessionFactory, workCache, sessionLoader, stateKeySuffix);
|
||||||
this.maxErrors = maxErrors;
|
this.maxErrors = maxErrors;
|
||||||
this.stalledTimeoutInSeconds = stalledTimeoutInSeconds;
|
this.stalledTimeoutInSeconds = stalledTimeoutInSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initCache() {
|
public void initCache() {
|
||||||
// due to lazy initialization, this might be called from multiple threads simultaneously, therefore, synchronize
|
// due to lazy initialization, this might be called from multiple threads simultaneously, therefore, synchronize
|
||||||
synchronized (workCache) {
|
synchronized (workCache) {
|
||||||
|
@ -72,19 +71,10 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
InitializerState state = getStateFromCache();
|
InitializerState state = getStateFromCache();
|
||||||
SessionLoader.LoaderContext[] ctx = new SessionLoader.LoaderContext[1];
|
SessionLoader.LoaderContext[] ctx = new SessionLoader.LoaderContext[1];
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
// Rather use separate transactions for update and counting
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run(KeycloakSession session) {
|
public void run(KeycloakSession session) {
|
||||||
sessionLoader.init(session);
|
ctx[0] = sessionLoader.computeLoaderContext();
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
ctx[0] = sessionLoader.computeLoaderContext(session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -94,7 +84,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run(KeycloakSession session) {
|
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 errors = 0;
|
||||||
int segmentToLoad = 0;
|
int segmentToLoad = 0;
|
||||||
|
|
||||||
SessionLoader.WorkerResult previousResult = null;
|
|
||||||
SessionLoader.WorkerResult nextResult = null;
|
|
||||||
int distributedWorkersCount = 1;
|
int distributedWorkersCount = 1;
|
||||||
|
|
||||||
while (segmentToLoad < state.getSegmentsCount()) {
|
while (segmentToLoad < state.getSegmentsCount()) {
|
||||||
|
@ -132,7 +120,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
final Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>();
|
final Queue<SessionLoader.WorkerResult> results = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
for (Integer segment : segments) {
|
for (Integer segment : segments) {
|
||||||
SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(loaderCtx, segment, segment - segmentToLoad, previousResult);
|
SessionLoader.WorkerContext workerCtx = sessionLoader.computeWorkerContext(segment);
|
||||||
|
|
||||||
SessionInitializerWorker worker = new SessionInitializerWorker();
|
SessionInitializerWorker worker = new SessionInitializerWorker();
|
||||||
worker.setWorkerEnvironment(loaderCtx, workerCtx, sessionLoader);
|
worker.setWorkerEnvironment(loaderCtx, workerCtx, sessionLoader);
|
||||||
|
@ -144,15 +132,14 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
|
|
||||||
// Check the results
|
// Check the results
|
||||||
for (SessionLoader.WorkerResult result : results) {
|
for (SessionLoader.WorkerResult result : results) {
|
||||||
if (result.isSuccess()) {
|
if (result.success()) {
|
||||||
state.markSegmentFinished(result.getSegment());
|
state.markSegmentFinished(result.segment());
|
||||||
if (result.getSegment() == segmentToLoad + distributedWorkersCount - 1) {
|
if (result.segment() == segmentToLoad + distributedWorkersCount - 1) {
|
||||||
// last result for next iteration when complete
|
// last result for next iteration when complete
|
||||||
nextResult = result;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (log.isTraceEnabled()) {
|
if (log.isTraceEnabled()) {
|
||||||
log.tracef("Segment %d failed to compute", result.getSegment());
|
log.tracef("Segment %d failed to compute", result.segment());
|
||||||
}
|
}
|
||||||
anyFailure = true;
|
anyFailure = true;
|
||||||
}
|
}
|
||||||
|
@ -165,8 +152,6 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
if (!anyFailure) {
|
if (!anyFailure) {
|
||||||
// everything is OK, prepare the new row
|
// everything is OK, prepare the new row
|
||||||
segmentToLoad += distributedWorkersCount;
|
segmentToLoad += distributedWorkersCount;
|
||||||
previousResult = nextResult;
|
|
||||||
nextResult = null;
|
|
||||||
if (log.isTraceEnabled()) {
|
if (log.isTraceEnabled()) {
|
||||||
log.debugf("New initializer state is: %s", state);
|
log.debugf("New initializer state is: %s", state);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +162,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer {
|
||||||
saveStateToCache(state);
|
saveStateToCache(state);
|
||||||
|
|
||||||
// Loader callback after the task is finished
|
// 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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new StringBuilder("OfflinePersistentLoaderContext [ ")
|
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_CONTEXT extends SessionLoader.WorkerContext,
|
||||||
WORKER_RESULT extends SessionLoader.WorkerResult> extends Serializable {
|
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
|
* 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
|
* @return
|
||||||
*/
|
*/
|
||||||
LOADER_CONTEXT computeLoaderContext(KeycloakSession session);
|
LOADER_CONTEXT computeLoaderContext();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the worker context for current iteration
|
* Compute the worker context for current iteration
|
||||||
*
|
*
|
||||||
* @param loaderCtx global loader context
|
|
||||||
* @param segment the current segment (page) to compute
|
* @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
|
* @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);
|
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
|
* 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.
|
* 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.
|
* For example info about which segment/page should be loaded by current worker.
|
||||||
*/
|
*/
|
||||||
class WorkerContext implements Serializable {
|
record WorkerContext(int segment) 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result of single worker iteration
|
* Result of single worker iteration
|
||||||
*/
|
*/
|
||||||
class WorkerResult implements Serializable {
|
record WorkerResult(boolean success, int segment) 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,7 @@ public class RemoteCacheInvoker {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
V session = sessionWrapper.getEntity();
|
SessionUpdateTask.CacheOperation operation = task.getOperation();
|
||||||
|
|
||||||
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
|
|
||||||
SessionUpdateTask.CrossDCMessageStatus status = task.getCrossDCMessageStatus(sessionWrapper);
|
SessionUpdateTask.CrossDCMessageStatus status = task.getCrossDCMessageStatus(sessionWrapper);
|
||||||
|
|
||||||
if (status == SessionUpdateTask.CrossDCMessageStatus.NOT_NEEDED) {
|
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) {
|
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();
|
||||||
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
|
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case REMOVE:
|
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
|
// Doesn't work due https://issues.jboss.org/browse/ISPN-9323. Needs to explicitly retrieve and create it
|
||||||
//cache.get(key);
|
//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);
|
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...)
|
// 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;
|
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,
|
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) {
|
SessionFunction<V> lifespanMsLoader, SessionFunction<V> maxIdleTimeMsLoader) {
|
||||||
/*boolean isCoordinator = InfinispanUtil.isCoordinator(cache);
|
/*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.DefaultInfinispanConnectionProviderFactory;
|
||||||
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.sessions.infinispan.initializer.BaseCacheInitializer;
|
|
||||||
import org.keycloak.models.sessions.infinispan.initializer.SessionLoader;
|
import org.keycloak.models.sessions.infinispan.initializer.SessionLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,27 +51,17 @@ public class RemoteCacheSessionsLoader implements SessionLoader<RemoteCacheSessi
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(KeycloakSession session) {
|
public RemoteCacheSessionsLoaderContext computeLoaderContext() {
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RemoteCacheSessionsLoaderContext computeLoaderContext(KeycloakSession session) {
|
|
||||||
return new RemoteCacheSessionsLoaderContext(sessionsPerSegment);
|
return new RemoteCacheSessionsLoaderContext(sessionsPerSegment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorkerContext computeWorkerContext(RemoteCacheSessionsLoaderContext loaderCtx, int segment, int workerId, WorkerResult previousResult) {
|
public WorkerContext computeWorkerContext(int segment) {
|
||||||
return new WorkerContext(segment, workerId);
|
return new WorkerContext(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WorkerResult createFailedWorkerResult(RemoteCacheSessionsLoaderContext loaderContext, WorkerContext workerContext) {
|
|
||||||
return new WorkerResult(false, workerContext.getSegment(), workerContext.getWorkerId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorkerResult loadSessions(KeycloakSession session, RemoteCacheSessionsLoaderContext loaderContext, WorkerContext ctx) {
|
public WorkerResult loadSessions(KeycloakSession session, RemoteCacheSessionsLoaderContext loaderContext, WorkerContext ctx) {
|
||||||
Cache<Object, Object> cache = getCache(session);
|
Cache<Object, Object> cache = getCache(session);
|
||||||
|
@ -142,13 +131,13 @@ public class RemoteCacheSessionsLoader implements SessionLoader<RemoteCacheSessi
|
||||||
insertSessions(decoratedCache, toInsertImmortal, maxIdleImmortal, -1);
|
insertSessions(decoratedCache, toInsertImmortal, maxIdleImmortal, -1);
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} 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;
|
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) {
|
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
|
@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() {
|
public int getSessionsPerSegment() {
|
||||||
return sessionsPerSegment;
|
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;
|
package org.keycloak.models.sessions.infinispan.stream;
|
||||||
|
|
||||||
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
|
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.LoginFailureEntity;
|
||||||
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
|
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 org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -37,72 +34,15 @@ import java.util.stream.Stream;
|
||||||
*/
|
*/
|
||||||
public class Mappers {
|
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() {
|
public static Function<Map.Entry<String, SessionEntityWrapper<UserSessionEntity>>, UserSessionEntity> userSessionEntity() {
|
||||||
return new UserSessionEntityMapper();
|
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() {
|
public static Function<Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>>, LoginFailureKey> loginFailureId() {
|
||||||
return new LoginFailureIdMapper();
|
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 {
|
private static class UserSessionEntityMapper implements Function<Map.Entry<String, SessionEntityWrapper<UserSessionEntity>>, UserSessionEntity>, Serializable {
|
||||||
|
|
||||||
@Override
|
@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 {
|
private static class LoginFailureIdMapper implements Function<Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>>, LoginFailureKey>, Serializable {
|
||||||
@Override
|
@Override
|
||||||
public LoginFailureKey apply(Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> entry) {
|
public LoginFailureKey apply(Map.Entry<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> entry) {
|
||||||
|
|
|
@ -22,7 +22,6 @@ import java.io.ObjectInput;
|
||||||
import java.io.ObjectOutput;
|
import java.io.ObjectOutput;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -40,8 +39,6 @@ import org.jboss.logging.Logger;
|
||||||
*/
|
*/
|
||||||
public class KeycloakMarshallUtil {
|
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<String> STRING_EXT = new StringExternalizer();
|
||||||
|
|
||||||
public static final Externalizer<UUID> UUID_EXT = new Externalizer<UUID>() {
|
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> {
|
private static class StringExternalizer implements Externalizer<String> {
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,6 @@ public class SessionTimeouts {
|
||||||
*/
|
*/
|
||||||
public static final long ENTRY_EXPIRED_FLAG = -2l;
|
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.
|
* 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
|
* 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
|
// Just to be able to test serializability
|
||||||
RemoteCacheSessionsLoader loader = new CustomLoader(cacheName, 64, cache2, remoteCache);
|
RemoteCacheSessionsLoader loader = new CustomLoader(cacheName, 64, cache2, remoteCache);
|
||||||
|
|
||||||
loader.init(null);
|
RemoteCacheSessionsLoaderContext ctx = loader.computeLoaderContext();
|
||||||
RemoteCacheSessionsLoaderContext ctx = loader.computeLoaderContext(null);
|
|
||||||
Assert.assertEquals(ctx.getSessionsPerSegment(), 64);
|
Assert.assertEquals(ctx.getSessionsPerSegment(), 64);
|
||||||
|
|
||||||
int totalCount = 0;
|
int totalCount = 0;
|
||||||
|
@ -113,7 +112,7 @@ public class RemoteCacheSessionsLoaderTest {
|
||||||
Set<String> visitedKeys = new HashSet<>();
|
Set<String> visitedKeys = new HashSet<>();
|
||||||
for (int currentSegment=0 ; currentSegment<ctx.getSegmentsCount() ; currentSegment++) {
|
for (int currentSegment=0 ; currentSegment<ctx.getSegmentsCount() ; currentSegment++) {
|
||||||
logger.infof("Loading segment %d", 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);
|
logger.infof("Loaded %d keys for segment %d", cache2.keySet().size(), currentSegment);
|
||||||
totalCount = totalCount + cache2.keySet().size();
|
totalCount = totalCount + cache2.keySet().size();
|
||||||
|
|
Loading…
Reference in a new issue