Closes #8969 - Add Groups HotRod storage

This commit is contained in:
Michal Hajas 2021-11-30 18:06:19 +01:00 committed by Hynek Mlnařík
parent 8e03942e87
commit 5aa9a09b20
11 changed files with 153 additions and 40 deletions

View file

@ -111,7 +111,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
@Override
public Stream<V> read(QueryParameters<M> queryParameters) {
IckleQueryMapModelCriteriaBuilder<K, V, M> iqmcb = queryParameters.getModelCriteriaBuilder()
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
.flashToModelCriteriaBuilder(createCriteriaBuilder());
String queryString = iqmcb.getIckleQuery();
@ -137,7 +137,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
@Override
public long getCount(QueryParameters<M> queryParameters) {
IckleQueryMapModelCriteriaBuilder<K, V, M> iqmcb = queryParameters.getModelCriteriaBuilder()
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
.flashToModelCriteriaBuilder(createCriteriaBuilder());
String queryString = iqmcb.getIckleQuery();
@ -153,7 +153,7 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
@Override
public long delete(QueryParameters<M> queryParameters) {
IckleQueryMapModelCriteriaBuilder<K, V, M> iqmcb = queryParameters.getModelCriteriaBuilder()
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
.flashToModelCriteriaBuilder(createCriteriaBuilder());
String queryString = "SELECT id " + iqmcb.getIckleQuery();
@ -183,8 +183,8 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends HotRo
return result.get();
}
public IckleQueryMapModelCriteriaBuilder<K, V, M> createCriteriaBuilder() {
return new IckleQueryMapModelCriteriaBuilder<>();
public IckleQueryMapModelCriteriaBuilder<E, M> createCriteriaBuilder() {
return new IckleQueryMapModelCriteriaBuilder<>(storedEntityDescriptor.getEntityTypeClass());
}
@Override

View file

@ -22,8 +22,10 @@ import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.component.AmphibianProviderFactory;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.map.group.MapGroupEntity;
import org.keycloak.models.map.storage.hotRod.client.HotRodClientEntity;
import org.keycloak.models.map.storage.hotRod.client.HotRodClientEntityDelegate;
import org.keycloak.models.map.storage.hotRod.client.HotRodProtocolMapperEntityDelegate;
@ -34,6 +36,8 @@ import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDescriptor;
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
import org.keycloak.models.map.storage.MapStorageProvider;
import org.keycloak.models.map.storage.MapStorageProviderFactory;
import org.keycloak.models.map.storage.hotRod.group.HotRodGroupEntity;
import org.keycloak.models.map.storage.hotRod.group.HotRodGroupEntityDelegate;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import java.util.HashMap;
@ -45,8 +49,9 @@ public class HotRodMapStorageProviderFactory implements AmphibianProviderFactory
private static final Logger LOG = Logger.getLogger(HotRodMapStorageProviderFactory.class);
private final static DeepCloner CLONER = new DeepCloner.Builder()
.constructorDC(MapClientEntity.class, HotRodClientEntityDelegate::new)
.constructor(MapProtocolMapperEntity.class, HotRodProtocolMapperEntityDelegate::new)
.constructorDC(MapClientEntity.class, HotRodClientEntityDelegate::new)
.constructor(MapProtocolMapperEntity.class, HotRodProtocolMapperEntityDelegate::new)
.constructor(MapGroupEntity.class, HotRodGroupEntityDelegate::new)
.build();
public static final Map<Class<?>, HotRodEntityDescriptor<?, ?>> ENTITY_DESCRIPTOR_MAP = new HashMap<>();
@ -56,6 +61,12 @@ public class HotRodMapStorageProviderFactory implements AmphibianProviderFactory
new HotRodEntityDescriptor<>(ClientModel.class,
HotRodClientEntity.class,
HotRodClientEntityDelegate::new));
// Groups descriptor
ENTITY_DESCRIPTOR_MAP.put(GroupModel.class,
new HotRodEntityDescriptor<>(GroupModel.class,
HotRodGroupEntity.class,
HotRodGroupEntityDelegate::new));
}
@Override
@ -95,6 +106,6 @@ public class HotRodMapStorageProviderFactory implements AmphibianProviderFactory
@Override
public String getHelpText() {
return "HotRod client storage";
return "HotRod map storage";
}
}

View file

@ -18,8 +18,9 @@
package org.keycloak.models.map.storage.hotRod;
import org.keycloak.models.ClientModel;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.GroupModel;
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
import org.keycloak.storage.SearchableModelField;
import java.util.Arrays;
@ -32,10 +33,12 @@ import java.util.stream.Collectors;
import static org.keycloak.models.map.storage.hotRod.IckleQueryOperators.C;
import static org.keycloak.models.map.storage.hotRod.IckleQueryOperators.findAvailableNamedParam;
import static org.keycloak.models.map.storage.hotRod.common.ProtoSchemaInitializer.HOT_ROD_ENTITY_PACKAGE;
public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> implements ModelCriteriaBuilder<M, IckleQueryMapModelCriteriaBuilder<K, V, M>> {
public class IckleQueryMapModelCriteriaBuilder<E extends AbstractHotRodEntity, M> implements ModelCriteriaBuilder<M, IckleQueryMapModelCriteriaBuilder<E, M>> {
private static final int INITIAL_BUILDER_CAPACITY = 250;
private final Class<E> hotRodEntityClass;
private final StringBuilder whereClauseBuilder = new StringBuilder(INITIAL_BUILDER_CAPACITY);
private final Map<String, Object> parameters;
public static final Map<SearchableModelField<?>, String> INFINISPAN_NAME_OVERRIDES = new HashMap<>();
@ -43,14 +46,19 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
static {
INFINISPAN_NAME_OVERRIDES.put(ClientModel.SearchableFields.SCOPE_MAPPING_ROLE, "scopeMappings");
INFINISPAN_NAME_OVERRIDES.put(ClientModel.SearchableFields.ATTRIBUTE, "attributes");
INFINISPAN_NAME_OVERRIDES.put(GroupModel.SearchableFields.PARENT_ID, "parentId");
INFINISPAN_NAME_OVERRIDES.put(GroupModel.SearchableFields.ASSIGNED_ROLE, "grantedRoles");
}
public IckleQueryMapModelCriteriaBuilder(StringBuilder whereClauseBuilder, Map<String, Object> parameters) {
public IckleQueryMapModelCriteriaBuilder(Class<E> hotRodEntityClass, StringBuilder whereClauseBuilder, Map<String, Object> parameters) {
this.hotRodEntityClass = hotRodEntityClass;
this.whereClauseBuilder.append(whereClauseBuilder);
this.parameters = parameters;
}
public IckleQueryMapModelCriteriaBuilder() {
public IckleQueryMapModelCriteriaBuilder(Class<E> hotRodEntityClass) {
this.hotRodEntityClass = hotRodEntityClass;
this.parameters = new HashMap<>();
}
@ -63,7 +71,7 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
}
@Override
public IckleQueryMapModelCriteriaBuilder<K, V, M> compare(SearchableModelField<? super M> modelField, Operator op, Object... value) {
public IckleQueryMapModelCriteriaBuilder<E, M> compare(SearchableModelField<? super M> modelField, Operator op, Object... value) {
StringBuilder newBuilder = new StringBuilder(INITIAL_BUILDER_CAPACITY);
newBuilder.append("(");
@ -78,17 +86,17 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
newBuilder.append(")");
}
return new IckleQueryMapModelCriteriaBuilder<>(newBuilder.append(")"), newParameters);
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass, newBuilder.append(")"), newParameters);
}
private StringBuilder joinBuilders(IckleQueryMapModelCriteriaBuilder<K, V, M>[] builders, String delimiter) {
private StringBuilder joinBuilders(IckleQueryMapModelCriteriaBuilder<E, M>[] builders, String delimiter) {
return new StringBuilder(INITIAL_BUILDER_CAPACITY).append("(").append(Arrays.stream(builders)
.map(IckleQueryMapModelCriteriaBuilder::getWhereClauseBuilder)
.filter(IckleQueryMapModelCriteriaBuilder::notEmpty)
.collect(Collectors.joining(delimiter))).append(")");
}
private Map<String, Object> joinParameters(IckleQueryMapModelCriteriaBuilder<K, V, M>[] builders) {
private Map<String, Object> joinParameters(IckleQueryMapModelCriteriaBuilder<E, M>[] builders) {
return Arrays.stream(builders)
.map(IckleQueryMapModelCriteriaBuilder::getParameters)
.map(Map::entrySet)
@ -97,7 +105,7 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
}
@SuppressWarnings("unchecked")
private IckleQueryMapModelCriteriaBuilder<K, V, M>[] resolveNamedQueryConflicts(IckleQueryMapModelCriteriaBuilder<K, V, M>[] builders) {
private IckleQueryMapModelCriteriaBuilder<E, M>[] resolveNamedQueryConflicts(IckleQueryMapModelCriteriaBuilder<E, M>[] builders) {
final Set<String> existingKeys = new HashSet<>();
return Arrays.stream(builders).map(builder -> {
@ -123,36 +131,36 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
}
}
return new IckleQueryMapModelCriteriaBuilder<>(new StringBuilder(newWhereClause), newParameters);
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass, new StringBuilder(newWhereClause), newParameters);
}).toArray(IckleQueryMapModelCriteriaBuilder[]::new);
}
@Override
public IckleQueryMapModelCriteriaBuilder<K, V, M> and(IckleQueryMapModelCriteriaBuilder<K, V, M>... builders) {
public IckleQueryMapModelCriteriaBuilder<E, M> and(IckleQueryMapModelCriteriaBuilder<E, M>... builders) {
if (builders.length == 0) {
return new IckleQueryMapModelCriteriaBuilder<>();
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass);
}
builders = resolveNamedQueryConflicts(builders);
return new IckleQueryMapModelCriteriaBuilder<>(joinBuilders(builders, " AND "),
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass, joinBuilders(builders, " AND "),
joinParameters(builders));
}
@Override
public IckleQueryMapModelCriteriaBuilder<K, V, M> or(IckleQueryMapModelCriteriaBuilder<K, V, M>... builders) {
public IckleQueryMapModelCriteriaBuilder<E, M> or(IckleQueryMapModelCriteriaBuilder<E, M>... builders) {
if (builders.length == 0) {
return new IckleQueryMapModelCriteriaBuilder<>();
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass);
}
builders = resolveNamedQueryConflicts(builders);
return new IckleQueryMapModelCriteriaBuilder<>(joinBuilders(builders, " OR "),
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass, joinBuilders(builders, " OR "),
joinParameters(builders));
}
@Override
public IckleQueryMapModelCriteriaBuilder<K, V, M> not(IckleQueryMapModelCriteriaBuilder<K, V, M> builder) {
public IckleQueryMapModelCriteriaBuilder<E, M> not(IckleQueryMapModelCriteriaBuilder<E, M> builder) {
StringBuilder newBuilder = new StringBuilder(INITIAL_BUILDER_CAPACITY);
StringBuilder originalBuilder = builder.getWhereClauseBuilder();
@ -160,7 +168,7 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
newBuilder.append("not").append(originalBuilder);
}
return new IckleQueryMapModelCriteriaBuilder<>(newBuilder, builder.getParameters());
return new IckleQueryMapModelCriteriaBuilder<>(hotRodEntityClass, newBuilder, builder.getParameters());
}
private StringBuilder getWhereClauseBuilder() {
@ -172,7 +180,7 @@ public class IckleQueryMapModelCriteriaBuilder<K, V extends AbstractEntity, M> i
* @return Ickle query that represents this QueryBuilder
*/
public String getIckleQuery() {
return "FROM org.keycloak.models.map.storage.hotrod.HotRodClientEntity " + C + ((whereClauseBuilder.length() != 0) ? " WHERE " + whereClauseBuilder : "");
return "FROM " + HOT_ROD_ENTITY_PACKAGE + "." + hotRodEntityClass.getSimpleName() + " " + C + ((whereClauseBuilder.length() != 0) ? " WHERE " + whereClauseBuilder : "");
}
/**

View file

@ -112,7 +112,7 @@ public class IckleQueryOperators {
operands = new HashSet<>(Arrays.asList(values));
}
return C + "." + modelField + " IN (" + operands.stream()
return operands.isEmpty() ? "false" : C + "." + modelField + " IN (" + operands.stream()
.map(operand -> {
String namedParam = findAvailableNamedParam(parameters.keySet(), modelField);
parameters.put(namedParam, operand);
@ -149,9 +149,13 @@ public class IckleQueryOperators {
return (modelFieldName, values, parameters) -> {
if (values.length != 1) throw new RuntimeException("Invalid arguments, expected (" + modelFieldName + "), got: " + Arrays.toString(values));
String namedParameter = findAvailableNamedParam(parameters.keySet(), modelFieldName);
if (values[0] == null && op.equals(ModelCriteriaBuilder.Operator.EQ)) {
return C + "." + modelFieldName + " IS NULL";
}
String namedParameter = findAvailableNamedParam(parameters.keySet(), modelFieldName);
parameters.put(namedParameter, values[0]);
return C + "." + modelFieldName + " " + IckleQueryOperators.operatorToString(op) + " :" + namedParameter;
};
}

View file

@ -22,20 +22,29 @@ import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.keycloak.models.map.storage.hotRod.client.HotRodAttributeEntity;
import org.keycloak.models.map.storage.hotRod.client.HotRodClientEntity;
import org.keycloak.models.map.storage.hotRod.client.HotRodProtocolMapperEntity;
import org.keycloak.models.map.storage.hotRod.group.HotRodGroupEntity;
/**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/
@AutoProtoSchemaBuilder(
includeClasses = {
HotRodAttributeEntity.class,
// Clients
HotRodClientEntity.class,
HotRodAttributeEntity.class,
HotRodProtocolMapperEntity.class,
// Groups
HotRodGroupEntity.class,
// Common
HotRodPair.class
},
schemaFileName = "KeycloakHotRodMapStorage.proto",
schemaFilePath = "proto/",
schemaPackageName = "org.keycloak.models.map.storage.hotrod")
schemaPackageName = ProtoSchemaInitializer.HOT_ROD_ENTITY_PACKAGE)
public interface ProtoSchemaInitializer extends GeneratedSchema {
String HOT_ROD_ENTITY_PACKAGE = "kc";
ProtoSchemaInitializer INSTANCE = new ProtoSchemaInitializerImpl();
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2021 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.map.storage.hotRod.group;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.map.annotations.GenerateHotRodEntityImplementation;
import org.keycloak.models.map.common.UpdatableEntity;
import org.keycloak.models.map.group.MapGroupEntity;
import org.keycloak.models.map.storage.hotRod.client.HotRodAttributeEntity;
import org.keycloak.models.map.storage.hotRod.common.AbstractHotRodEntity;
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDelegate;
import java.util.Set;
@GenerateHotRodEntityImplementation(
implementInterface = "org.keycloak.models.map.group.MapGroupEntity",
inherits = "org.keycloak.models.map.storage.hotRod.group.HotRodGroupEntity.AbstractHotRodGroupEntityDelegate"
)
public class HotRodGroupEntity implements AbstractHotRodEntity {
public static abstract class AbstractHotRodGroupEntityDelegate extends UpdatableEntity.Impl implements HotRodEntityDelegate<HotRodGroupEntity>, MapGroupEntity {
@Override
public String getId() {
return getHotRodEntity().id;
}
@Override
public void setId(String id) {
HotRodGroupEntity entity = getHotRodEntity();
if (entity.id != null) throw new IllegalStateException("Id cannot be changed");
entity.id = id;
this.updated |= id != null;
}
}
@ProtoField(number = 1, required = true)
public int entityVersion = 1;
@ProtoField(number = 2, required = true)
public String id;
@ProtoField(number = 3)
public String realmId;
@ProtoField(number = 4)
public String name;
@ProtoField(number = 5)
public String parentId;
@ProtoField(number = 6)
public Set<HotRodAttributeEntity> attributes;
@ProtoField(number = 7)
public Set<String> grantedRoles;
}

View file

@ -6,5 +6,8 @@
<distributed-cache name="clients" mode="SYNC">
<encoding media-type="application/x-protostream"/>
</distributed-cache>
<distributed-cache name="groups" mode="SYNC">
<encoding media-type="application/x-protostream"/>
</distributed-cache>
</cache-container>
</infinispan>

View file

@ -8,5 +8,8 @@
<distributed-cache name="clients" mode="SYNC">
<encoding media-type="application/x-protostream"/>
</distributed-cache>
<distributed-cache name="groups" mode="SYNC">
<encoding media-type="application/x-protostream"/>
</distributed-cache>
</cache-container>
</infinispan>

View file

@ -37,9 +37,9 @@ import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.crit
public class IckleQueryMapModelCriteriaBuilderTest {
@Test
public void testSimpleIckleQuery() {
IckleQueryMapModelCriteriaBuilder<String, HotRodClientEntityDelegate, ClientModel> v = new IckleQueryMapModelCriteriaBuilder<>();
IckleQueryMapModelCriteriaBuilder<String, HotRodClientEntityDelegate, ClientModel> mcb = v.compare(CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, 3);
assertThat(mcb.getIckleQuery(), is(equalTo("FROM org.keycloak.models.map.storage.hotrod.HotRodClientEntity c WHERE (c.clientId = :clientId0)")));
IckleQueryMapModelCriteriaBuilder<HotRodClientEntity, ClientModel> v = new IckleQueryMapModelCriteriaBuilder<>(HotRodClientEntity.class);
IckleQueryMapModelCriteriaBuilder<HotRodClientEntity, ClientModel> mcb = v.compare(CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, 3);
assertThat(mcb.getIckleQuery(), is(equalTo("FROM kc.HotRodClientEntity c WHERE (c.clientId = :clientId0)")));
assertThat(mcb.getParameters().entrySet(), hasSize(1));
assertThat(mcb.getParameters(), hasEntry("clientId0", 3));
@ -47,7 +47,7 @@ public class IckleQueryMapModelCriteriaBuilderTest {
mcb = v.compare(CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, 4)
.compare(ID, ModelCriteriaBuilder.Operator.EQ, 5);
assertThat(mcb.getIckleQuery(), is(equalTo("FROM org.keycloak.models.map.storage.hotrod.HotRodClientEntity c WHERE ((c.clientId = :clientId0) AND (c.id = :id0))")));
assertThat(mcb.getIckleQuery(), is(equalTo("FROM kc.HotRodClientEntity c WHERE ((c.clientId = :clientId0) AND (c.id = :id0))")));
assertThat(mcb.getParameters().entrySet(), hasSize(2));
assertThat(mcb.getParameters(), allOf(hasEntry("clientId0", 4), hasEntry("id0", 5)));
}
@ -56,16 +56,16 @@ public class IckleQueryMapModelCriteriaBuilderTest {
@Test
public void testSimpleIckleQueryFlashedFromDefault() {
DefaultModelCriteria<ClientModel> v = criteria();
IckleQueryMapModelCriteriaBuilder<String, HotRodClientEntityDelegate, ClientModel> mcb = v.compare(CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, 3).flashToModelCriteriaBuilder(new IckleQueryMapModelCriteriaBuilder<>());
assertThat(mcb.getIckleQuery(), is(equalTo("FROM org.keycloak.models.map.storage.hotrod.HotRodClientEntity c WHERE (c.clientId = :clientId0)")));
IckleQueryMapModelCriteriaBuilder<HotRodClientEntity, ClientModel> mcb = v.compare(CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, 3).flashToModelCriteriaBuilder(new IckleQueryMapModelCriteriaBuilder<>(HotRodClientEntity.class));
assertThat(mcb.getIckleQuery(), is(equalTo("FROM kc.HotRodClientEntity c WHERE (c.clientId = :clientId0)")));
assertThat(mcb.getParameters().entrySet(), hasSize(1));
assertThat(mcb.getParameters(), hasEntry("clientId0", 3));
mcb = v.compare(CLIENT_ID, ModelCriteriaBuilder.Operator.EQ, 4)
.compare(ID, ModelCriteriaBuilder.Operator.EQ, 5).flashToModelCriteriaBuilder(new IckleQueryMapModelCriteriaBuilder<>());
.compare(ID, ModelCriteriaBuilder.Operator.EQ, 5).flashToModelCriteriaBuilder(new IckleQueryMapModelCriteriaBuilder<>(HotRodClientEntity.class));
assertThat(mcb.getIckleQuery(), is(equalTo("FROM org.keycloak.models.map.storage.hotrod.HotRodClientEntity c WHERE ((c.clientId = :clientId0) AND (c.id = :id0))")));
assertThat(mcb.getIckleQuery(), is(equalTo("FROM kc.HotRodClientEntity c WHERE ((c.clientId = :clientId0) AND (c.id = :id0))")));
assertThat(mcb.getParameters().entrySet(), hasSize(2));
assertThat(mcb.getParameters(), allOf(hasEntry("clientId0", 4), hasEntry("id0", 5)));
}

View file

@ -1497,6 +1497,7 @@
<configuration>
<systemPropertyVariables>
<keycloak.client.map.storage.provider>hotrod</keycloak.client.map.storage.provider>
<keycloak.group.map.storage.provider>hotrod</keycloak.group.map.storage.provider>
</systemPropertyVariables>
</configuration>
</plugin>

View file

@ -1,9 +1,11 @@
<infinispan>
<cache-container>
<transport stack="udp"/>
<distributed-cache name="clients" mode="SYNC">
<encoding media-type="application/x-protostream"/>
</distributed-cache>
<distributed-cache name="groups" mode="SYNC">
<encoding media-type="application/x-protostream"/>
</distributed-cache>
</cache-container>
</infinispan>