Remove EXPIRATION fields and add expired entities filtering to all queries automatically

Closes #12563
This commit is contained in:
Michal Hajas 2022-06-20 11:48:57 +02:00 committed by Hynek Mlnařík
parent 22f9b0fee3
commit 0719d3e49b
22 changed files with 76 additions and 97 deletions

View file

@ -23,9 +23,12 @@ import org.infinispan.commons.util.CloseableIterator;
import org.infinispan.query.dsl.Query;
import org.infinispan.query.dsl.QueryFactory;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Time;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.map.common.AbstractEntity;
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.HotRodEntityDelegate;
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.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.utils.StreamsUtil.closing;
@ -60,6 +64,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
protected final HotRodEntityDescriptor<E, V> storedEntityDescriptor;
private final Function<E, V> delegateProducer;
protected final DeepCloner cloner;
protected boolean isExpirableEntity;
public HotRodMapStorage(RemoteCache<K, E> remoteCache, StringKeyConverter<K> keyConverter, HotRodEntityDescriptor<E, V> storedEntityDescriptor, DeepCloner cloner) {
this.remoteCache = remoteCache;
@ -67,6 +72,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
this.storedEntityDescriptor = storedEntityDescriptor;
this.cloner = cloner;
this.delegateProducer = storedEntityDescriptor.getHotRodDelegateProvider();
this.isExpirableEntity = ExpirableEntity.class.isAssignableFrom(ModelEntityUtil.getEntityType(storedEntityDescriptor.getModelTypeClass()));
}
@Override
@ -86,7 +92,10 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
public V read(String key) {
Objects.requireNonNull(key, "Key must be non-null");
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
@ -109,12 +118,22 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
return modelFieldName + " " + orderString;
}
private static String isNotExpiredIckleWhereClause() {
return "(" + IckleQueryOperators.C + ".expiration > " + Time.currentTimeMillis() + " OR "
+ IckleQueryOperators.C + ".expiration is null)";
}
@Override
public Stream<V> read(QueryParameters<M> queryParameters) {
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
.flashToModelCriteriaBuilder(createCriteriaBuilder());
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()) {
queryString += " ORDER BY " + queryParameters.getOrderBy().stream().map(HotRodMapStorage::toOrderString)
.collect(Collectors.joining(", "));

View file

@ -52,17 +52,6 @@ public class JpaRootAuthenticationSessionModelCriteriaBuilder extends JpaModelCr
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:
throw new CriterionNotSupportedException(modelField, op);
}

View file

@ -135,21 +135,14 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi
@Override
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
public void removeExpired(RealmModel realm) {
Objects.requireNonNull(realm, "The provided realm can't be null!");
LOG.debugf("Removing expired sessions");
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());
LOG.tracef("removeExpired(%s)%s", realm, getShortStackTrace());
LOG.warnf("Clearing expired entities should not be triggered manually. It is responsibility of the store to clear these.");
}
@Override

View file

@ -35,4 +35,8 @@ public class ExpirationUtils {
if (!allowInfiniteValues && expiration == null) return false;
return expiration != null && expiration <= Time.currentTimeMillis();
}
public static boolean isNotExpired(Object entity) {
return !isExpired((ExpirableEntity) entity, true);
}
}

View file

@ -126,14 +126,6 @@ public class MapAdminEventQuery implements AdminEventQuery {
@Override
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)
.offset(firstResult)
.limit(maxResults)

View file

@ -106,14 +106,6 @@ public class MapAuthEventQuery implements EventQuery {
@Override
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)
.offset(firstResult)
.limit(maxResults)

View file

@ -123,14 +123,7 @@ public class MapEventStoreProvider implements EventStoreProvider {
@Override
public void clearExpiredEvents() {
LOG.tracef("clearExpiredEvents()%s", getShortStackTrace());
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())));
LOG.warnf("Clearing expired entities should not be triggered manually. It is responsibility of the store to clear these.");
}
/** ADMIN EVENTS **/

View file

@ -75,8 +75,7 @@ public class MapSingleUseObjectProvider implements ActionTokenStoreProvider, Sin
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
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_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getActionVerificationNonce().toString())
.compare(ActionTokenValueModel.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT, Time.currentTimeMillis());
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, actionTokenKey.getActionVerificationNonce().toString());
ActionTokenValueModel existing = actionTokenStoreTx.read(withCriteria(mcb))
.findFirst().map(this::singleUseEntityToAdapter).orElse(null);
@ -106,8 +105,7 @@ public class MapSingleUseObjectProvider implements ActionTokenStoreProvider, Sin
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
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_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString())
.compare(ActionTokenValueModel.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT, Time.currentTimeMillis());
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString());
return actionTokenStoreTx.read(withCriteria(mcb))
.findFirst().map(this::singleUseEntityToAdapter).orElse(null);
@ -124,9 +122,7 @@ public class MapSingleUseObjectProvider implements ActionTokenStoreProvider, Sin
DefaultModelCriteria<ActionTokenValueModel> mcb = criteria();
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_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString())
.compare(ActionTokenValueModel.SearchableFields.EXPIRATION, ModelCriteriaBuilder.Operator.GT, Time.currentTimeMillis());
.compare(ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, ModelCriteriaBuilder.Operator.EQ, key.getActionVerificationNonce().toString());
MapSingleUseObjectEntity mapSingleUseObjectEntity = actionTokenStoreTx.read(withCriteria(mcb)).findFirst().orElse(null);
if (mapSingleUseObjectEntity != null) {
ActionTokenValueModel actionToken = singleUseEntityToAdapter(mapSingleUseObjectEntity);

View file

@ -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
* 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
* @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
* 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.
* @return values that fulfill the given criteria, that are updated based on changes in the current transaction
*/

View file

@ -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.
* <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.
* @param key Key of the object. Must not be {@code null}.
* @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.
* 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.
* @return Stream of objects. Never returns {@code null}.
*/

View file

@ -16,6 +16,8 @@
*/
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.KeycloakSession;
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.UpdatableEntity;
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.criteria.DefaultModelCriteria;
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.function.Predicate;
import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
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 StringKeyConverter<K> keyConverter;
protected final DeepCloner cloner;
private final boolean isExpirableEntity;
@SuppressWarnings("unchecked")
public ConcurrentHashMapStorage(Class<M> modelClass, StringKeyConverter<K> keyConverter, DeepCloner cloner) {
this.fieldPredicates = MapFieldPredicates.getPredicates(modelClass);
this.keyConverter = keyConverter;
this.cloner = cloner;
this.isExpirableEntity = ExpirableEntity.class.isAssignableFrom(ModelEntityUtil.getEntityType(modelClass));
}
@Override
@ -79,7 +85,10 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity & UpdatableEnt
public V read(String key) {
Objects.requireNonNull(key, "Key must be non-null");
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
@ -157,7 +166,14 @@ public class ConcurrentHashMapStorage<K, V extends AbstractEntity & UpdatableEnt
Stream<Entry<K, V>> stream = store.entrySet().stream();
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()))
.map(Map.Entry::getValue);

View file

@ -151,7 +151,6 @@ public class MapFieldPredicates {
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.EXPIRATION, MapRootAuthenticationSessionEntity::getExpiration);
put(AUTHZ_RESOURCE_SERVER_PREDICATES, ResourceServer.SearchableFields.ID, predicateForKeyField(MapResourceServerEntity::getId));
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.IS_OFFLINE, MapUserSessionEntity::isOffline);
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.CLIENT_ID, MapAuthenticatedClientSessionEntity::getClientId);
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.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.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.USER_ID, MapAuthEventEntity::getUserId);
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.EVENT_TYPE, MapAuthEventEntity::getType);
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.EXPIRATION, MapAdminEventEntity::getExpiration);
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_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.ACTION_ID, MapSingleUseObjectEntity::getActionId);
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE, MapSingleUseObjectEntity::getActionVerificationNonce);
put(ACTION_TOKEN_PREDICATES, ActionTokenValueModel.SearchableFields.EXPIRATION, MapSingleUseObjectEntity::getExpiration);
}
static {

View file

@ -29,8 +29,6 @@ import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import java.util.stream.Stream;
import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
/**
* @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());
if (mcb.isValid()) {
MapSingleUseObjectEntity value = read(mcb.getKey());
if (value == null || (mcb.checkExpiration() && isExpired(value, false))) return Stream.empty();
return Stream.of(value);
return value != null ? Stream.of(value) : Stream.empty();
}
return super.read(queryParameters);

View file

@ -17,7 +17,6 @@
package org.keycloak.models.map.storage.chm;
import org.keycloak.models.ActionTokenValueModel;
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
import org.keycloak.storage.SearchableModelField;
@ -32,16 +31,13 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
private String actionVerificationNonce;
private Boolean checkExpiration;
public SingleUseObjectModelCriteriaBuilder() {
}
public SingleUseObjectModelCriteriaBuilder(String userId, String actionId, String actionVerificationNonce, Boolean checkExpiration) {
public SingleUseObjectModelCriteriaBuilder(String userId, String actionId, String actionVerificationNonce) {
this.userId = userId;
this.actionId = actionId;
this.actionVerificationNonce = actionVerificationNonce;
this.checkExpiration = checkExpiration;
}
@Override
@ -52,11 +48,8 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
actionId = value[0].toString();
} else if (modelField == org.keycloak.models.ActionTokenValueModel.SearchableFields.ACTION_VERIFICATION_NONCE) {
actionVerificationNonce = value[0].toString();
} else if (modelField == ActionTokenValueModel.SearchableFields.EXPIRATION && op == Operator.GT) {
checkExpiration = true;
}
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce, checkExpiration);
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce);
}
@Override
@ -64,7 +57,6 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
String userId = null;
String actionId = null;
String actionVerificationNonce = null;
Boolean checkExpiration = null;
for (ModelCriteriaBuilder builder: builders) {
SingleUseObjectModelCriteriaBuilder suoMcb = (SingleUseObjectModelCriteriaBuilder) builder;
@ -77,11 +69,8 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
if (suoMcb.actionVerificationNonce != null) {
actionVerificationNonce = suoMcb.actionVerificationNonce;
}
if (suoMcb.checkExpiration != null) {
checkExpiration = suoMcb.checkExpiration;
}
}
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce, checkExpiration);
return new SingleUseObjectModelCriteriaBuilder(userId, actionId, actionVerificationNonce);
}
@Override
@ -98,10 +87,6 @@ public class SingleUseObjectModelCriteriaBuilder implements ModelCriteriaBuilder
return userId != null && actionId != null && actionVerificationNonce != null;
}
public boolean checkExpiration() {
return checkExpiration != null && checkExpiration;
}
public String getKey() {
return userId + ":" + actionId + ":" + actionVerificationNonce;
}

View file

@ -207,8 +207,7 @@ public class MapUserSessionProvider implements UserSessionProvider {
.compare(AuthenticatedClientSessionModel.SearchableFields.USER_SESSION_ID, Operator.EQ, userSession.getId())
.compare(AuthenticatedClientSessionModel.SearchableFields.REALM_ID, Operator.EQ, userSession.getRealm().getId())
.compare(AuthenticatedClientSessionModel.SearchableFields.CLIENT_ID, Operator.EQ, client.getId())
.compare(AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline)
.compare(AuthenticatedClientSessionModel.SearchableFields.EXPIRATION, Operator.GT, Time.currentTimeMillis());
.compare(AuthenticatedClientSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline);
return clientSessionTx.read(withCriteria(mcb))
.findFirst()
@ -606,9 +605,7 @@ public class MapUserSessionProvider implements UserSessionProvider {
// first get a user entity by ID
DefaultModelCriteria<UserSessionModel> mcb = criteria();
mcb = mcb.compare(UserSessionModel.SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(UserSessionModel.SearchableFields.ID, Operator.EQ, userSessionId)
.compare(UserSessionModel.SearchableFields.EXPIRATION, Operator.GT, Time.currentTimeMillis())
;
.compare(UserSessionModel.SearchableFields.ID, Operator.EQ, userSessionId);
// check if it's an offline user session
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) {
return DefaultModelCriteria.<UserSessionModel>criteria()
.compare(UserSessionModel.SearchableFields.REALM_ID, Operator.EQ, realm.getId())
.compare(UserSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline)
.compare(UserSessionModel.SearchableFields.EXPIRATION, Operator.GT, Time.currentTimeMillis());
.compare(UserSessionModel.SearchableFields.IS_OFFLINE, Operator.EQ, offline);
}
private MapUserSessionEntity getUserSessionById(String id) {

View file

@ -33,7 +33,6 @@ public class Event {
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> 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> EVENT_TYPE = new SearchableModelField<>("eventType", EventType.class);
}

View file

@ -28,7 +28,6 @@ public class AdminEvent {
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> 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_CLIENT_ID = new SearchableModelField<>("authClientId", String.class);
public static final SearchableModelField<AdminEvent> AUTH_USER_ID = new SearchableModelField<>("authUserId", String.class);

View file

@ -31,7 +31,6 @@ public interface ActionTokenValueModel {
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_VERIFICATION_NONCE = new SearchableModelField<>("actionVerificationNonce", String.class);
public static final SearchableModelField<ActionTokenValueModel> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
}
/**

View file

@ -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> IS_OFFLINE = new SearchableModelField<>("isOffline", Boolean.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";

View file

@ -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> 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> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
}
/**

View file

@ -74,12 +74,19 @@ public interface AuthenticationSessionProvider extends Provider {
/**
* 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();
/**
* Removes all expired root authentication sessions for the given realm.
* @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);

View file

@ -34,7 +34,6 @@ public interface RootAuthenticationSessionModel {
public static class SearchableFields {
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> EXPIRATION = new SearchableModelField<>("expiration", Long.class);
}
/**