Add cascade removal of client session on user session removal for HotRod
Closes #12096
This commit is contained in:
parent
1a98765fb7
commit
9b36ea0269
6 changed files with 177 additions and 78 deletions
|
@ -56,10 +56,10 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
|
|||
private static final Logger LOG = Logger.getLogger(HotRodMapStorage.class);
|
||||
|
||||
private final RemoteCache<K, E> remoteCache;
|
||||
private final StringKeyConverter<K> keyConverter;
|
||||
private final HotRodEntityDescriptor<E, V> storedEntityDescriptor;
|
||||
protected final StringKeyConverter<K> keyConverter;
|
||||
protected final HotRodEntityDescriptor<E, V> storedEntityDescriptor;
|
||||
private final Function<E, V> delegateProducer;
|
||||
private final DeepCloner cloner;
|
||||
protected final DeepCloner cloner;
|
||||
|
||||
public HotRodMapStorage(RemoteCache<K, E> remoteCache, StringKeyConverter<K> keyConverter, HotRodEntityDescriptor<E, V> storedEntityDescriptor, DeepCloner cloner) {
|
||||
this.remoteCache = remoteCache;
|
||||
|
@ -191,7 +191,13 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
|
|||
|
||||
@Override
|
||||
public MapKeycloakTransaction<V, M> createTransaction(KeycloakSession session) {
|
||||
Map<SearchableModelField<? super M>, MapModelCriteriaBuilder.UpdatePredicatesFunc<K, V, M>> fieldPredicates = MapFieldPredicates.getPredicates((Class<M>) storedEntityDescriptor.getModelTypeClass());
|
||||
return new ConcurrentHashMapKeycloakTransaction<>(this, keyConverter, cloner, fieldPredicates);
|
||||
MapKeycloakTransaction<V, M> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
|
||||
if (sessionTransaction == null) {
|
||||
Map<SearchableModelField<? super M>, MapModelCriteriaBuilder.UpdatePredicatesFunc<K, V, M>> fieldPredicates = MapFieldPredicates.getPredicates((Class<M>) storedEntityDescriptor.getModelTypeClass());
|
||||
sessionTransaction = new ConcurrentHashMapKeycloakTransaction<>(this, keyConverter, cloner, fieldPredicates);
|
||||
session.setAttribute("map-transaction-" + hashCode(), sessionTransaction);
|
||||
}
|
||||
return sessionTransaction;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,39 +17,25 @@
|
|||
|
||||
package org.keycloak.models.map.storage.hotRod;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
|
||||
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDescriptor;
|
||||
import org.keycloak.models.map.common.StringKeyConverter;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageProviderFactory;
|
||||
|
||||
public class HotRodMapStorageProvider implements MapStorageProvider {
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final HotRodMapStorageProviderFactory factory;
|
||||
private final HotRodConnectionProvider connectionProvider;
|
||||
private final DeepCloner cloner;
|
||||
|
||||
public HotRodMapStorageProvider(HotRodMapStorageProviderFactory factory, HotRodConnectionProvider connectionProvider, DeepCloner cloner) {
|
||||
public HotRodMapStorageProvider(KeycloakSession session, HotRodMapStorageProviderFactory factory) {
|
||||
this.session = session;
|
||||
this.factory = factory;
|
||||
this.connectionProvider = connectionProvider;
|
||||
this.cloner = cloner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends AbstractEntity, M> MapStorage<V, M> getStorage(Class<M> modelType, MapStorageProviderFactory.Flag... flags) {
|
||||
HotRodMapStorage storage = getHotRodStorage(modelType, flags);
|
||||
return storage;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E extends AbstractHotRodEntity, V extends HotRodEntityDelegate<E> & AbstractEntity, M> HotRodMapStorage<String, E, V, M> getHotRodStorage(Class<M> modelType, MapStorageProviderFactory.Flag... flags) {
|
||||
HotRodEntityDescriptor<E, V> entityDescriptor = (HotRodEntityDescriptor<E, V>) factory.getEntityDescriptor(modelType);
|
||||
return new HotRodMapStorage<>(connectionProvider.getRemoteCache(entityDescriptor.getCacheName()), StringKeyConverter.StringKey.INSTANCE, entityDescriptor, cloner);
|
||||
return (MapStorage<V, M>) factory.getHotRodStorage(session, modelType, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -45,6 +45,8 @@ import org.keycloak.models.map.authorization.entity.MapScopeEntity;
|
|||
import org.keycloak.models.map.authSession.MapAuthenticationSessionEntity;
|
||||
import org.keycloak.models.map.authSession.MapRootAuthenticationSessionEntity;
|
||||
import org.keycloak.models.map.clientscope.MapClientScopeEntity;
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.common.StringKeyConverter;
|
||||
import org.keycloak.models.map.group.MapGroupEntity;
|
||||
import org.keycloak.models.map.loginFailure.MapUserLoginFailureEntity;
|
||||
import org.keycloak.models.map.realm.MapRealmEntity;
|
||||
|
@ -73,6 +75,8 @@ import org.keycloak.models.map.storage.hotRod.authorization.HotRodResourceServer
|
|||
import org.keycloak.models.map.storage.hotRod.authorization.HotRodResourceServerEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.authorization.HotRodScopeEntity;
|
||||
import org.keycloak.models.map.storage.hotRod.authorization.HotRodScopeEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
|
||||
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.loginFailure.HotRodUserLoginFailureEntity;
|
||||
import org.keycloak.models.map.storage.hotRod.loginFailure.HotRodUserLoginFailureEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.role.HotRodRoleEntity;
|
||||
|
@ -113,6 +117,7 @@ import org.keycloak.models.map.storage.hotRod.userSession.HotRodAuthenticatedCli
|
|||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodAuthenticatedClientSessionEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodUserSessionEntity;
|
||||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodUserSessionEntityDelegate;
|
||||
import org.keycloak.models.map.storage.hotRod.userSession.HotRodUserSessionMapStorage;
|
||||
import org.keycloak.models.map.user.MapUserConsentEntity;
|
||||
import org.keycloak.models.map.user.MapUserCredentialEntity;
|
||||
import org.keycloak.models.map.user.MapUserEntity;
|
||||
|
@ -124,11 +129,14 @@ import org.keycloak.sessions.RootAuthenticationSessionModel;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HotRodMapStorageProviderFactory implements AmphibianProviderFactory<MapStorageProvider>, MapStorageProviderFactory, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "hotrod";
|
||||
private static final Logger LOG = Logger.getLogger(HotRodMapStorageProviderFactory.class);
|
||||
private final Map<Class<?>, HotRodMapStorage> storages = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
private final static DeepCloner CLONER = new DeepCloner.Builder()
|
||||
.constructor(MapRootAuthenticationSessionEntity.class, HotRodRootAuthenticationSessionEntityDelegate::new)
|
||||
|
@ -289,19 +297,30 @@ public class HotRodMapStorageProviderFactory implements AmphibianProviderFactory
|
|||
|
||||
@Override
|
||||
public MapStorageProvider create(KeycloakSession session) {
|
||||
HotRodConnectionProvider cacheProvider = session.getProvider(HotRodConnectionProvider.class);
|
||||
|
||||
if (cacheProvider == null) {
|
||||
throw new IllegalStateException("Cannot find HotRodConnectionProvider interface implementation");
|
||||
}
|
||||
|
||||
return new HotRodMapStorageProvider(this, cacheProvider, CLONER);
|
||||
return new HotRodMapStorageProvider(session, this);
|
||||
}
|
||||
|
||||
public HotRodEntityDescriptor<?, ?> getEntityDescriptor(Class<?> c) {
|
||||
return ENTITY_DESCRIPTOR_MAP.get(c);
|
||||
}
|
||||
|
||||
public <E extends AbstractHotRodEntity, V extends HotRodEntityDelegate<E> & AbstractEntity, M> HotRodMapStorage<String, E, V, M> getHotRodStorage(KeycloakSession session, Class<M> modelType, MapStorageProviderFactory.Flag... flags) {
|
||||
if (modelType == UserSessionModel.class) getHotRodStorage(session, AuthenticatedClientSessionModel.class, flags);
|
||||
return storages.computeIfAbsent(modelType, c -> createHotRodStorage(session, modelType, flags));
|
||||
}
|
||||
|
||||
private <E extends AbstractHotRodEntity, V extends HotRodEntityDelegate<E> & AbstractEntity, M> HotRodMapStorage<String, E, V, M> createHotRodStorage(KeycloakSession session, Class<M> modelType, MapStorageProviderFactory.Flag... flags) {
|
||||
HotRodConnectionProvider connectionProvider = session.getProvider(HotRodConnectionProvider.class);
|
||||
HotRodEntityDescriptor<E, V> entityDescriptor = (HotRodEntityDescriptor<E, V>) getEntityDescriptor(modelType);
|
||||
|
||||
if (modelType == UserSessionModel.class) {
|
||||
HotRodMapStorage clientSessionStore = getHotRodStorage(session, AuthenticatedClientSessionModel.class);
|
||||
return new HotRodUserSessionMapStorage(clientSessionStore, connectionProvider.getRemoteCache(entityDescriptor.getCacheName()), StringKeyConverter.StringKey.INSTANCE, entityDescriptor, CLONER);
|
||||
|
||||
}
|
||||
return new HotRodMapStorage<>(connectionProvider.getRemoteCache(entityDescriptor.getCacheName()), StringKeyConverter.StringKey.INSTANCE, entityDescriptor, CLONER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2022 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.map.storage.hotRod.userSession;
|
||||
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.StringKeyConverter;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.chm.MapFieldPredicates;
|
||||
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.chm.UserSessionCascadeRemovalTransaction;
|
||||
import org.keycloak.models.map.storage.hotRod.HotRodMapStorage;
|
||||
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDescriptor;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HotRodUserSessionMapStorage<K> extends HotRodMapStorage<K, HotRodUserSessionEntity, HotRodUserSessionEntityDelegate, UserSessionModel> {
|
||||
|
||||
private final HotRodMapStorage<K, HotRodAuthenticatedClientSessionEntity, HotRodAuthenticatedClientSessionEntityDelegate, AuthenticatedClientSessionModel> hotRodClientSessionStore;
|
||||
|
||||
public HotRodUserSessionMapStorage(HotRodMapStorage<K, HotRodAuthenticatedClientSessionEntity, HotRodAuthenticatedClientSessionEntityDelegate, AuthenticatedClientSessionModel> hotRodClientSessionStore,
|
||||
RemoteCache<K, HotRodUserSessionEntity> remoteCache,
|
||||
StringKeyConverter<K> keyConverter,
|
||||
HotRodEntityDescriptor<HotRodUserSessionEntity, HotRodUserSessionEntityDelegate> storedEntityDescriptor,
|
||||
DeepCloner cloner
|
||||
) {
|
||||
super(remoteCache, keyConverter, storedEntityDescriptor, cloner);
|
||||
this.hotRodClientSessionStore = hotRodClientSessionStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapKeycloakTransaction<HotRodUserSessionEntityDelegate, UserSessionModel> createTransaction(KeycloakSession session) {
|
||||
MapKeycloakTransaction<HotRodUserSessionEntityDelegate, UserSessionModel> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
|
||||
if (sessionTransaction == null) {
|
||||
Map<SearchableModelField<? super UserSessionModel>, MapModelCriteriaBuilder.UpdatePredicatesFunc<K, HotRodUserSessionEntityDelegate, UserSessionModel>> fieldPredicates = MapFieldPredicates.getPredicates((Class<UserSessionModel>) storedEntityDescriptor.getModelTypeClass());
|
||||
sessionTransaction = new UserSessionCascadeRemovalTransaction<>(this, hotRodClientSessionStore.createTransaction(session), keyConverter, cloner, fieldPredicates);
|
||||
session.setAttribute("map-transaction-" + hashCode(), sessionTransaction);
|
||||
}
|
||||
|
||||
return sessionTransaction;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2022 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.map.storage.chm;
|
||||
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.StringKeyConverter;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionEntity;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
public class UserSessionCascadeRemovalTransaction<K, V extends MapUserSessionEntity> extends ConcurrentHashMapKeycloakTransaction<K, V, UserSessionModel> {
|
||||
|
||||
private final MapKeycloakTransaction<? extends MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTr;
|
||||
|
||||
public UserSessionCascadeRemovalTransaction(ConcurrentHashMapCrudOperations<V, UserSessionModel> userSessionConcurrentHashMapStorage,
|
||||
MapKeycloakTransaction<? extends MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTr,
|
||||
StringKeyConverter<K> keyConverter,
|
||||
DeepCloner cloner,
|
||||
Map<SearchableModelField<? super UserSessionModel>,
|
||||
MapModelCriteriaBuilder.UpdatePredicatesFunc<K,
|
||||
V,
|
||||
UserSessionModel>> fieldPredicates) {
|
||||
super(userSessionConcurrentHashMapStorage, keyConverter, cloner, fieldPredicates);
|
||||
this.clientSessionTr = clientSessionTr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long delete(QueryParameters<UserSessionModel> queryParameters) {
|
||||
Set<String> ids = read(queryParameters).map(AbstractEntity::getId).collect(Collectors.toSet());
|
||||
DefaultModelCriteria<AuthenticatedClientSessionModel> csMcb = DefaultModelCriteria.<AuthenticatedClientSessionModel>criteria()
|
||||
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, ModelCriteriaBuilder.Operator.IN, ids);
|
||||
clientSessionTr.delete(withCriteria(csMcb));
|
||||
return super.delete(queryParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(String key) {
|
||||
DefaultModelCriteria<AuthenticatedClientSessionModel> csMcb = DefaultModelCriteria.<AuthenticatedClientSessionModel>criteria()
|
||||
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, ModelCriteriaBuilder.Operator.EQ, key);
|
||||
clientSessionTr.delete(withCriteria(csMcb));
|
||||
return super.delete(key);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,22 +20,10 @@ import org.keycloak.models.map.common.StringKeyConverter;
|
|||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredicatesFunc;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionEntity;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
|
||||
|
||||
/**
|
||||
* User session storage with a naive implementation of referential integrity in client to user session relation, restricted to
|
||||
|
@ -47,40 +35,6 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
|
|||
|
||||
private final ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionStore;
|
||||
|
||||
private class Transaction extends ConcurrentHashMapKeycloakTransaction<K, MapUserSessionEntity, UserSessionModel> {
|
||||
|
||||
private final MapKeycloakTransaction<MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTr;
|
||||
|
||||
public Transaction(MapKeycloakTransaction<MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionTr,
|
||||
StringKeyConverter<K> keyConverter,
|
||||
DeepCloner cloner,
|
||||
Map<SearchableModelField<? super UserSessionModel>,
|
||||
UpdatePredicatesFunc<K,
|
||||
MapUserSessionEntity,
|
||||
UserSessionModel>> fieldPredicates) {
|
||||
super(UserSessionConcurrentHashMapStorage.this, keyConverter, cloner, fieldPredicates);
|
||||
this.clientSessionTr = clientSessionTr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long delete(QueryParameters<UserSessionModel> queryParameters) {
|
||||
Set<String> ids = read(queryParameters).map(AbstractEntity::getId).collect(Collectors.toSet());
|
||||
DefaultModelCriteria<AuthenticatedClientSessionModel> csMcb = DefaultModelCriteria.<AuthenticatedClientSessionModel>criteria()
|
||||
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.IN, ids);
|
||||
clientSessionTr.delete(withCriteria(csMcb));
|
||||
return super.delete(queryParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(String key) {
|
||||
DefaultModelCriteria<AuthenticatedClientSessionModel> csMcb = DefaultModelCriteria.<AuthenticatedClientSessionModel>criteria()
|
||||
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.EQ, key);
|
||||
clientSessionTr.delete(withCriteria(csMcb));
|
||||
return super.delete(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public UserSessionConcurrentHashMapStorage(ConcurrentHashMapStorage<K, MapAuthenticatedClientSessionEntity, AuthenticatedClientSessionModel> clientSessionStore,
|
||||
StringKeyConverter<K> keyConverter, DeepCloner cloner) {
|
||||
|
@ -94,7 +48,7 @@ public class UserSessionConcurrentHashMapStorage<K> extends ConcurrentHashMapSto
|
|||
MapKeycloakTransaction<MapUserSessionEntity, UserSessionModel> sessionTransaction = session.getAttribute("map-transaction-" + hashCode(), MapKeycloakTransaction.class);
|
||||
|
||||
if (sessionTransaction == null) {
|
||||
sessionTransaction = new Transaction(clientSessionStore.createTransaction(session), clientSessionStore.getKeyConverter(), cloner, fieldPredicates);
|
||||
sessionTransaction = new UserSessionCascadeRemovalTransaction<>(this, clientSessionStore.createTransaction(session), clientSessionStore.getKeyConverter(), cloner, fieldPredicates);
|
||||
session.setAttribute("map-transaction-" + hashCode(), sessionTransaction);
|
||||
}
|
||||
return sessionTransaction;
|
||||
|
|
Loading…
Reference in a new issue