Replace old HotRod index annotation with new one

This commit is contained in:
Martin Kanis 2022-11-24 16:32:06 +01:00 committed by Michal Hajas
parent 9bb5b08015
commit c0e103dc95
34 changed files with 354 additions and 341 deletions

View file

@ -24,6 +24,10 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-map</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-api</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>

View file

@ -19,8 +19,8 @@ package org.keycloak.models.map.storage.hotRod;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.Scope;
import org.keycloak.events.Event;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.RealmModel;
@ -53,11 +53,8 @@ public class IckleQueryMapModelCriteriaBuilder<E extends AbstractHotRodEntity, M
private final Map<String, Object> parameters;
private static final Pattern LIKE_PATTERN_DELIMITER = Pattern.compile("%+");
private static final Pattern NON_ANALYZED_FIELD_REGEX = Pattern.compile("[%_\\\\]");
// private static final Pattern ANALYZED_FIELD_REGEX = Pattern.compile("[+!^\"~*?:\\\\]"); // TODO reevaluate once https://github.com/keycloak/keycloak/issues/9295 is fixed
private static final Pattern ANALYZED_FIELD_REGEX = Pattern.compile("\\\\"); // escape "\" with extra "\"
public static final Map<SearchableModelField<?>, String> INFINISPAN_NAME_OVERRIDES = new HashMap<>();
public static final Set<SearchableModelField<?>> ANALYZED_MODEL_FIELDS = new HashSet<>();
public static final Set<SearchableModelField<?>> LOWERCASE_NORMALIZED_MODEL_FIELDS = new HashSet<>();
static {
INFINISPAN_NAME_OVERRIDES.put(ClientModel.SearchableFields.SCOPE_MAPPING_ROLE, "scopeMappings");
@ -96,13 +93,19 @@ public class IckleQueryMapModelCriteriaBuilder<E extends AbstractHotRodEntity, M
}
static {
// the "filename" analyzer in Infinispan works correctly for case-insensitive search with whitespaces
ANALYZED_MODEL_FIELDS.add(RoleModel.SearchableFields.DESCRIPTION);
ANALYZED_MODEL_FIELDS.add(UserModel.SearchableFields.FIRST_NAME);
ANALYZED_MODEL_FIELDS.add(UserModel.SearchableFields.LAST_NAME);
ANALYZED_MODEL_FIELDS.add(UserModel.SearchableFields.EMAIL);
ANALYZED_MODEL_FIELDS.add(Policy.SearchableFields.TYPE);
ANALYZED_MODEL_FIELDS.add(Resource.SearchableFields.TYPE);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(Policy.SearchableFields.NAME);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(Policy.SearchableFields.TYPE);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(Resource.SearchableFields.NAME);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(Resource.SearchableFields.TYPE);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(Scope.SearchableFields.NAME);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(ClientModel.SearchableFields.CLIENT_ID);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(GroupModel.SearchableFields.NAME);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(RoleModel.SearchableFields.NAME);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(RoleModel.SearchableFields.DESCRIPTION);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(UserModel.SearchableFields.USERNAME_CASE_INSENSITIVE);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(UserModel.SearchableFields.EMAIL);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(UserModel.SearchableFields.FIRST_NAME);
LOWERCASE_NORMALIZED_MODEL_FIELDS.add(UserModel.SearchableFields.LAST_NAME);
}
public IckleQueryMapModelCriteriaBuilder(Class<E> hotRodEntityClass, StringBuilder whereClauseBuilder, Map<String, Object> parameters) {
@ -237,14 +240,6 @@ public class IckleQueryMapModelCriteriaBuilder<E extends AbstractHotRodEntity, M
return value;
}
public static Object sanitizeAnalyzed(Object value) {
if (value instanceof String) {
return sanitizeEachUnitAndReplaceDelimiter((String) value, IckleQueryMapModelCriteriaBuilder::sanitizeSingleUnitAnalyzed, "*");
}
return value;
}
private static String sanitizeEachUnitAndReplaceDelimiter(String value, UnaryOperator<String> sanitizeSingleUnit, String replacement) {
return LIKE_PATTERN_DELIMITER.splitAsStream(value)
.map(sanitizeSingleUnit)
@ -256,18 +251,6 @@ public class IckleQueryMapModelCriteriaBuilder<E extends AbstractHotRodEntity, M
return NON_ANALYZED_FIELD_REGEX.matcher(value).replaceAll("\\\\\\\\" + "$0");
}
private static String sanitizeSingleUnitAnalyzed(String value) {
return ANALYZED_FIELD_REGEX.matcher(value).replaceAll("\\\\\\\\"); // escape "\" with extra "\"
// .replaceAll("\\\\\\\\" + "$0"); skipped for now because Infinispan is not able to escape
// special characters for analyzed fields
// TODO reevaluate once https://github.com/keycloak/keycloak/issues/9295 is fixed
}
public static boolean isAnalyzedModelField(SearchableModelField<?> modelField) {
return ANALYZED_MODEL_FIELDS.contains(modelField);
}
/**
*
* @return Ickle query that represents this QueryBuilder

View file

@ -56,7 +56,7 @@ public class IckleQueryOperators {
OPERATOR_TO_EXPRESSION_COMBINATORS.put(ModelCriteriaBuilder.Operator.IN, IckleQueryOperators::in);
OPERATOR_TO_EXPRESSION_COMBINATORS.put(ModelCriteriaBuilder.Operator.EXISTS, IckleQueryOperators::exists);
OPERATOR_TO_EXPRESSION_COMBINATORS.put(ModelCriteriaBuilder.Operator.NOT_EXISTS, IckleQueryOperators::notExists);
OPERATOR_TO_EXPRESSION_COMBINATORS.put(ModelCriteriaBuilder.Operator.ILIKE, IckleQueryOperators::iLike);
OPERATOR_TO_EXPRESSION_COMBINATORS.put(ModelCriteriaBuilder.Operator.ILIKE, IckleQueryOperators::like);
OPERATOR_TO_EXPRESSION_COMBINATORS.put(ModelCriteriaBuilder.Operator.LIKE, IckleQueryOperators::like);
OPERATOR_TO_STRING.put(ModelCriteriaBuilder.Operator.EQ, "=");
@ -94,12 +94,6 @@ public class IckleQueryOperators {
return field + " IS NULL OR " + field + " IS EMPTY";
}
private static String iLike(String modelFieldName, Object[] values, Map<String, Object> parameters) {
String sanitizedValue = (String) IckleQueryMapModelCriteriaBuilder.sanitizeNonAnalyzed(values[0]);
return singleValueOperator(ModelCriteriaBuilder.Operator.ILIKE)
.combine(modelFieldName + "Lowercase", new String[] {sanitizedValue.toLowerCase()}, parameters);
}
private static String like(String modelFieldName, Object[] values, Map<String, Object> parameters) {
String sanitizedValue = (String) IckleQueryMapModelCriteriaBuilder.sanitizeNonAnalyzed(values[0]);
return singleValueOperator(ModelCriteriaBuilder.Operator.LIKE)

View file

@ -38,9 +38,8 @@ import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.keycloak.models.map.storage.hotRod.IckleQueryMapModelCriteriaBuilder.LOWERCASE_NORMALIZED_MODEL_FIELDS;
import static org.keycloak.models.map.storage.hotRod.IckleQueryMapModelCriteriaBuilder.getFieldName;
import static org.keycloak.models.map.storage.hotRod.IckleQueryMapModelCriteriaBuilder.sanitizeAnalyzed;
import static org.keycloak.models.map.storage.hotRod.IckleQueryOperators.C;
/**
* This class provides knowledge on how to build Ickle query where clauses for specified {@link SearchableModelField}.
@ -98,15 +97,12 @@ public class IckleQueryWhereClauses {
Object[] values, Map<String, Object> parameters) {
String fieldName = IckleQueryMapModelCriteriaBuilder.getFieldName(modelField);
if (IckleQueryMapModelCriteriaBuilder.isAnalyzedModelField(modelField) &&
(op.equals(ModelCriteriaBuilder.Operator.ILIKE) || op.equals(ModelCriteriaBuilder.Operator.EQ) || op.equals(ModelCriteriaBuilder.Operator.NE))) {
if (op == ModelCriteriaBuilder.Operator.ILIKE && !LOWERCASE_NORMALIZED_MODEL_FIELDS.contains(modelField)) {
throw new CriterionNotSupportedException(modelField, op, "Attempt to search case-insensitively without lowercase normalizer applied on the field.");
}
String clause = C + "." + fieldName + " : '" + sanitizeAnalyzed(((String)values[0]).toLowerCase()) + "'";
if (op.equals(ModelCriteriaBuilder.Operator.NE)) {
return "not(" + clause + ")";
}
return clause;
if (op == ModelCriteriaBuilder.Operator.LIKE && LOWERCASE_NORMALIZED_MODEL_FIELDS.contains(modelField)) {
throw new CriterionNotSupportedException(modelField, op, "Attempt to search case-sensitively with lowercase-normalized field.");
}
return whereClauseProducerForModelField(modelField).produceWhereClause(fieldName, op, values, parameters);

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.authSession;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -41,7 +43,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.sessions.RootAuthenticationSessionModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodRootAuthenticationSessionEntity.VERSION)
public class HotRodRootAuthenticationSessionEntity extends AbstractHotRodEntity {
@ -62,21 +64,21 @@ public class HotRodRootAuthenticationSessionEntity extends AbstractHotRodEntity
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoField(number = 4)
public Long timestamp;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 5)
public Long expiration;

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.authorization;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -35,7 +37,7 @@ import org.keycloak.models.map.storage.hotRod.common.UpdatableHotRodEntityDelega
modelClass = "org.keycloak.authorization.model.PermissionTicket",
cacheName = "authz"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodPermissionTicketEntity.VERSION)
public class HotRodPermissionTicketEntity extends AbstractHotRodEntity {
@ -53,47 +55,47 @@ public class HotRodPermissionTicketEntity extends AbstractHotRodEntity {
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@Basic(sortable = true)
@ProtoField(number = 4)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String owner;
@Basic(sortable = true)
@ProtoField(number = 5)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String requester;
@ProtoField(number = 6)
public Long createdTimestamp;
@Basic(sortable = true)
@ProtoField(number = 7)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public Long grantedTimestamp;
@Basic(sortable = true)
@ProtoField(number = 8)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String resourceId;
@Basic(sortable = true)
@ProtoField(number = 9)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String scopeId;
@Basic(sortable = true)
@ProtoField(number = 10)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String resourceServerId;
@Basic(sortable = true)
@ProtoField(number = 11)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String policyId;
public static abstract class AbstractHotRodPermissionTicketEntity extends UpdatableHotRodEntityDelegateImpl<HotRodPermissionTicketEntity> implements MapPermissionTicketEntity {

View file

@ -17,6 +17,9 @@
package org.keycloak.models.map.storage.hotRod.authorization;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -39,7 +42,7 @@ import java.util.Set;
modelClass = "org.keycloak.authorization.model.Policy",
cacheName = "authz"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodPolicyEntity.VERSION)
public class HotRodPolicyEntity extends AbstractHotRodEntity {
@ -59,61 +62,57 @@ public class HotRodPolicyEntity extends AbstractHotRodEntity {
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 4)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String name;
@ProtoField(number = 5)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String nameLowercase;
@ProtoField(number = 6)
public String description;
@ProtoField(number = 7)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"filename\"))")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 6)
public String type;
@ProtoField(number = 8)
@ProtoField(number = 7)
public Integer decisionStrategy;
@ProtoField(number = 9)
@ProtoField(number = 8)
public Integer logic;
@ProtoField(number = 10)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 9)
public Set<HotRodStringPair> configs;
@ProtoField(number = 11)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 10)
public String resourceServerId;
@ProtoField(number = 12)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 11)
public Set<String> associatedPolicyIds;
@ProtoField(number = 13)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 12)
public Set<String> resourceIds;
@ProtoField(number = 14)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 13)
public Set<String> scopeIds;
@ProtoField(number = 15)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 14)
public String owner;
public static abstract class AbstractHotRodPolicyEntity extends UpdatableHotRodEntityDelegateImpl<HotRodPolicyEntity> implements MapPolicyEntity {
@ -136,7 +135,6 @@ public class HotRodPolicyEntity extends AbstractHotRodEntity {
HotRodPolicyEntity entity = getHotRodEntity();
entity.updated |= ! Objects.equals(entity.name, name);
entity.name = name;
entity.nameLowercase = name == null ? null : name.toLowerCase();
}
}

View file

@ -17,6 +17,9 @@
package org.keycloak.models.map.storage.hotRod.authorization;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -39,7 +42,7 @@ import java.util.Set;
modelClass = "org.keycloak.authorization.model.Resource",
cacheName = "authz"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodResourceEntity.VERSION)
public class HotRodResourceEntity extends AbstractHotRodEntity {
@ -59,57 +62,53 @@ public class HotRodResourceEntity extends AbstractHotRodEntity {
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 4)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String name;
@ProtoField(number = 5)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String nameLowercase;
@ProtoField(number = 6)
public String displayName;
@ProtoField(number = 7)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 6)
public Set<String> uris;
@ProtoField(number = 8)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"filename\"))")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 7)
public String type;
@ProtoField(number = 9)
@ProtoField(number = 8)
public String iconUri;
@ProtoField(number = 10)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 9)
public String owner;
@ProtoField(number = 11)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 10)
public Boolean ownerManagedAccess;
@ProtoField(number = 12)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 11)
public String resourceServerId;
@ProtoField(number = 13)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 12)
public Set<String> scopeIds;
@ProtoField(number = 14)
@ProtoField(number = 13)
public Set<HotRodAttributeEntityNonIndexed> attributes;
public static abstract class AbstractHotRodResourceEntity extends UpdatableHotRodEntityDelegateImpl<HotRodResourceEntity> implements MapResourceEntity {
@ -132,7 +131,6 @@ public class HotRodResourceEntity extends AbstractHotRodEntity {
HotRodResourceEntity entity = getHotRodEntity();
entity.updated |= ! Objects.equals(entity.name, name);
entity.name = name;
entity.nameLowercase = name == null ? null : name.toLowerCase();
}
}

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.authorization;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -37,7 +39,7 @@ import org.keycloak.models.map.storage.hotRod.common.UpdatableHotRodEntityDelega
cacheName = "authz"
)
@ProtoDoc("schema-version: " + HotRodResourceServerEntity.VERSION)
@ProtoDoc("@Indexed")
@Indexed
public class HotRodResourceServerEntity extends AbstractHotRodEntity {
@IgnoreForEntityImplementationGenerator
@ -54,19 +56,19 @@ public class HotRodResourceServerEntity extends AbstractHotRodEntity {
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 4)
public String clientId;

View file

@ -17,6 +17,9 @@
package org.keycloak.models.map.storage.hotRod.authorization;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -37,7 +40,7 @@ import java.util.Objects;
modelClass = "org.keycloak.authorization.model.Scope",
cacheName = "authz"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodScopeEntity.VERSION)
public class HotRodScopeEntity extends AbstractHotRodEntity {
@ -55,34 +58,30 @@ public class HotRodScopeEntity extends AbstractHotRodEntity {
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 4)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String name;
@ProtoField(number = 5)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String nameLowercase;
@ProtoField(number = 6)
public String displayName;
@ProtoField(number = 7)
@ProtoField(number = 6)
public String iconUri;
@ProtoField(number = 8)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 7)
public String resourceServerId;
public static abstract class AbstractHotRodScopeEntity extends UpdatableHotRodEntityDelegateImpl<HotRodScopeEntity> implements MapScopeEntity {
@ -105,7 +104,6 @@ public class HotRodScopeEntity extends AbstractHotRodEntity {
HotRodScopeEntity entity = getHotRodEntity();
entity.updated |= ! Objects.equals(entity.name, name);
entity.name = name;
entity.nameLowercase = name == null ? null : name.toLowerCase();
}
}

View file

@ -17,6 +17,9 @@
package org.keycloak.models.map.storage.hotRod.client;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -46,7 +49,7 @@ import java.util.stream.Stream;
topLevelEntity = true,
modelClass = "org.keycloak.models.ClientModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodClientEntity.VERSION)
public class HotRodClientEntity extends AbstractHotRodEntity {
@ -66,123 +69,115 @@ public class HotRodClientEntity extends AbstractHotRodEntity {
HotRodClientEntitySchema INSTANCE = new HotRodClientEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 4)
public String clientId;
/**
* Lowercase interpretation of {@link #clientId} field. Infinispan doesn't support case-insensitive LIKE for non-analyzed fields.
* Search on analyzed fields can be case-insensitive (based on used analyzer) but doesn't support ORDER BY analyzed field.
*/
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 5)
public String clientIdLowercase;
@ProtoField(number = 6)
public String name;
@ProtoField(number = 7)
@ProtoField(number = 6)
public String description;
@ProtoField(number = 8)
@ProtoField(number = 7)
public Set<String> redirectUris;
@ProtoField(number = 9)
@ProtoField(number = 8)
public Boolean enabled;
@ProtoField(number = 10)
@ProtoField(number = 9)
public Boolean alwaysDisplayInConsole;
@ProtoField(number = 11)
@ProtoField(number = 10)
public String clientAuthenticatorType;
@ProtoField(number = 12)
@ProtoField(number = 11)
public String secret;
@ProtoField(number = 13)
@ProtoField(number = 12)
public String registrationToken;
@ProtoField(number = 14)
@ProtoField(number = 13)
public String protocol;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 15)
@Basic(sortable = true)
@ProtoField(number = 14)
public Set<HotRodAttributeEntity> attributes;
@ProtoField(number = 16)
@ProtoField(number = 15)
public Set<HotRodPair<String, String>> authenticationFlowBindingOverrides;
@ProtoField(number = 17)
@ProtoField(number = 16)
public Boolean publicClient;
@ProtoField(number = 18)
@ProtoField(number = 17)
public Boolean fullScopeAllowed;
@ProtoField(number = 19)
@ProtoField(number = 18)
public Boolean frontchannelLogout;
@ProtoField(number = 20)
@ProtoField(number = 19)
public Long notBefore;
@ProtoField(number = 21)
@ProtoField(number = 20)
public Set<String> scope;
@ProtoField(number = 22)
@ProtoField(number = 21)
public Set<String> webOrigins;
@ProtoField(number = 23)
@ProtoField(number = 22)
public Set<HotRodProtocolMapperEntity> protocolMappers;
@ProtoField(number = 24)
@ProtoField(number = 23)
public Set<HotRodPair<String, Boolean>> clientScopes;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 25, collectionImplementation = LinkedList.class)
@Basic(sortable = true)
@ProtoField(number = 24, collectionImplementation = LinkedList.class)
public Collection<String> scopeMappings;
@ProtoField(number = 26)
@ProtoField(number = 25)
public Boolean surrogateAuthRequired;
@ProtoField(number = 27)
@ProtoField(number = 26)
public String managementUrl;
@ProtoField(number = 28)
@ProtoField(number = 27)
public String baseUrl;
@ProtoField(number = 29)
@ProtoField(number = 28)
public Boolean bearerOnly;
@ProtoField(number = 30)
@ProtoField(number = 29)
public Boolean consentRequired;
@ProtoField(number = 31)
@ProtoField(number = 30)
public String rootUrl;
@ProtoField(number = 32)
@ProtoField(number = 31)
public Boolean standardFlowEnabled;
@ProtoField(number = 33)
@ProtoField(number = 32)
public Boolean implicitFlowEnabled;
@ProtoField(number = 34)
@ProtoField(number = 33)
public Boolean directAccessGrantsEnabled;
@ProtoField(number = 35)
@ProtoField(number = 34)
public Boolean serviceAccountsEnabled;
@ProtoField(number = 36)
@ProtoField(number = 35)
public Integer nodeReRegistrationTimeout;
public static abstract class AbstractHotRodClientEntityDelegate extends UpdatableHotRodEntityDelegateImpl<HotRodClientEntity> implements MapClientEntity {
@ -205,7 +200,6 @@ public class HotRodClientEntity extends AbstractHotRodEntity {
HotRodClientEntity entity = getHotRodEntity();
entity.updated |= ! Objects.equals(entity.clientId, clientId);
entity.clientId = clientId;
entity.clientIdLowercase = clientId == null ? null : clientId.toLowerCase();
}
@Override

View file

@ -34,10 +34,6 @@ public class HotRodProtocolMapperEntity extends AbstractHotRodEntity {
public String protocol;
@ProtoField(number = 4)
public String protocolMapper;
// @ProtoField(number = 5, defaultValue = "false")
// public boolean consentRequired;
// @ProtoField(number = 5)
// public String consentText;
@ProtoField(number = 5)
public Set<HotRodPair<String, String>> config;

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.clientscope;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -43,7 +45,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.models.ClientScopeModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodClientScopeEntity.VERSION)
public class HotRodClientScopeEntity extends AbstractHotRodEntity {
@ -63,18 +65,18 @@ public class HotRodClientScopeEntity extends AbstractHotRodEntity {
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 4)
public String name;

View file

@ -17,7 +17,8 @@
package org.keycloak.models.map.storage.hotRod.common;
import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.annotations.ProtoField;
import java.util.List;
@ -29,13 +30,13 @@ import java.util.Objects;
* If some change is needed please create a new version of this class and solve the migration on top-level entities.
*
*/
@ProtoDoc("@Indexed")
@Indexed
public class HotRodAttributeEntity {
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 1)
public String name;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 2)
public List<String> values;

View file

@ -17,7 +17,6 @@
package org.keycloak.models.map.storage.hotRod.common;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.UpdatableEntity;
public interface HotRodEntityDelegate<E> extends UpdatableEntity {

View file

@ -17,7 +17,8 @@
package org.keycloak.models.map.storage.hotRod.common;
import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.annotations.ProtoField;
import java.util.Objects;
@ -30,14 +31,14 @@ import java.util.Objects;
* Indexed Hot Rod pair entity where both key and value are {@link String} type. The entity should be used when
* there is a need to search by key or/and value. Otherwise {@link HotRodPair<String, String>} should be used.
*/
@ProtoDoc("@Indexed")
@Indexed
public class HotRodStringPair {
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 1)
public String key;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 2)
public String value;

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.events;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -34,7 +36,7 @@ import org.keycloak.models.map.storage.hotRod.common.UpdatableHotRodEntityDelega
topLevelEntity = true,
modelClass = "org.keycloak.events.admin.AdminEvent"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodAdminEventEntity.VERSION)
public class HotRodAdminEventEntity extends AbstractHotRodEntity {
@ -50,56 +52,56 @@ public class HotRodAdminEventEntity extends AbstractHotRodEntity {
public interface HotRodAdminEventEntitySchema extends GeneratedSchema {
HotRodAdminEventEntitySchema INSTANCE = new HotRodAdminEventEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public Long expiration;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 4)
public Long timestamp;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 5)
public Integer operationType;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 6)
public String authClientId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 7)
public String authIpAddress;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 8)
public String authRealmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 9)
public String authUserId;
@ProtoField(number = 10)
public String error;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 11)
public String realmId;
@ProtoField(number = 12)
public String representation;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 13)
public String resourcePath;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 14)
public String resourceType;

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.events;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -36,7 +38,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.events.Event"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodAuthEventEntity.VERSION)
public class HotRodAuthEventEntity extends AbstractHotRodEntity {
@ -55,44 +57,44 @@ public class HotRodAuthEventEntity extends AbstractHotRodEntity {
HotRodAuthEventEntitySchema INSTANCE = new HotRodAuthEventEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public Integer type;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 4)
public Long expiration;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 5)
public Long timestamp;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 6)
public String clientId;
@ProtoField(number = 7)
public String error;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 8)
public String ipAddress;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 9)
public String realmId;
@ProtoField(number = 10)
public String sessionId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 11)
public String userId;

View file

@ -17,6 +17,9 @@
package org.keycloak.models.map.storage.hotRod.group;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -38,7 +41,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.models.GroupModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodGroupEntity.VERSION)
public class HotRodGroupEntity extends AbstractHotRodEntity {
@ -77,44 +80,35 @@ public class HotRodGroupEntity extends AbstractHotRodEntity {
HotRodGroupEntity entity = getHotRodEntity();
entity.updated |= ! Objects.equals(entity.name, name);
entity.name = name;
entity.nameLowercase = name == null ? null : name.toLowerCase();
}
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 4)
public String name;
/**
* Lowercase interpretation of {@link #name} field. Infinispan doesn't support case-insensitive LIKE for non-analyzed fields.
* Search on analyzed fields can be case-insensitive (based on used analyzer) but doesn't support ORDER BY analyzed field.
*/
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 5)
public String nameLowercase;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 6)
public String parentId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 7)
@Basic(sortable = true)
@ProtoField(number = 6)
public Set<HotRodAttributeEntity> attributes;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 8)
@Basic(sortable = true)
@ProtoField(number = 7)
public Set<String> grantedRoles;
@Override

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.loginFailure;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -34,7 +36,7 @@ import org.keycloak.models.map.storage.hotRod.common.UpdatableHotRodEntityDelega
topLevelEntity = true,
modelClass = "org.keycloak.models.UserLoginFailureModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodUserLoginFailureEntity.VERSION)
public class HotRodUserLoginFailureEntity extends AbstractHotRodEntity {
@ -51,18 +53,18 @@ public class HotRodUserLoginFailureEntity extends AbstractHotRodEntity {
HotRodUserLoginFailureEntitySchema INSTANCE = new HotRodUserLoginFailureEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 4)
public String userId;

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.realm;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -75,7 +77,7 @@ import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
topLevelEntity = true,
modelClass = "org.keycloak.models.RealmModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodRealmEntity.VERSION)
public class HotRodRealmEntity extends AbstractHotRodEntity {
@ -106,14 +108,14 @@ public class HotRodRealmEntity extends AbstractHotRodEntity {
HotRodRealmEntitySchema INSTANCE = new HotRodRealmEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String name;
@ -242,11 +244,11 @@ public class HotRodRealmEntity extends AbstractHotRodEntity {
@ProtoField(number = 65)
public Set<HotRodAuthenticatorConfigEntity> authenticatorConfigs;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 66)
public Set<HotRodClientInitialAccessEntity> clientInitialAccesses;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 67)
public Set<HotRodComponentEntity> components;

View file

@ -1,6 +1,7 @@
package org.keycloak.models.map.storage.hotRod.realm.entity;
import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.map.annotations.GenerateHotRodEntityImplementation;
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
@ -11,7 +12,7 @@ import java.util.Set;
@GenerateHotRodEntityImplementation(
implementInterface = "org.keycloak.models.map.realm.entity.MapComponentEntity"
)
@ProtoDoc("@Indexed")
@Indexed
public class HotRodComponentEntity extends AbstractHotRodEntity {
@ProtoField(number = 1)
public String id;
@ -22,7 +23,7 @@ public class HotRodComponentEntity extends AbstractHotRodEntity {
@ProtoField(number = 4)
public String providerId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 5)
public String providerType;

View file

@ -16,6 +16,9 @@
*/
package org.keycloak.models.map.storage.hotRod.role;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -37,7 +40,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.models.RoleModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodRoleEntity.VERSION)
public class HotRodRoleEntity extends AbstractHotRodEntity {
@ -77,51 +80,42 @@ public class HotRodRoleEntity extends AbstractHotRodEntity {
HotRodRoleEntity entity = getHotRodEntity();
entity.updated |= ! Objects.equals(entity.name, name);
entity.name = name;
entity.nameLowercase = name == null ? null : name.toLowerCase();
}
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 4)
public String name;
/**
* Lowercase interpretation of {@link #name} field. Infinispan doesn't support case-insensitive LIKE for non-analyzed fields.
* Search on analyzed fields can be case-insensitive (based on used analyzer) but doesn't support ORDER BY analyzed field.
*/
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 5)
public String nameLowercase;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"filename\"))")
@ProtoField(number = 6)
public String description;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 7)
@Basic(sortable = true)
@ProtoField(number = 6)
public Boolean clientRole;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 8)
@Basic(sortable = true)
@ProtoField(number = 7)
public String clientId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@ProtoField(number = 9)
@Basic(sortable = true)
@ProtoField(number = 8)
public Set<String> compositeRoles;
@ProtoField(number = 10)
@ProtoField(number = 9)
public Set<HotRodAttributeEntityNonIndexed> attributes;
@Override

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.singleUseObject;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -37,7 +39,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.models.SingleUseObjectValueModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodSingleUseObjectEntity.VERSION)
public class HotRodSingleUseObjectEntity extends AbstractHotRodEntity {
@ -56,7 +58,7 @@ public class HotRodSingleUseObjectEntity extends AbstractHotRodEntity {
HotRodSingleUseObjectEntitySchema INSTANCE = new HotRodSingleUseObjectEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;

View file

@ -17,23 +17,23 @@
package org.keycloak.models.map.storage.hotRod.user;
import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.map.annotations.GenerateHotRodEntityImplementation;
import org.keycloak.models.map.storage.hotRod.client.HotRodProtocolMapperEntityDelegate;
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
import java.util.Set;
@GenerateHotRodEntityImplementation(implementInterface = "org.keycloak.models.map.user.MapUserConsentEntity")
@ProtoDoc("@Indexed")
@Indexed
public class HotRodUserConsentEntity extends AbstractHotRodEntity {
@Basic(sortable = true)
@ProtoField(number = 1)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String clientId;
@Basic(sortable = true)
@ProtoField(number = 2)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public Set<String> grantedClientScopesIds;
@ProtoField(number = 3)

View file

@ -17,6 +17,9 @@
package org.keycloak.models.map.storage.hotRod.user;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.api.annotations.indexing.Keyword;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -49,7 +52,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.models.UserModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodUserEntity.VERSION)
public class HotRodUserEntity extends AbstractHotRodEntity {
@ -73,42 +76,41 @@ public class HotRodUserEntity extends AbstractHotRodEntity {
@IgnoreForEntityImplementationGenerator
private static final Logger LOG = Logger.getLogger(HotRodUserEntity.class);
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@Basic(sortable = true)
@ProtoField(number = 4)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String username;
@ProtoField(number = 22)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 5)
public String usernameLowercase;
@ProtoField(number = 5)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"filename\"))")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 6)
public String firstName;
@ProtoField(number = 6)
@ProtoField(number = 7)
public Long createdTimestamp;
@ProtoField(number = 7)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"filename\"))")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 8)
public String lastName;
@ProtoField(number = 8)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"filename\"))")
@Keyword(sortable = true, normalizer = "lowercase")
@ProtoField(number = 9)
public String email;
@ProtoField(number = 9)
/**
* TODO: Workaround for ISPN-8584
*
@ -121,10 +123,10 @@ public class HotRodUserEntity extends AbstractHotRodEntity {
*
* In other words it is not possible to combine searching for Analyzed field and non-indexed field in one Ickle query
*/
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 10)
public Boolean enabled;
@ProtoField(number = 10)
/**
* TODO: Workaround for ISPN-8584
*
@ -135,48 +137,49 @@ public class HotRodUserEntity extends AbstractHotRodEntity {
*
* In other words it is not possible to combine searching for Analyzed field and non-indexed field in one Ickle query
*/
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 11)
public Boolean emailVerified;
// This is necessary to be able to dynamically switch unique email constraints on and off in the realm settings
@ProtoField(number = 11)
@ProtoField(number = 12)
public String emailConstraint;
@ProtoField(number = 12)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 13)
public Set<HotRodAttributeEntity> attributes;
@ProtoField(number = 13)
@ProtoField(number = 14)
public Set<String> requiredActions;
@ProtoField(number = 14)
@ProtoField(number = 15)
public List<HotRodUserCredentialEntity> credentials;
@ProtoField(number = 15)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 16)
public Set<HotRodUserFederatedIdentityEntity> federatedIdentities;
@ProtoField(number = 16)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 17)
public Set<HotRodUserConsentEntity> userConsents;
@ProtoField(number = 17)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 18)
public Set<String> groupsMembership = new HashSet<>();
@ProtoField(number = 18)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 19)
public Set<String> rolesMembership = new HashSet<>();
@ProtoField(number = 19)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 20)
public String federationLink;
@ProtoField(number = 20)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 21)
public String serviceAccountClientLink;
@ProtoField(number = 21)
@ProtoField(number = 22)
public Long notBefore;
public static abstract class AbstractHotRodUserEntityDelegate extends UpdatableHotRodEntityDelegateImpl<HotRodUserEntity> implements MapUserEntity {

View file

@ -17,25 +17,25 @@
package org.keycloak.models.map.storage.hotRod.user;
import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.map.annotations.GenerateHotRodEntityImplementation;
import org.keycloak.models.map.storage.hotRod.client.HotRodProtocolMapperEntityDelegate;
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
@GenerateHotRodEntityImplementation(implementInterface = "org.keycloak.models.map.user.MapUserFederatedIdentityEntity")
@ProtoDoc("@Indexed")
@Indexed
public class HotRodUserFederatedIdentityEntity extends AbstractHotRodEntity {
@Basic(sortable = true)
@ProtoField(number = 1)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String identityProvider;
@ProtoField(number = 2)
public String token;
@Basic(sortable = true)
@ProtoField(number = 3)
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
public String userId;
@ProtoField(number = 4)

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.userSession;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -42,7 +44,7 @@ import java.util.Set;
cacheName = "org.keycloak.models.map.storage.ModelEntityUtil.getModelName(org.keycloak.models.UserSessionModel.class)" // Use the same cache name as user-sessions
)
@ProtoDoc("schema-version: " + HotRodResourceServerEntity.VERSION)
@ProtoDoc("@Indexed")
@Indexed
public class HotRodAuthenticatedClientSessionEntity extends AbstractHotRodEntity {
@IgnoreForEntityImplementationGenerator
@ -63,10 +65,11 @@ public class HotRodAuthenticatedClientSessionEntity extends AbstractHotRodEntity
HotRodAuthenticatedClientSessionEntitySchema INSTANCE = new HotRodAuthenticatedClientSessionEntitySchemaImpl();
}
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true, sortable = true)
@ProtoField(number = 2)
public String id;

View file

@ -17,13 +17,14 @@
package org.keycloak.models.map.storage.hotRod.userSession;
import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.annotations.ProtoField;
@ProtoDoc("@Indexed")
@Indexed
public class HotRodAuthenticatedClientSessionEntityReference {
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 1)
public String clientId;

View file

@ -17,6 +17,8 @@
package org.keycloak.models.map.storage.hotRod.userSession;
import org.infinispan.api.annotations.indexing.Basic;
import org.infinispan.api.annotations.indexing.Indexed;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.annotations.ProtoDoc;
@ -24,20 +26,15 @@ import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.map.annotations.GenerateHotRodEntityImplementation;
import org.keycloak.models.map.annotations.IgnoreForEntityImplementationGenerator;
import org.keycloak.models.map.common.DeepCloner;
import org.keycloak.models.map.common.delegate.DelegateProvider;
import org.keycloak.models.map.storage.hotRod.authorization.HotRodResourceServerEntity;
import org.keycloak.models.map.common.UpdatableEntity;
import org.keycloak.models.map.storage.hotRod.client.HotRodClientEntityDelegate;
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
import org.keycloak.models.map.storage.hotRod.common.CommonPrimitivesProtoSchemaInitializer;
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDelegate;
import org.keycloak.models.map.storage.hotRod.common.HotRodStringPair;
import org.keycloak.models.map.storage.hotRod.common.HotRodTypesUtils;
import org.keycloak.models.map.storage.hotRod.common.UpdatableHotRodEntityDelegateImpl;
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
import org.keycloak.models.map.userSession.MapUserSessionEntity;
import org.keycloak.models.map.userSession.MapUserSessionEntityDelegate;
import java.util.Collections;
import java.util.Objects;
@ -50,7 +47,7 @@ import java.util.Set;
topLevelEntity = true,
modelClass = "org.keycloak.models.UserSessionModel"
)
@ProtoDoc("@Indexed")
@Indexed
@ProtoDoc("schema-version: " + HotRodResourceServerEntity.VERSION)
public class HotRodUserSessionEntity extends AbstractHotRodEntity {
@ -70,26 +67,26 @@ public class HotRodUserSessionEntity extends AbstractHotRodEntity {
HotRodUserSessionEntitySchema INSTANCE = new HotRodUserSessionEntitySchemaImpl();
}
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(projectable = true)
@ProtoField(number = 1)
public Integer entityVersion = VERSION;
@ProtoField(number = 2)
public String id;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 3)
public String realmId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 4)
public String userId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 5)
public String brokerSessionId;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 6)
public String brokerUserId;
@ -108,26 +105,26 @@ public class HotRodUserSessionEntity extends AbstractHotRodEntity {
@ProtoField(number = 11)
public Long timestamp;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 12)
public Long lastSessionRefresh;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 13)
public Long expiration;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 14)
public Set<HotRodStringPair> notes;
@ProtoField(number = 15)
public Integer state;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 16)
public Set<HotRodAuthenticatedClientSessionEntityReference> authenticatedClientSessions;
@ProtoDoc("@Field(index = Index.YES, store = Store.YES)")
@Basic(sortable = true)
@ProtoField(number = 17)
public Boolean offline;

View file

@ -77,7 +77,7 @@ public class IckleQueryMapModelCriteriaBuilderTest {
DefaultModelCriteria<UserModel> criteria = mcb.compare(UserModel.SearchableFields.REALM_ID, ModelCriteriaBuilder.Operator.EQ, "realm1");
criteria = criteria.compare(UserModel.SearchableFields.SERVICE_ACCOUNT_CLIENT, ModelCriteriaBuilder.Operator.NOT_EXISTS);
criteria = mcb.and(criteria, mcb.or(
mcb.compare(UserModel.SearchableFields.USERNAME, ModelCriteriaBuilder.Operator.ILIKE, "a"),
mcb.compare(UserModel.SearchableFields.USERNAME, ModelCriteriaBuilder.Operator.LIKE, "a"),
mcb.compare(UserModel.SearchableFields.EMAIL, ModelCriteriaBuilder.Operator.ILIKE, "a"),
mcb.compare(UserModel.SearchableFields.FIRST_NAME, ModelCriteriaBuilder.Operator.ILIKE, "a"),
mcb.compare(UserModel.SearchableFields.LAST_NAME, ModelCriteriaBuilder.Operator.ILIKE, "a")
@ -85,7 +85,17 @@ public class IckleQueryMapModelCriteriaBuilderTest {
IckleQueryMapModelCriteriaBuilder<HotRodUserEntity, UserModel> ickle = criteria.flashToModelCriteriaBuilder(new IckleQueryMapModelCriteriaBuilder<>(HotRodUserEntity.class));
assertThat(ickle.getIckleQuery(), is(equalTo("FROM kc.HotRodUserEntity c WHERE ((c.realmId = :realmId0) AND (c.serviceAccountClientLink IS NULL OR c.serviceAccountClientLink IS EMPTY) AND ((c.usernameLowercase LIKE :usernameLowercase0) OR (c.email : 'a') OR (c.firstName : 'a') OR (c.lastName : 'a')))")));
assertThat(ickle.getIckleQuery(), is(equalTo("FROM kc.HotRodUserEntity c WHERE ((c.realmId = :realmId0) AND (c.serviceAccountClientLink IS NULL OR c.serviceAccountClientLink IS EMPTY) AND ((c.username LIKE :username0) OR (c.email LIKE :email0) OR (c.firstName LIKE :firstName0) OR (c.lastName LIKE :lastName0)))")));
assertThat(ickle.getParameters().entrySet(), hasSize(5));
assertThat(ickle.getParameters(), allOf(hasEntry("realmId0", "realm1"), hasEntry("username0", "a"), hasEntry("email0", "a"), hasEntry("firstName0", "a"), hasEntry("lastName0", "a")));
final DefaultModelCriteria<UserModel> mcb2 = criteria();
criteria = mcb2.compare(UserModel.SearchableFields.REALM_ID, ModelCriteriaBuilder.Operator.EQ, "realm1")
.compare(UserModel.SearchableFields.USERNAME_CASE_INSENSITIVE, ModelCriteriaBuilder.Operator.ILIKE, "a");
ickle = criteria.flashToModelCriteriaBuilder(new IckleQueryMapModelCriteriaBuilder<>(HotRodUserEntity.class));
assertThat(ickle.getIckleQuery(), is(equalTo("FROM kc.HotRodUserEntity c WHERE ((c.realmId = :realmId0) AND (c.usernameLowercase LIKE :usernameLowercase0))")));
assertThat(ickle.getParameters().entrySet(), hasSize(2));
assertThat(ickle.getParameters(), allOf(hasEntry("realmId0", "realm1"), hasEntry("usernameLowercase0", "a")));
}

View file

@ -958,6 +958,11 @@
<artifactId>infinispan-server-rest</artifactId>
<version>${infinispan.version}</version>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-api</artifactId>
<version>${infinispan.version}</version>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-client-hotrod</artifactId>

View file

@ -502,6 +502,17 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-api</artifactId>
<version>${infinispan.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.ua-parser</groupId>
<artifactId>uap-java</artifactId>

View file

@ -149,6 +149,20 @@ public class UserModelTest extends KeycloakModelTest {
return null;
});
// try to query storage in a separate transaction to make sure that storage can handle case-sensitive usernames
withRealm(realm1Id, (session, realm) -> {
UserModel user1 = session.users().getUserByUsername(realm, "user");
UserModel user2 = session.users().getUserByUsername(realm, "USER");
assertThat(user1, not(nullValue()));
assertThat(user2, not(nullValue()));
assertThat(user1.getUsername(), equalTo("user"));
assertThat(user2.getUsername(), equalTo("USER"));
return null;
});
realm2Id = inComittedTransaction((Function<KeycloakSession, String>) session -> {
RealmModel realm = session.realms().createRealm("realm2");
realm.setDefaultRole(session.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));