Remove EXPIRATION fields and add expired entities filtering to all queries automatically
Closes #12563
This commit is contained in:
parent
22f9b0fee3
commit
0719d3e49b
22 changed files with 76 additions and 97 deletions
|
@ -23,9 +23,12 @@ import org.infinispan.commons.util.CloseableIterator;
|
||||||
import org.infinispan.query.dsl.Query;
|
import org.infinispan.query.dsl.Query;
|
||||||
import org.infinispan.query.dsl.QueryFactory;
|
import org.infinispan.query.dsl.QueryFactory;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.map.common.AbstractEntity;
|
import org.keycloak.models.map.common.AbstractEntity;
|
||||||
import org.keycloak.models.map.common.DeepCloner;
|
import org.keycloak.models.map.common.DeepCloner;
|
||||||
|
import org.keycloak.models.map.common.ExpirableEntity;
|
||||||
|
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||||
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
|
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.HotRodEntityDelegate;
|
||||||
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDescriptor;
|
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDescriptor;
|
||||||
|
@ -48,6 +51,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
|
||||||
import static org.keycloak.models.map.storage.hotRod.common.HotRodUtils.paginateQuery;
|
import static org.keycloak.models.map.storage.hotRod.common.HotRodUtils.paginateQuery;
|
||||||
import static org.keycloak.utils.StreamsUtil.closing;
|
import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
|
|
||||||
|
@ -60,6 +64,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
|
||||||
protected final HotRodEntityDescriptor<E, V> storedEntityDescriptor;
|
protected final HotRodEntityDescriptor<E, V> storedEntityDescriptor;
|
||||||
private final Function<E, V> delegateProducer;
|
private final Function<E, V> delegateProducer;
|
||||||
protected final DeepCloner cloner;
|
protected final DeepCloner cloner;
|
||||||
|
protected boolean isExpirableEntity;
|
||||||
|
|
||||||
public HotRodMapStorage(RemoteCache<K, E> remoteCache, StringKeyConverter<K> keyConverter, HotRodEntityDescriptor<E, V> storedEntityDescriptor, DeepCloner cloner) {
|
public HotRodMapStorage(RemoteCache<K, E> remoteCache, StringKeyConverter<K> keyConverter, HotRodEntityDescriptor<E, V> storedEntityDescriptor, DeepCloner cloner) {
|
||||||
this.remoteCache = remoteCache;
|
this.remoteCache = remoteCache;
|
||||||
|
@ -67,6 +72,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
|
||||||
this.storedEntityDescriptor = storedEntityDescriptor;
|
this.storedEntityDescriptor = storedEntityDescriptor;
|
||||||
this.cloner = cloner;
|
this.cloner = cloner;
|
||||||
this.delegateProducer = storedEntityDescriptor.getHotRodDelegateProvider();
|
this.delegateProducer = storedEntityDescriptor.getHotRodDelegateProvider();
|
||||||
|
this.isExpirableEntity = ExpirableEntity.class.isAssignableFrom(ModelEntityUtil.getEntityType(storedEntityDescriptor.getModelTypeClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -86,7 +92,10 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
|
||||||
public V read(String key) {
|
public V read(String key) {
|
||||||
Objects.requireNonNull(key, "Key must be non-null");
|
Objects.requireNonNull(key, "Key must be non-null");
|
||||||
K k = keyConverter.fromStringSafe(key);
|
K k = keyConverter.fromStringSafe(key);
|
||||||
return delegateProducer.apply(remoteCache.get(k));
|
|
||||||
|
V v = delegateProducer.apply(remoteCache.get(k));
|
||||||
|
if (v == null || v.getHotRodEntity() == null) return null;
|
||||||
|
return isExpirableEntity && isExpired((ExpirableEntity) v, true) ? null : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,12 +118,22 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
|
||||||
return modelFieldName + " " + orderString;
|
return modelFieldName + " " + orderString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String isNotExpiredIckleWhereClause() {
|
||||||
|
return "(" + IckleQueryOperators.C + ".expiration > " + Time.currentTimeMillis() + " OR "
|
||||||
|
+ IckleQueryOperators.C + ".expiration is null)";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<V> read(QueryParameters<M> queryParameters) {
|
public Stream<V> read(QueryParameters<M> queryParameters) {
|
||||||
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
|
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
|
||||||
.flashToModelCriteriaBuilder(createCriteriaBuilder());
|
.flashToModelCriteriaBuilder(createCriteriaBuilder());
|
||||||
String queryString = iqmcb.getIckleQuery();
|
String queryString = iqmcb.getIckleQuery();
|
||||||
|
|
||||||
|
// Temporary solution until https://github.com/keycloak/keycloak/issues/12068 is fixed
|
||||||
|
if (isExpirableEntity) {
|
||||||
|
queryString += (queryString.contains("WHERE") ? " AND " : " WHERE ") + isNotExpiredIckleWhereClause();
|
||||||
|
}
|
||||||
|
|
||||||
if (!queryParameters.getOrderBy().isEmpty()) {
|
if (!queryParameters.getOrderBy().isEmpty()) {
|
||||||
queryString += " ORDER BY " + queryParameters.getOrderBy().stream().map(HotRodMapStorage::toOrderString)
|
queryString += " ORDER BY " + queryParameters.getOrderBy().stream().map(HotRodMapStorage::toOrderString)
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
|
|
|
@ -52,17 +52,6 @@ public class JpaRootAuthenticationSessionModelCriteriaBuilder extends JpaModelCr
|
||||||
throw new CriterionNotSupportedException(modelField, op);
|
throw new CriterionNotSupportedException(modelField, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LT:
|
|
||||||
if (modelField == SearchableFields.EXPIRATION) {
|
|
||||||
validateValue(value, modelField, op, Number.class);
|
|
||||||
|
|
||||||
Number expiration = (Number) value[0];
|
|
||||||
return new JpaRootAuthenticationSessionModelCriteriaBuilder((cb, root) ->
|
|
||||||
cb.lt(root.get(modelField.getName()), expiration)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw new CriterionNotSupportedException(modelField, op);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw new CriterionNotSupportedException(modelField, op);
|
throw new CriterionNotSupportedException(modelField, op);
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,21 +135,14 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAllExpired() {
|
public void removeAllExpired() {
|
||||||
session.realms().getRealmsStream().forEach(this::removeExpired);
|
LOG.tracef("removeAllExpired()%s", getShortStackTrace());
|
||||||
|
LOG.warnf("Clearing expired entities should not be triggered manually. It is responsibility of the store to clear these.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeExpired(RealmModel realm) {
|
public void removeExpired(RealmModel realm) {
|
||||||
Objects.requireNonNull(realm, "The provided realm can't be null!");
|
LOG.tracef("removeExpired(%s)%s", realm, getShortStackTrace());
|
||||||
LOG.debugf("Removing expired sessions");
|
LOG.warnf("Clearing expired entities should not be triggered manually. It is responsibility of the store to clear these.");
|
||||||
|
|
||||||
DefaultModelCriteria<RootAuthenticationSessionModel> mcb = criteria();
|
|
||||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
|
||||||
.compare(SearchableFields.EXPIRATION, Operator.LT, Time.currentTimeMillis());
|
|
||||||
|
|
||||||
long deletedCount = tx.delete(withCriteria(mcb));
|
|
||||||
|
|
||||||
LOG.debugf("Removed %d expired authentication sessions for realm '%s'", deletedCount, realm.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -35,4 +35,8 @@ public class ExpirationUtils {
|
||||||
if (!allowInfiniteValues && expiration == null) return false;
|
if (!allowInfiniteValues && expiration == null) return false;
|
||||||
return expiration != null && expiration <= Time.currentTimeMillis();
|
return expiration != null && expiration <= Time.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isNotExpired(Object entity) {
|
||||||
|
return !isExpired((ExpirableEntity) entity, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,14 +126,6 @@ public class MapAdminEventQuery implements AdminEventQuery {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<AdminEvent> getResultStream() {
|
public Stream<AdminEvent> getResultStream() {
|
||||||
// Add expiration condition to not load expired events
|
|
||||||
mcb = mcb.and(
|
|
||||||
criteria.or(
|
|
||||||
criteria.compare(AdminEvent.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.NOT_EXISTS),
|
|
||||||
criteria.compare(AdminEvent.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT,
|
|
||||||
Time.currentTimeMillis())
|
|
||||||
));
|
|
||||||
|
|
||||||
return resultProducer.apply(QueryParameters.withCriteria(mcb)
|
return resultProducer.apply(QueryParameters.withCriteria(mcb)
|
||||||
.offset(firstResult)
|
.offset(firstResult)
|
||||||
.limit(maxResults)
|
.limit(maxResults)
|
||||||
|
|
|
@ -106,14 +106,6 @@ public class MapAuthEventQuery implements EventQuery {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<Event> getResultStream() {
|
public Stream<Event> getResultStream() {
|
||||||
// Add expiration condition to not load expired events
|
|
||||||
mcb = mcb.and(
|
|
||||||
criteria.or(
|
|
||||||
criteria.compare(Event.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.NOT_EXISTS),
|
|
||||||
criteria.compare(Event.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT,
|
|
||||||
Time.currentTimeMillis())
|
|
||||||
));
|
|
||||||
|
|
||||||
return resultProducer.apply(QueryParameters.withCriteria(mcb)
|
return resultProducer.apply(QueryParameters.withCriteria(mcb)
|
||||||
.offset(firstResult)
|
.offset(firstResult)
|
||||||
.limit(maxResults)
|
.limit(maxResults)
|
||||||
|
|
|
@ -123,14 +123,7 @@ public class MapEventStoreProvider implements EventStoreProvider {
|
||||||
@Override
|
@Override
|
||||||
public void clearExpiredEvents() {
|
public void clearExpiredEvents() {
|
||||||
LOG.tracef("clearExpiredEvents()%s", getShortStackTrace());
|
LOG.tracef("clearExpiredEvents()%s", getShortStackTrace());
|
||||||
|
LOG.warnf("Clearing expired entities should not be triggered manually. It is responsibility of the store to clear these.");
|
||||||
authEventsTX.delete(QueryParameters.withCriteria(DefaultModelCriteria.<Event>criteria()
|
|
||||||
.compare(Event.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.LE,
|
|
||||||
Time.currentTimeMillis())));
|
|
||||||
|
|
||||||
adminEventsTX.delete(QueryParameters.withCriteria(DefaultModelCriteria.<AdminEvent>criteria()
|
|
||||||
.compare(AdminEvent.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.LE,
|
|
||||||
Time.currentTimeMillis())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ADMIN EVENTS **/
|
/** ADMIN EVENTS **/
|
||||||
|
|
|
@ -75,8 +75,7 @@ public class MapSingleUseObjectProvider implements ActionTokenStoreProvider, Sin
|
||||||
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
|
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
|
||||||
mcb = mcb.compare(ActionTokenValueModel.SearchableFields.USER_ID, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getUserId())
|
mcb = mcb.compare(ActionTokenValueModel.SearchableFields.USER_ID, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getUserId())
|
||||||
.compare(ActionTokenValueModel.SearchableFields.ACTION_ID, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getActionId())
|
.compare(ActionTokenValueModel.SearchableFields.ACTION_ID, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getActionId())
|
||||||
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getActionVerificationNonce().toString())
|
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getActionVerificationNonce().toString());
|
||||||
.compare(ActionTokenValueModel.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT, Time.currentTimeMillis());
|
|
||||||
|
|
||||||
ActionTokenValueModel existing = actionTokenStoreTx.read(withCriteria(mcb))
|
ActionTokenValueModel existing = actionTokenStoreTx.read(withCriteria(mcb))
|
||||||
.findFirst().map(this::singleUseEntityToAdapter).orElse(null);
|
.findFirst().map(this::singleUseEntityToAdapter).orElse(null);
|
||||||
|
@ -106,8 +105,7 @@ public class MapSingleUseObjectProvider implements ActionTokenStoreProvider, Sin
|
||||||
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
|
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
|
||||||
mcb = mcb.compare(ActionTokenValueModel.SearchableFields.USER_ID, ModelCriteriaBuilder.Operator.EQ, key.getUserId())
|
mcb = mcb.compare(ActionTokenValueModel.SearchableFields.USER_ID, ModelCriteriaBuilder.Operator.EQ, key.getUserId())
|
||||||
.compare(ActionTokenValueModel.SearchableFields.ACTION_ID, ModelCriteriaBuilder.Operator.EQ, key.getActionId())
|
.compare(ActionTokenValueModel.SearchableFields.ACTION_ID, ModelCriteriaBuilder.Operator.EQ, key.getActionId())
|
||||||
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString())
|
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString());
|
||||||
.compare(ActionTokenValueModel.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT, Time.currentTimeMillis());
|
|
||||||
|
|
||||||
return actionTokenStoreTx.read(withCriteria(mcb))
|
return actionTokenStoreTx.read(withCriteria(mcb))
|
||||||
.findFirst().map(this::singleUseEntityToAdapter).orElse(null);
|
.findFirst().map(this::singleUseEntityToAdapter).orElse(null);
|
||||||
|
@ -124,9 +122,7 @@ public class MapSingleUseObjectProvider implements ActionTokenStoreProvider, Sin
|
||||||
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
|
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
|
||||||
mcb = mcb.compare(ActionTokenValueModel.SearchableFields.USER_ID, ModelCriteriaBuilder.Operator.EQ, key.getUserId())
|
mcb = mcb.compare(ActionTokenValueModel.SearchableFields.USER_ID, ModelCriteriaBuilder.Operator.EQ, key.getUserId())
|
||||||
.compare(ActionTokenValueModel.SearchableFields.ACTION_ID, ModelCriteriaBuilder.Operator.EQ, key.getActionId())
|
.compare(ActionTokenValueModel.SearchableFields.ACTION_ID, ModelCriteriaBuilder.Operator.EQ, key.getActionId())
|
||||||
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString())
|
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString());
|
||||||
.compare(ActionTokenValueModel.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT, Time.currentTimeMillis());
|
|
||||||
|
|
||||||
MapSingleUseObjectEntity mapSingleUseObjectEntity = actionTokenStoreTx.read(withCriteria(mcb)).findFirst().orElse(null);
|
MapSingleUseObjectEntity mapSingleUseObjectEntity = actionTokenStoreTx.read(withCriteria(mcb)).findFirst().orElse(null);
|
||||||
if (mapSingleUseObjectEntity != null) {
|
if (mapSingleUseObjectEntity != null) {
|
||||||
ActionTokenValueModel actionToken = singleUseEntityToAdapter(mapSingleUseObjectEntity);
|
ActionTokenValueModel actionToken = singleUseEntityToAdapter(mapSingleUseObjectEntity);
|
||||||
|
|
|
@ -43,6 +43,9 @@ public interface MapKeycloakTransaction<V extends AbstractEntity, M> extends Key
|
||||||
* in current transaction. Updates to the returned instance would be visible in the current transaction
|
* in current transaction. Updates to the returned instance would be visible in the current transaction
|
||||||
* and will propagate into the underlying store upon commit.
|
* and will propagate into the underlying store upon commit.
|
||||||
*
|
*
|
||||||
|
* If {@code V} implements {@link org.keycloak.models.map.common.ExpirableEntity} this method should not return
|
||||||
|
* entities that are expired. See {@link org.keycloak.models.map.common.ExpirableEntity} JavaDoc for more details.
|
||||||
|
*
|
||||||
* @param key identifier of a value
|
* @param key identifier of a value
|
||||||
* @return a value associated with the given {@code key}
|
* @return a value associated with the given {@code key}
|
||||||
*/
|
*/
|
||||||
|
@ -57,6 +60,9 @@ public interface MapKeycloakTransaction<V extends AbstractEntity, M> extends Key
|
||||||
* Updates to the returned instances of {@code V} would be visible in the current transaction
|
* Updates to the returned instances of {@code V} would be visible in the current transaction
|
||||||
* and will propagate into the underlying store upon commit.
|
* and will propagate into the underlying store upon commit.
|
||||||
*
|
*
|
||||||
|
* If {@code V} implements {@link org.keycloak.models.map.common.ExpirableEntity} this method should not return
|
||||||
|
* entities that are expired. See {@link org.keycloak.models.map.common.ExpirableEntity} JavaDoc for more details.
|
||||||
|
*
|
||||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||||
* @return values that fulfill the given criteria, that are updated based on changes in the current transaction
|
* @return values that fulfill the given criteria, that are updated based on changes in the current transaction
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,6 +23,9 @@ public interface ConcurrentHashMapCrudOperations<V extends AbstractEntity & Upda
|
||||||
/**
|
/**
|
||||||
* Returns object with the given {@code key} from the storage or {@code null} if object does not exist.
|
* Returns object with the given {@code key} from the storage or {@code null} if object does not exist.
|
||||||
* <br>
|
* <br>
|
||||||
|
* If {@code V} implements {@link org.keycloak.models.map.common.ExpirableEntity} this method should not return
|
||||||
|
* entities that are expired. See {@link org.keycloak.models.map.common.ExpirableEntity} JavaDoc for more details.
|
||||||
|
*
|
||||||
* TODO: Consider returning {@code Optional<V>} instead.
|
* TODO: Consider returning {@code Optional<V>} instead.
|
||||||
* @param key Key of the object. Must not be {@code null}.
|
* @param key Key of the object. Must not be {@code null}.
|
||||||
* @return See description
|
* @return See description
|
||||||
|
@ -57,6 +60,9 @@ public interface ConcurrentHashMapCrudOperations<V extends AbstractEntity & Upda
|
||||||
* Returns stream of objects satisfying given {@code criteria} from the storage.
|
* Returns stream of objects satisfying given {@code criteria} from the storage.
|
||||||
* The criteria are specified in the given criteria builder based on model properties.
|
* The criteria are specified in the given criteria builder based on model properties.
|
||||||
*
|
*
|
||||||
|
* If {@code V} implements {@link org.keycloak.models.map.common.ExpirableEntity} this method should not return
|
||||||
|
* entities that are expired. See {@link org.keycloak.models.map.common.ExpirableEntity} JavaDoc for more details.
|
||||||
|
*
|
||||||
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
* @param queryParameters parameters for the query like firstResult, maxResult, requested ordering, etc.
|
||||||
* @return Stream of objects. Never returns {@code null}.
|
* @return Stream of objects. Never returns {@code null}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.models.map.storage.chm;
|
package org.keycloak.models.map.storage.chm;
|
||||||
|
|
||||||
|
import org.keycloak.models.map.common.ExpirableEntity;
|
||||||
|
import org.keycloak.models.map.common.ExpirationUtils;
|
||||||
import org.keycloak.models.map.common.StringKeyConverter;
|
import org.keycloak.models.map.common.StringKeyConverter;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
||||||
|
@ -23,6 +25,7 @@ import org.keycloak.models.map.common.AbstractEntity;
|
||||||
import org.keycloak.models.map.common.DeepCloner;
|
import org.keycloak.models.map.common.DeepCloner;
|
||||||
import org.keycloak.models.map.common.UpdatableEntity;
|
import org.keycloak.models.map.common.UpdatableEntity;
|
||||||
import org.keycloak.models.map.storage.MapStorage;
|
import org.keycloak.models.map.storage.MapStorage;
|
||||||
|
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||||
import org.keycloak.models.map.storage.QueryParameters;
|
import org.keycloak.models.map.storage.QueryParameters;
|
||||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||||
import org.keycloak.storage.SearchableModelField;
|
import org.keycloak.storage.SearchableModelField;
|
||||||
|
@ -38,6 +41,7 @@ import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredica
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
|
||||||
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
import static org.keycloak.utils.StreamsUtil.paginatedStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,12 +60,14 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity & UpdatableEnt
|
||||||
protected final Map<SearchableModelField<? super M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates;
|
protected final Map<SearchableModelField<? super M>, UpdatePredicatesFunc<K, V, M>> fieldPredicates;
|
||||||
protected final StringKeyConverter<K> keyConverter;
|
protected final StringKeyConverter<K> keyConverter;
|
||||||
protected final DeepCloner cloner;
|
protected final DeepCloner cloner;
|
||||||
|
private final boolean isExpirableEntity;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public ConcurrentHashMapStorage(Class<M> modelClass, StringKeyConverter<K> keyConverter, DeepCloner cloner) {
|
public ConcurrentHashMapStorage(Class<M> modelClass, StringKeyConverter<K> keyConverter, DeepCloner cloner) {
|
||||||
this.fieldPredicates = MapFieldPredicates.getPredicates(modelClass);
|
this.fieldPredicates = MapFieldPredicates.getPredicates(modelClass);
|
||||||
this.keyConverter = keyConverter;
|
this.keyConverter = keyConverter;
|
||||||
this.cloner = cloner;
|
this.cloner = cloner;
|
||||||
|
this.isExpirableEntity = ExpirableEntity.class.isAssignableFrom(ModelEntityUtil.getEntityType(modelClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,7 +85,10 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity & UpdatableEnt
|
||||||
public V read(String key) {
|
public V read(String key) {
|
||||||
Objects.requireNonNull(key, "Key must be non-null");
|
Objects.requireNonNull(key, "Key must be non-null");
|
||||||
K k = keyConverter.fromStringSafe(key);
|
K k = keyConverter.fromStringSafe(key);
|
||||||
return store.get(k);
|
|
||||||
|
V v = store.get(k);
|
||||||
|
if (v == null) return null;
|
||||||
|
return isExpirableEntity && isExpired((ExpirableEntity) v, true) ? null : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -157,7 +166,14 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity & UpdatableEnt
|
||||||
Stream<Entry<K, V>> stream = store.entrySet().stream();
|
Stream<Entry<K, V>> stream = store.entrySet().stream();
|
||||||
|
|
||||||
Predicate<? super K> keyFilter = mcb.getKeyFilter();
|
Predicate<? super K> keyFilter = mcb.getKeyFilter();
|
||||||
Predicate<? super V> entityFilter = mcb.getEntityFilter();
|
Predicate<? super V> entityFilter;
|
||||||
|
|
||||||
|
if (isExpirableEntity) {
|
||||||
|
entityFilter = mcb.getEntityFilter().and(ExpirationUtils::isNotExpired);
|
||||||
|
} else {
|
||||||
|
entityFilter = mcb.getEntityFilter();
|
||||||
|
}
|
||||||
|
|
||||||
Stream<V> valueStream = stream.filter(me -> keyFilter.test(me.getKey()) && entityFilter.test(me.getValue()))
|
Stream<V> valueStream = stream.filter(me -> keyFilter.test(me.getKey()) && entityFilter.test(me.getValue()))
|
||||||
.map(Map.Entry::getValue);
|
.map(Map.Entry::getValue);
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,6 @@ public class MapFieldPredicates {
|
||||||
put(USER_PREDICATES, UserModel.SearchableFields.SERVICE_ACCOUNT_CLIENT, MapUserEntity::getServiceAccountClientLink);
|
put(USER_PREDICATES, UserModel.SearchableFields.SERVICE_ACCOUNT_CLIENT, MapUserEntity::getServiceAccountClientLink);
|
||||||
|
|
||||||
put(AUTHENTICATION_SESSION_PREDICATES, RootAuthenticationSessionModel.SearchableFields.REALM_ID, MapRootAuthenticationSessionEntity::getRealmId);
|
put(AUTHENTICATION_SESSION_PREDICATES, RootAuthenticationSessionModel.SearchableFields.REALM_ID, MapRootAuthenticationSessionEntity::getRealmId);
|
||||||
put(AUTHENTICATION_SESSION_PREDICATES, RootAuthenticationSessionModel.SearchableFields.EXPIRATION, MapRootAuthenticationSessionEntity::getExpiration);
|
|
||||||
|
|
||||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.ID, predicateForKeyField(MapResourceServerEntity::getId));
|
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.ID, predicateForKeyField(MapResourceServerEntity::getId));
|
||||||
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.CLIENT_ID, MapResourceServerEntity::getClientId);
|
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.CLIENT_ID, MapResourceServerEntity::getClientId);
|
||||||
|
@ -201,14 +200,12 @@ public class MapFieldPredicates {
|
||||||
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.BROKER_USER_ID, MapUserSessionEntity::getBrokerUserId);
|
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.BROKER_USER_ID, MapUserSessionEntity::getBrokerUserId);
|
||||||
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.IS_OFFLINE, MapUserSessionEntity::isOffline);
|
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.IS_OFFLINE, MapUserSessionEntity::isOffline);
|
||||||
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.LAST_SESSION_REFRESH, MapUserSessionEntity::getLastSessionRefresh);
|
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.LAST_SESSION_REFRESH, MapUserSessionEntity::getLastSessionRefresh);
|
||||||
put(USER_SESSION_PREDICATES, UserSessionModel.SearchableFields.EXPIRATION, MapUserSessionEntity::getExpiration);
|
|
||||||
|
|
||||||
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.REALM_ID, MapAuthenticatedClientSessionEntity::getRealmId);
|
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.REALM_ID, MapAuthenticatedClientSessionEntity::getRealmId);
|
||||||
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, MapAuthenticatedClientSessionEntity::getClientId);
|
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, MapAuthenticatedClientSessionEntity::getClientId);
|
||||||
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, MapAuthenticatedClientSessionEntity::getUserSessionId);
|
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, MapAuthenticatedClientSessionEntity::getUserSessionId);
|
||||||
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, MapAuthenticatedClientSessionEntity::isOffline);
|
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, MapAuthenticatedClientSessionEntity::isOffline);
|
||||||
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.TIMESTAMP, MapAuthenticatedClientSessionEntity::getTimestamp);
|
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.TIMESTAMP, MapAuthenticatedClientSessionEntity::getTimestamp);
|
||||||
put(CLIENT_SESSION_PREDICATES, AuthenticatedClientSessionModel.SearchableFields.EXPIRATION, MapAuthenticatedClientSessionEntity::getExpiration);
|
|
||||||
|
|
||||||
put(USER_LOGIN_FAILURE_PREDICATES, UserLoginFailureModel.SearchableFields.REALM_ID, MapUserLoginFailureEntity::getRealmId);
|
put(USER_LOGIN_FAILURE_PREDICATES, UserLoginFailureModel.SearchableFields.REALM_ID, MapUserLoginFailureEntity::getRealmId);
|
||||||
put(USER_LOGIN_FAILURE_PREDICATES, UserLoginFailureModel.SearchableFields.USER_ID, MapUserLoginFailureEntity::getUserId);
|
put(USER_LOGIN_FAILURE_PREDICATES, UserLoginFailureModel.SearchableFields.USER_ID, MapUserLoginFailureEntity::getUserId);
|
||||||
|
@ -217,13 +214,11 @@ public class MapFieldPredicates {
|
||||||
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.CLIENT_ID, MapAuthEventEntity::getClientId);
|
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.CLIENT_ID, MapAuthEventEntity::getClientId);
|
||||||
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.USER_ID, MapAuthEventEntity::getUserId);
|
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.USER_ID, MapAuthEventEntity::getUserId);
|
||||||
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.TIMESTAMP, MapAuthEventEntity::getTimestamp);
|
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.TIMESTAMP, MapAuthEventEntity::getTimestamp);
|
||||||
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.EXPIRATION, MapAuthEventEntity::getExpiration);
|
|
||||||
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.IP_ADDRESS, MapAuthEventEntity::getIpAddress);
|
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.IP_ADDRESS, MapAuthEventEntity::getIpAddress);
|
||||||
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.EVENT_TYPE, MapAuthEventEntity::getType);
|
put(AUTH_EVENTS_PREDICATES, Event.SearchableFields.EVENT_TYPE, MapAuthEventEntity::getType);
|
||||||
|
|
||||||
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.REALM_ID, MapAdminEventEntity::getRealmId);
|
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.REALM_ID, MapAdminEventEntity::getRealmId);
|
||||||
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.TIMESTAMP, MapAdminEventEntity::getTimestamp);
|
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.TIMESTAMP, MapAdminEventEntity::getTimestamp);
|
||||||
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.EXPIRATION, MapAdminEventEntity::getExpiration);
|
|
||||||
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.AUTH_REALM_ID, MapAdminEventEntity::getAuthRealmId);
|
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.AUTH_REALM_ID, MapAdminEventEntity::getAuthRealmId);
|
||||||
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.AUTH_CLIENT_ID, MapAdminEventEntity::getAuthClientId);
|
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.AUTH_CLIENT_ID, MapAdminEventEntity::getAuthClientId);
|
||||||
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.AUTH_USER_ID, MapAdminEventEntity::getAuthUserId);
|
put(ADMIN_EVENTS_PREDICATES, AdminEvent.SearchableFields.AUTH_USER_ID, MapAdminEventEntity::getAuthUserId);
|
||||||
|
@ -235,7 +230,6 @@ public class MapFieldPredicates {
|
||||||
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.USER_ID, MapSingleUseObjectEntity::getUserId);
|
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.USER_ID, MapSingleUseObjectEntity::getUserId);
|
||||||
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.ACTION_ID, MapSingleUseObjectEntity::getActionId);
|
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.ACTION_ID, MapSingleUseObjectEntity::getActionId);
|
||||||
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, MapSingleUseObjectEntity::getActionVerificationNonce);
|
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, MapSingleUseObjectEntity::getActionVerificationNonce);
|
||||||
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.EXPIRATION, MapSingleUseObjectEntity::getExpiration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -29,8 +29,6 @@ import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||||
*/
|
*/
|
||||||
|
@ -74,8 +72,7 @@ public class SingleUseObjectConcurrentHashMapStorage<K, V extends AbstractEntity
|
||||||
SingleUseObjectModelCriteriaBuilder mcb = criteria.flashToModelCriteriaBuilder(createSingleUseObjectCriteriaBuilder());
|
SingleUseObjectModelCriteriaBuilder mcb = criteria.flashToModelCriteriaBuilder(createSingleUseObjectCriteriaBuilder());
|
||||||
if (mcb.isValid()) {
|
if (mcb.isValid()) {
|
||||||
MapSingleUseObjectEntity value = read(mcb.getKey());
|
MapSingleUseObjectEntity value = read(mcb.getKey());
|
||||||
if (value == null || (mcb.checkExpiration() && isExpired(value, false))) return Stream.empty();
|
return value != null ? Stream.of(value) : Stream.empty();
|
||||||
return Stream.of(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.read(queryParameters);
|
return super.read(queryParameters);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package org.keycloak.models.map.storage.chm;
|
package org.keycloak.models.map.storage.chm;
|
||||||
|
|
||||||
import org.keycloak.models.ActionTokenValueModel;
|
|
||||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||||
import org.keycloak.storage.SearchableModelField;
|
import org.keycloak.storage.SearchableModelField;
|
||||||
|
|
||||||
|
@ -32,16 +31,13 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
|
||||||
|
|
||||||
private String actionVerificationNonce;
|
private String actionVerificationNonce;
|
||||||
|
|
||||||
private Boolean checkExpiration;
|
|
||||||
|
|
||||||
public SingleUseObjectModelCriteriaBuilder() {
|
public SingleUseObjectModelCriteriaBuilder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SingleUseObjectModelCriteriaBuilder(String userId, String actionId, String actionVerificationNonce, Boolean checkExpiration) {
|
public SingleUseObjectModelCriteriaBuilder(String userId, String actionId, String actionVerificationNonce) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.actionId = actionId;
|
this.actionId = actionId;
|
||||||
this.actionVerificationNonce = actionVerificationNonce;
|
this.actionVerificationNonce = actionVerificationNonce;
|
||||||
this.checkExpiration = checkExpiration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,11 +48,8 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
|
||||||
actionId = value[0].toString();
|
actionId = value[0].toString();
|
||||||
} else if (modelField == org.keycloak.models.ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE) {
|
} else if (modelField == org.keycloak.models.ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE) {
|
||||||
actionVerificationNonce = value[0].toString();
|
actionVerificationNonce = value[0].toString();
|
||||||
} else if (modelField == ActionTokenValueModel.SearchableFields.EXPIRATION && op == Operator.GT) {
|
|
||||||
checkExpiration = true;
|
|
||||||
}
|
}
|
||||||
|
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce);
|
||||||
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce, checkExpiration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,7 +57,6 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
|
||||||
String userId = null;
|
String userId = null;
|
||||||
String actionId = null;
|
String actionId = null;
|
||||||
String actionVerificationNonce = null;
|
String actionVerificationNonce = null;
|
||||||
Boolean checkExpiration = null;
|
|
||||||
|
|
||||||
for (ModelCriteriaBuilder builder: builders) {
|
for (ModelCriteriaBuilder builder: builders) {
|
||||||
SingleUseObjectModelCriteriaBuilder suoMcb = (SingleUseObjectModelCriteriaBuilder) builder;
|
SingleUseObjectModelCriteriaBuilder suoMcb = (SingleUseObjectModelCriteriaBuilder) builder;
|
||||||
|
@ -77,11 +69,8 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
|
||||||
if (suoMcb.actionVerificationNonce != null) {
|
if (suoMcb.actionVerificationNonce != null) {
|
||||||
actionVerificationNonce = suoMcb.actionVerificationNonce;
|
actionVerificationNonce = suoMcb.actionVerificationNonce;
|
||||||
}
|
}
|
||||||
if (suoMcb.checkExpiration != null) {
|
|
||||||
checkExpiration = suoMcb.checkExpiration;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce, checkExpiration);
|
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,10 +87,6 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
|
||||||
return userId != null && actionId != null && actionVerificationNonce != null;
|
return userId != null && actionId != null && actionVerificationNonce != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkExpiration() {
|
|
||||||
return checkExpiration != null && checkExpiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return userId + ":" + actionId + ":" + actionVerificationNonce;
|
return userId + ":" + actionId + ":" + actionVerificationNonce;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,8 +207,7 @@ public class MapUserSessionProvider implements UserSessionProvider {
|
||||||
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.EQ, userSession.getId())
|
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.EQ, userSession.getId())
|
||||||
.compare(AuthenticatedClientSessionModel.SearchableFields.REALM_ID, Operator.EQ, userSession.getRealm().getId())
|
.compare(AuthenticatedClientSessionModel.SearchableFields.REALM_ID, Operator.EQ, userSession.getRealm().getId())
|
||||||
.compare(AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, Operator.EQ, client.getId())
|
.compare(AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, Operator.EQ, client.getId())
|
||||||
.compare(AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline)
|
.compare(AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline);
|
||||||
.compare(AuthenticatedClientSessionModel.SearchableFields.EXPIRATION, Operator.GT, Time.currentTimeMillis());
|
|
||||||
|
|
||||||
return clientSessionTx.read(withCriteria(mcb))
|
return clientSessionTx.read(withCriteria(mcb))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
|
@ -606,9 +605,7 @@ public class MapUserSessionProvider implements UserSessionProvider {
|
||||||
// first get a user entity by ID
|
// first get a user entity by ID
|
||||||
DefaultModelCriteria<UserSessionModel> mcb = criteria();
|
DefaultModelCriteria<UserSessionModel> mcb = criteria();
|
||||||
mcb = mcb.compare(UserSessionModel.SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
mcb = mcb.compare(UserSessionModel.SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||||
.compare(UserSessionModel.SearchableFields.ID, Operator.EQ, userSessionId)
|
.compare(UserSessionModel.SearchableFields.ID, Operator.EQ, userSessionId);
|
||||||
.compare(UserSessionModel.SearchableFields.EXPIRATION, Operator.GT, Time.currentTimeMillis())
|
|
||||||
;
|
|
||||||
|
|
||||||
// check if it's an offline user session
|
// check if it's an offline user session
|
||||||
MapUserSessionEntity userSessionEntity = userSessionTx.read(withCriteria(mcb)).findFirst().orElse(null);
|
MapUserSessionEntity userSessionEntity = userSessionTx.read(withCriteria(mcb)).findFirst().orElse(null);
|
||||||
|
@ -637,8 +634,7 @@ public class MapUserSessionProvider implements UserSessionProvider {
|
||||||
private DefaultModelCriteria<UserSessionModel> realmAndOfflineCriteriaBuilder(RealmModel realm, boolean offline) {
|
private DefaultModelCriteria<UserSessionModel> realmAndOfflineCriteriaBuilder(RealmModel realm, boolean offline) {
|
||||||
return DefaultModelCriteria.<UserSessionModel>criteria()
|
return DefaultModelCriteria.<UserSessionModel>criteria()
|
||||||
.compare(UserSessionModel.SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
.compare(UserSessionModel.SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||||
.compare(UserSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline)
|
.compare(UserSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline);
|
||||||
.compare(UserSessionModel.SearchableFields.EXPIRATION, Operator.GT, Time.currentTimeMillis());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MapUserSessionEntity getUserSessionById(String id) {
|
private MapUserSessionEntity getUserSessionById(String id) {
|
||||||
|
|
|
@ -33,7 +33,6 @@ public class Event {
|
||||||
public static final SearchableModelField<Event> CLIENT_ID = new SearchableModelField<>("clientId", String.class);
|
public static final SearchableModelField<Event> CLIENT_ID = new SearchableModelField<>("clientId", String.class);
|
||||||
public static final SearchableModelField<Event> USER_ID = new SearchableModelField<>("userId", String.class);
|
public static final SearchableModelField<Event> USER_ID = new SearchableModelField<>("userId", String.class);
|
||||||
public static final SearchableModelField<Event> TIMESTAMP = new SearchableModelField<>("timestamp", Long.class);
|
public static final SearchableModelField<Event> TIMESTAMP = new SearchableModelField<>("timestamp", Long.class);
|
||||||
public static final SearchableModelField<Event> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
|
|
||||||
public static final SearchableModelField<Event> IP_ADDRESS = new SearchableModelField<>("ipAddress", String.class);
|
public static final SearchableModelField<Event> IP_ADDRESS = new SearchableModelField<>("ipAddress", String.class);
|
||||||
public static final SearchableModelField<Event> EVENT_TYPE = new SearchableModelField<>("eventType", EventType.class);
|
public static final SearchableModelField<Event> EVENT_TYPE = new SearchableModelField<>("eventType", EventType.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ public class AdminEvent {
|
||||||
public static final SearchableModelField<AdminEvent> ID = new SearchableModelField<>("id", String.class);
|
public static final SearchableModelField<AdminEvent> ID = new SearchableModelField<>("id", String.class);
|
||||||
public static final SearchableModelField<AdminEvent> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
public static final SearchableModelField<AdminEvent> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
||||||
public static final SearchableModelField<AdminEvent> TIMESTAMP = new SearchableModelField<>("timestamp", Long.class);
|
public static final SearchableModelField<AdminEvent> TIMESTAMP = new SearchableModelField<>("timestamp", Long.class);
|
||||||
public static final SearchableModelField<AdminEvent> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
|
|
||||||
public static final SearchableModelField<AdminEvent> AUTH_REALM_ID = new SearchableModelField<>("authRealmId", String.class);
|
public static final SearchableModelField<AdminEvent> AUTH_REALM_ID = new SearchableModelField<>("authRealmId", String.class);
|
||||||
public static final SearchableModelField<AdminEvent> AUTH_CLIENT_ID = new SearchableModelField<>("authClientId", String.class);
|
public static final SearchableModelField<AdminEvent> AUTH_CLIENT_ID = new SearchableModelField<>("authClientId", String.class);
|
||||||
public static final SearchableModelField<AdminEvent> AUTH_USER_ID = new SearchableModelField<>("authUserId", String.class);
|
public static final SearchableModelField<AdminEvent> AUTH_USER_ID = new SearchableModelField<>("authUserId", String.class);
|
||||||
|
|
|
@ -31,7 +31,6 @@ public interface ActionTokenValueModel {
|
||||||
public static final SearchableModelField<ActionTokenValueModel> USER_ID = new SearchableModelField<>("userId", String.class);
|
public static final SearchableModelField<ActionTokenValueModel> USER_ID = new SearchableModelField<>("userId", String.class);
|
||||||
public static final SearchableModelField<ActionTokenValueModel> ACTION_ID = new SearchableModelField<>("actionId", String.class);
|
public static final SearchableModelField<ActionTokenValueModel> ACTION_ID = new SearchableModelField<>("actionId", String.class);
|
||||||
public static final SearchableModelField<ActionTokenValueModel> ACTION_VERIFICATION_NONCE = new SearchableModelField<>("actionVerificationNonce", String.class);
|
public static final SearchableModelField<ActionTokenValueModel> ACTION_VERIFICATION_NONCE = new SearchableModelField<>("actionVerificationNonce", String.class);
|
||||||
public static final SearchableModelField<ActionTokenValueModel> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -35,7 +35,6 @@ public interface AuthenticatedClientSessionModel extends CommonClientSessionMode
|
||||||
public static final SearchableModelField<AuthenticatedClientSessionModel> USER_SESSION_ID = new SearchableModelField<>("userSessionId", String.class);
|
public static final SearchableModelField<AuthenticatedClientSessionModel> USER_SESSION_ID = new SearchableModelField<>("userSessionId", String.class);
|
||||||
public static final SearchableModelField<AuthenticatedClientSessionModel> IS_OFFLINE = new SearchableModelField<>("isOffline", Boolean.class);
|
public static final SearchableModelField<AuthenticatedClientSessionModel> IS_OFFLINE = new SearchableModelField<>("isOffline", Boolean.class);
|
||||||
public static final SearchableModelField<AuthenticatedClientSessionModel> TIMESTAMP = new SearchableModelField<>("timestamp", Long.class);
|
public static final SearchableModelField<AuthenticatedClientSessionModel> TIMESTAMP = new SearchableModelField<>("timestamp", Long.class);
|
||||||
public static final SearchableModelField<AuthenticatedClientSessionModel> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String STARTED_AT_NOTE = "startedAt";
|
String STARTED_AT_NOTE = "startedAt";
|
||||||
|
|
|
@ -44,7 +44,6 @@ public interface UserSessionModel {
|
||||||
public static final SearchableModelField<UserSessionModel> BROKER_USER_ID = new SearchableModelField<>("brokerUserId", String.class);
|
public static final SearchableModelField<UserSessionModel> BROKER_USER_ID = new SearchableModelField<>("brokerUserId", String.class);
|
||||||
public static final SearchableModelField<UserSessionModel> IS_OFFLINE = new SearchableModelField<>("isOffline", Boolean.class);
|
public static final SearchableModelField<UserSessionModel> IS_OFFLINE = new SearchableModelField<>("isOffline", Boolean.class);
|
||||||
public static final SearchableModelField<UserSessionModel> LAST_SESSION_REFRESH = new SearchableModelField<>("lastSessionRefresh", Long.class);
|
public static final SearchableModelField<UserSessionModel> LAST_SESSION_REFRESH = new SearchableModelField<>("lastSessionRefresh", Long.class);
|
||||||
public static final SearchableModelField<UserSessionModel> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -74,12 +74,19 @@ public interface AuthenticationSessionProvider extends Provider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove expired authentication sessions in all the realms
|
* Remove expired authentication sessions in all the realms
|
||||||
|
*
|
||||||
|
* @deprecated manual removal of expired entities should not be used anymore. It is responsibility of the store
|
||||||
|
* implementation to handle expirable entities
|
||||||
*/
|
*/
|
||||||
void removeAllExpired();
|
void removeAllExpired();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all expired root authentication sessions for the given realm.
|
* Removes all expired root authentication sessions for the given realm.
|
||||||
* @param realm {@code RealmModel} Can't be {@code null}.
|
* @param realm {@code RealmModel} Can't be {@code null}.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @deprecated manual removal of expired entities should not be used anymore. It is responsibility of the store
|
||||||
|
* implementation to handle expirable entities
|
||||||
*/
|
*/
|
||||||
void removeExpired(RealmModel realm);
|
void removeExpired(RealmModel realm);
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ public interface RootAuthenticationSessionModel {
|
||||||
public static class SearchableFields {
|
public static class SearchableFields {
|
||||||
public static final SearchableModelField<RootAuthenticationSessionModel> ID = new SearchableModelField<>("id", String.class);
|
public static final SearchableModelField<RootAuthenticationSessionModel> ID = new SearchableModelField<>("id", String.class);
|
||||||
public static final SearchableModelField<RootAuthenticationSessionModel> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
public static final SearchableModelField<RootAuthenticationSessionModel> REALM_ID = new SearchableModelField<>("realmId", String.class);
|
||||||
public static final SearchableModelField<RootAuthenticationSessionModel> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue