Deletion of all objects when realm is being removed

Closes #11076
This commit is contained in:
vramik 2022-04-01 19:13:09 +02:00 committed by Hynek Mlnařík
parent 29233f33c8
commit 2ecf250e37
38 changed files with 405 additions and 318 deletions

View file

@ -477,16 +477,16 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
ClusterProvider cluster = session.getProvider(ClusterProvider.class); ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.registerListener(REALM_CLEAR_CACHE_EVENTS, (ClusterEvent event) -> { cluster.registerListener(REALM_CLEAR_CACHE_EVENTS, (ClusterEvent event) -> {
if (event instanceof ClearCacheEvent) { if (event instanceof ClearCacheEvent) {
sessionFactory.invalidate(ObjectType._ALL_); sessionFactory.invalidate(null, ObjectType._ALL_);
} }
}); });
cluster.registerListener(REALM_INVALIDATION_EVENTS, (ClusterEvent event) -> { cluster.registerListener(REALM_INVALIDATION_EVENTS, (ClusterEvent event) -> {
if (event instanceof RealmUpdatedEvent) { if (event instanceof RealmUpdatedEvent) {
RealmUpdatedEvent rr = (RealmUpdatedEvent) event; RealmUpdatedEvent rr = (RealmUpdatedEvent) event;
sessionFactory.invalidate(ObjectType.REALM, rr.getId()); sessionFactory.invalidate(null, ObjectType.REALM, rr.getId());
} else if (event instanceof RealmRemovedEvent) { } else if (event instanceof RealmRemovedEvent) {
RealmRemovedEvent rr = (RealmRemovedEvent) event; RealmRemovedEvent rr = (RealmRemovedEvent) event;
sessionFactory.invalidate(ObjectType.REALM, rr.getId()); sessionFactory.invalidate(null, ObjectType.REALM, rr.getId());
} }
}); });
} }

View file

@ -18,7 +18,6 @@ package org.keycloak.models.map.authSession;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.sessions.AuthenticationSessionProviderFactory; import org.keycloak.sessions.AuthenticationSessionProviderFactory;
import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel;
@ -26,15 +25,15 @@ import org.keycloak.sessions.RootAuthenticationSessionModel;
/** /**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a> * @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/ */
public class MapRootAuthenticationSessionProviderFactory extends AbstractMapProviderFactory<AuthenticationSessionProvider, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel> public class MapRootAuthenticationSessionProviderFactory extends AbstractMapProviderFactory<MapRootAuthenticationSessionProvider, MapRootAuthenticationSessionEntity, RootAuthenticationSessionModel>
implements AuthenticationSessionProviderFactory { implements AuthenticationSessionProviderFactory<MapRootAuthenticationSessionProvider> {
public MapRootAuthenticationSessionProviderFactory() { public MapRootAuthenticationSessionProviderFactory() {
super(RootAuthenticationSessionModel.class); super(RootAuthenticationSessionModel.class, MapRootAuthenticationSessionProvider.class);
} }
@Override @Override
public AuthenticationSessionProvider create(KeycloakSession session) { public MapRootAuthenticationSessionProvider createNew(KeycloakSession session) {
return new MapRootAuthenticationSessionProvider(session, getStorage(session)); return new MapRootAuthenticationSessionProvider(session, getStorage(session));
} }

View file

@ -17,21 +17,8 @@
package org.keycloak.models.map.client; package org.keycloak.models.map.client;
import org.jboss.logging.Logger;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientModel.ClientUpdatedEvent;
import org.keycloak.models.ClientModel.SearchableFields;
import org.keycloak.models.ClientProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.map.common.TimeAdapter;
import org.keycloak.models.map.storage.MapKeycloakTransaction;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@ -41,18 +28,30 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jboss.logging.Logger;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientModel.ClientUpdatedEvent;
import org.keycloak.models.ClientModel.SearchableFields;
import org.keycloak.models.ClientProvider;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.map.common.TimeAdapter;
import org.keycloak.models.map.storage.MapKeycloakTransaction;
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorage;
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import org.keycloak.models.ClientScopeModel; import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_AFTER_REMOVE;
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator; import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_BEFORE_REMOVE;
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING; import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria; import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria; import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
import java.util.HashSet;
public class MapClientProvider implements ClientProvider { public class MapClientProvider implements ClientProvider {
private static final Logger LOG = Logger.getLogger(MapClientProvider.class); private static final Logger LOG = Logger.getLogger(MapClientProvider.class);
@ -196,33 +195,19 @@ public class MapClientProvider implements ClientProvider {
@Override @Override
public boolean removeClient(RealmModel realm, String id) { public boolean removeClient(RealmModel realm, String id) {
if (id == null) { if (id == null) return false;
return false;
}
LOG.tracef("removeClient(%s, %s)%s", realm, id, getShortStackTrace()); LOG.tracef("removeClient(%s, %s)%s", realm, id, getShortStackTrace());
// TODO: Sending an event (and client role removal) should be extracted to store layer
final ClientModel client = getClientById(realm, id); final ClientModel client = getClientById(realm, id);
if (client == null) return false; if (client == null) return false;
session.users().preRemove(realm, client);
session.roles().removeRoles(client);
session.getKeycloakSessionFactory().publish(new ClientModel.ClientRemovedEvent() { session.invalidate(CLIENT_BEFORE_REMOVE, realm, client);
@Override
public ClientModel getClient() {
return client;
}
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
});
// TODO: ^^^^^^^ Up to here
tx.delete(id); tx.delete(id);
session.invalidate(CLIENT_AFTER_REMOVE, client);
return true; return true;
} }
@ -374,6 +359,14 @@ public class MapClientProvider implements ClientProvider {
} }
} }
public void preRemove(RealmModel realm) {
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
DefaultModelCriteria<ClientModel> mcb = criteria();
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
tx.delete(withCriteria(mcb));
}
@Override @Override
public void close() { public void close() {

View file

@ -16,72 +16,54 @@
*/ */
package org.keycloak.models.map.client; package org.keycloak.models.map.client;
import org.keycloak.models.ClientModel;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.ClientProvider;
import org.keycloak.models.ClientProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
import org.keycloak.models.RoleModel;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import org.keycloak.models.ClientModel;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.ClientProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.provider.InvalidationHandler;
import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.ROLE_BEFORE_REMOVE;
/** /**
* *
* @author hmlnarik * @author hmlnarik
*/ */
public class MapClientProviderFactory extends AbstractMapProviderFactory<ClientProvider, MapClientEntity, ClientModel> implements ClientProviderFactory, ProviderEventListener { public class MapClientProviderFactory extends AbstractMapProviderFactory<MapClientProvider, MapClientEntity, ClientModel> implements ClientProviderFactory<MapClientProvider>, InvalidationHandler {
private final ConcurrentHashMap<String, ConcurrentMap<String, Long>> REGISTERED_NODES_STORE = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, ConcurrentMap<String, Long>> REGISTERED_NODES_STORE = new ConcurrentHashMap<>();
private Runnable onClose;
public MapClientProviderFactory() { public MapClientProviderFactory() {
super(ClientModel.class); super(ClientModel.class, MapClientProvider.class);
} }
@Override @Override
public void postInit(KeycloakSessionFactory factory) { public MapClientProvider createNew(KeycloakSession session) {
factory.register(this);
onClose = () -> factory.unregister(this);
}
@Override
public MapClientProvider create(KeycloakSession session) {
return new MapClientProvider(session, getStorage(session), REGISTERED_NODES_STORE); return new MapClientProvider(session, getStorage(session), REGISTERED_NODES_STORE);
} }
@Override
public void close() {
super.close();
onClose.run();
}
@Override @Override
public String getHelpText() { public String getHelpText() {
return "Client provider"; return "Client provider";
} }
@Override @Override
public void onEvent(ProviderEvent event) { public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (event instanceof RoleContainerModel.RoleRemovedEvent) { if (type == REALM_BEFORE_REMOVE) {
RoleRemovedEvent e = (RoleContainerModel.RoleRemovedEvent) event; create(session).preRemove((RealmModel) params[0]);
RoleModel role = e.getRole(); } else if (type == ROLE_BEFORE_REMOVE) {
RoleContainerModel container = role.getContainer(); create(session).preRemove((RealmModel) params[0], (RoleModel) params[1]);
RealmModel realm; } else if (type == CLIENT_AFTER_REMOVE) {
if (container instanceof RealmModel) { session.getKeycloakSessionFactory().publish(new ClientModel.ClientRemovedEvent() {
realm = (RealmModel) container; @Override public ClientModel getClient() { return (ClientModel) params[0]; }
} else if (container instanceof ClientModel) { @Override public KeycloakSession getKeycloakSession() { return session; }
realm = ((ClientModel) container).getRealm(); });
} else {
return;
}
((MapClientProvider) e.getKeycloakSession().getProvider(ClientProvider.class)).preRemove(realm, role);
} }
} }
} }

View file

@ -23,7 +23,6 @@ import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import org.keycloak.models.ClientScopeModel.SearchableFields; import org.keycloak.models.ClientScopeModel.SearchableFields;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.ClientScopeProvider; import org.keycloak.models.ClientScopeProvider;
@ -36,6 +35,9 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria; import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_SCOPE_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_SCOPE_BEFORE_REMOVE;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING; import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria; import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria; import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
@ -106,23 +108,12 @@ public class MapClientScopeProvider implements ClientScopeProvider {
ClientScopeModel clientScope = getClientScopeById(realm, id); ClientScopeModel clientScope = getClientScopeById(realm, id);
if (clientScope == null) return false; if (clientScope == null) return false;
session.users().preRemove(clientScope); session.invalidate(CLIENT_SCOPE_BEFORE_REMOVE, realm, clientScope);
realm.removeDefaultClientScope(clientScope);
session.getKeycloakSessionFactory().publish(new ClientScopeModel.ClientScopeRemovedEvent() {
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
@Override
public ClientScopeModel getClientScope() {
return clientScope;
}
});
tx.delete(id); tx.delete(id);
session.invalidate(CLIENT_SCOPE_AFTER_REMOVE, clientScope);
return true; return true;
} }
@ -150,6 +141,14 @@ public class MapClientScopeProvider implements ClientScopeProvider {
: entityToAdapterFunc(realm).apply(entity); : entityToAdapterFunc(realm).apply(entity);
} }
public void preRemove(RealmModel realm) {
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
DefaultModelCriteria<ClientScopeModel> mcb = criteria();
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
tx.delete(withCriteria(mcb));
}
@Override @Override
public void close() { public void close() {
} }

View file

@ -17,19 +17,24 @@
package org.keycloak.models.map.clientscope; package org.keycloak.models.map.clientscope;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.ClientScopeProvider;
import org.keycloak.models.ClientScopeProviderFactory; import org.keycloak.models.ClientScopeProviderFactory;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.provider.InvalidationHandler;
public class MapClientScopeProviderFactory extends AbstractMapProviderFactory<ClientScopeProvider, MapClientScopeEntity, ClientScopeModel> implements ClientScopeProviderFactory { import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_SCOPE_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_SCOPE_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
public class MapClientScopeProviderFactory extends AbstractMapProviderFactory<MapClientScopeProvider, MapClientScopeEntity, ClientScopeModel> implements ClientScopeProviderFactory<MapClientScopeProvider>, InvalidationHandler {
public MapClientScopeProviderFactory() { public MapClientScopeProviderFactory() {
super(ClientScopeModel.class); super(ClientScopeModel.class, MapClientScopeProvider.class);
} }
@Override @Override
public ClientScopeProvider create(KeycloakSession session) { public MapClientScopeProvider createNew(KeycloakSession session) {
return new MapClientScopeProvider(session, getStorage(session)); return new MapClientScopeProvider(session, getStorage(session));
} }
@ -37,4 +42,18 @@ public class MapClientScopeProviderFactory extends AbstractMapProviderFactory<Cl
public String getHelpText() { public String getHelpText() {
return "Client scope provider"; return "Client scope provider";
} }
@Override
public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (type == REALM_BEFORE_REMOVE) {
create(session).preRemove((RealmModel) params[0]);
} else if (type == CLIENT_SCOPE_BEFORE_REMOVE) {
((RealmModel) params[0]).removeDefaultClientScope((ClientScopeModel) params[1]);
} else if (type == CLIENT_SCOPE_AFTER_REMOVE) {
session.getKeycloakSessionFactory().publish(new ClientScopeModel.ClientScopeRemovedEvent() {
@Override public ClientScopeModel getClientScope() { return (ClientScopeModel) params[0]; }
@Override public KeycloakSession getKeycloakSession() { return session; }
});
}
}
} }

View file

@ -16,6 +16,7 @@
*/ */
package org.keycloak.models.map.common; package org.keycloak.models.map.common;
import java.util.concurrent.atomic.AtomicInteger;
import org.keycloak.Config.Scope; import org.keycloak.Config.Scope;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -25,9 +26,11 @@ import org.keycloak.models.map.storage.MapStorageSpi;
import org.keycloak.component.AmphibianProviderFactory; import org.keycloak.component.AmphibianProviderFactory;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.provider.InvalidationHandler;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory; import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory;
/** /**
@ -42,13 +45,59 @@ public abstract class AbstractMapProviderFactory<T extends Provider, V extends A
protected final Logger LOG = Logger.getLogger(getClass()); protected final Logger LOG = Logger.getLogger(getClass());
public static final AtomicInteger uniqueCounter = new AtomicInteger();
private final String uniqueKey = getClass().getName() + uniqueCounter.incrementAndGet();
protected final Class<M> modelType; protected final Class<M> modelType;
private final Class<T> providerType;
private Scope storageConfigScope; private Scope storageConfigScope;
@SuppressWarnings("unchecked") protected AbstractMapProviderFactory(Class<M> modelType, Class<T> providerType) {
protected AbstractMapProviderFactory(Class<M> modelType) {
this.modelType = modelType; this.modelType = modelType;
this.providerType = providerType;
}
public enum MapProviderObjectType implements InvalidationHandler.InvalidableObjectType {
CLIENT_BEFORE_REMOVE,
CLIENT_AFTER_REMOVE,
CLIENT_SCOPE_BEFORE_REMOVE,
CLIENT_SCOPE_AFTER_REMOVE,
GROUP_BEFORE_REMOVE,
GROUP_AFTER_REMOVE,
REALM_BEFORE_REMOVE,
REALM_AFTER_REMOVE,
ROLE_BEFORE_REMOVE,
ROLE_AFTER_REMOVE,
USER_BEFORE_REMOVE,
USER_AFTER_REMOVE
}
/**
* Creates new instance of a provider.
*
* @param session
* @return See description.
*/
public abstract T createNew(KeycloakSession session);
/**
* Returns instance of a provider. If the instance is already created within
* the session (it's found in session attributes), it's returned from there,
* otherwise new instance is created (and stored among the session attributes).
*
* @param session
* @return See description.
*/
@Override
public T create(KeycloakSession session) {
T provider = session.getAttribute(uniqueKey, providerType);
if (provider != null) {
return provider;
}
provider = createNew(session);
session.setAttribute(uniqueKey, provider);
return provider;
} }
@Override @Override

View file

@ -36,10 +36,11 @@ import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.GROUP_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.GROUP_BEFORE_REMOVE;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING; import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria; import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria; import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
@ -214,34 +215,12 @@ public class MapGroupProvider implements GroupProvider {
LOG.tracef("removeGroup(%s, %s)%s", realm, group, getShortStackTrace()); LOG.tracef("removeGroup(%s, %s)%s", realm, group, getShortStackTrace());
if (group == null) return false; if (group == null) return false;
// TODO: Sending an event (, user group removal and realm default groups) should be extracted to store layer session.invalidate(GROUP_BEFORE_REMOVE, realm, group);
session.getKeycloakSessionFactory().publish(new GroupModel.GroupRemovedEvent() {
@Override
public RealmModel getRealm() {
return realm;
}
@Override
public GroupModel getGroup() {
return group;
}
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
});
session.users().preRemove(realm, group);
realm.removeDefaultGroup(group);
group.getSubGroupsStream().collect(Collectors.toSet()).forEach(subGroup -> session.groups().removeGroup(realm, subGroup));
// TODO: ^^^^^^^ Up to here
tx.delete(group.getId()); tx.delete(group.getId());
session.invalidate(GROUP_AFTER_REMOVE, realm, group);
return true; return true;
} }
@ -306,9 +285,16 @@ public class MapGroupProvider implements GroupProvider {
} }
} }
public void preRemove(RealmModel realm) {
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
DefaultModelCriteria<GroupModel> mcb = criteria();
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
tx.delete(withCriteria(mcb));
}
@Override @Override
public void close() { public void close() {
} }
} }

View file

@ -16,70 +16,58 @@
*/ */
package org.keycloak.models.map.group; package org.keycloak.models.map.group;
import org.keycloak.models.ClientModel; import java.util.stream.Collectors;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.GroupProvider;
import org.keycloak.models.GroupProviderFactory; import org.keycloak.models.GroupProviderFactory;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.provider.InvalidationHandler;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.GROUP_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.GROUP_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.ROLE_BEFORE_REMOVE;
/** /**
* *
* @author mhajas * @author mhajas
*/ */
public class MapGroupProviderFactory extends AbstractMapProviderFactory<GroupProvider, MapGroupEntity, GroupModel> implements GroupProviderFactory, ProviderEventListener { public class MapGroupProviderFactory extends AbstractMapProviderFactory<MapGroupProvider, MapGroupEntity, GroupModel> implements GroupProviderFactory<MapGroupProvider>, InvalidationHandler {
private Runnable onClose;
public MapGroupProviderFactory() { public MapGroupProviderFactory() {
super(GroupModel.class); super(GroupModel.class, MapGroupProvider.class);
} }
@Override @Override
public void postInit(KeycloakSessionFactory factory) { public MapGroupProvider createNew(KeycloakSession session) {
factory.register(this);
onClose = () -> factory.unregister(this);
}
@Override
public MapGroupProvider create(KeycloakSession session) {
return new MapGroupProvider(session, getStorage(session)); return new MapGroupProvider(session, getStorage(session));
} }
@Override
public void close() {
super.close();
onClose.run();
}
@Override @Override
public String getHelpText() { public String getHelpText() {
return "Group provider"; return "Group provider";
} }
@Override @Override
public void onEvent(ProviderEvent event) { public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (event instanceof RoleContainerModel.RoleRemovedEvent) { if (type == REALM_BEFORE_REMOVE) {
RoleRemovedEvent e = (RoleContainerModel.RoleRemovedEvent) event; create(session).preRemove((RealmModel) params[0]);
RoleModel role = e.getRole(); } else if (type == ROLE_BEFORE_REMOVE) {
RoleContainerModel container = role.getContainer(); create(session).preRemove((RealmModel) params[0], (RoleModel) params[1]);
RealmModel realm; } else if (type == GROUP_BEFORE_REMOVE) {
if (container instanceof RealmModel) { RealmModel realm = (RealmModel) params[0];
realm = (RealmModel) container; GroupModel group = (GroupModel) params[1];
} else if (container instanceof ClientModel) {
realm = ((ClientModel) container).getRealm(); realm.removeDefaultGroup(group);
} else { group.getSubGroupsStream().collect(Collectors.toSet()).forEach(subGroup -> create(session).removeGroup(realm, subGroup));
return; } else if (type == GROUP_AFTER_REMOVE) {
} session.getKeycloakSessionFactory().publish(new GroupModel.GroupRemovedEvent() {
((MapGroupProvider) e.getKeycloakSession().getProvider(GroupProvider.class)).preRemove(realm, role); @Override public RealmModel getRealm() { return (RealmModel) params[0]; }
@Override public GroupModel getGroup() { return (GroupModel) params[1]; }
@Override public KeycloakSession getKeycloakSession() { return session; }
});
} }
} }
} }

View file

@ -17,43 +17,28 @@
package org.keycloak.models.map.loginFailure; package org.keycloak.models.map.loginFailure;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserLoginFailureProviderFactory; import org.keycloak.models.UserLoginFailureProviderFactory;
import org.keycloak.models.UserLoginFailureModel; import org.keycloak.models.UserLoginFailureModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.InvalidationHandler;
import org.keycloak.provider.ProviderEventListener;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.USER_BEFORE_REMOVE;
/** /**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a> * @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/ */
public class MapUserLoginFailureProviderFactory extends AbstractMapProviderFactory<UserLoginFailureProvider, MapUserLoginFailureEntity, UserLoginFailureModel> public class MapUserLoginFailureProviderFactory extends AbstractMapProviderFactory<MapUserLoginFailureProvider, MapUserLoginFailureEntity, UserLoginFailureModel>
implements UserLoginFailureProviderFactory, ProviderEventListener { implements UserLoginFailureProviderFactory<MapUserLoginFailureProvider>, InvalidationHandler {
private Runnable onClose;
public MapUserLoginFailureProviderFactory() { public MapUserLoginFailureProviderFactory() {
super(UserLoginFailureModel.class); super(UserLoginFailureModel.class, MapUserLoginFailureProvider.class);
} }
@Override @Override
public void postInit(KeycloakSessionFactory factory) { public MapUserLoginFailureProvider createNew(KeycloakSession session) {
factory.register(this);
onClose = () -> factory.unregister(this);
}
@Override
public void close() {
super.close();
onClose.run();
}
@Override
public MapUserLoginFailureProvider create(KeycloakSession session) {
return new MapUserLoginFailureProvider(session, getStorage(session)); return new MapUserLoginFailureProvider(session, getStorage(session));
} }
@ -63,17 +48,11 @@ public class MapUserLoginFailureProviderFactory extends AbstractMapProviderFacto
} }
@Override @Override
public void onEvent(ProviderEvent event) { public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (event instanceof UserModel.UserRemovedEvent) { if (type == REALM_BEFORE_REMOVE) {
UserModel.UserRemovedEvent userRemovedEvent = (UserModel.UserRemovedEvent) event; create(session).removeAllUserLoginFailures((RealmModel) params[0]);
} else if (type == USER_BEFORE_REMOVE) {
MapUserLoginFailureProvider provider = MapUserLoginFailureProviderFactory.this.create(userRemovedEvent.getKeycloakSession()); create(session).removeUserLoginFailure((RealmModel) params[0], ((UserModel) params[1]).getId());
provider.removeUserLoginFailure(userRemovedEvent.getRealm(), userRemovedEvent.getUser().getId());
} else if (event instanceof RealmModel.RealmRemovedEvent) {
RealmModel.RealmRemovedEvent realmRemovedEvent = (RealmModel.RealmRemovedEvent) event;
MapUserLoginFailureProvider provider = MapUserLoginFailureProviderFactory.this.create(realmRemovedEvent.getKeycloakSession());
provider.removeAllUserLoginFailures(realmRemovedEvent.getRealm());
} }
} }

View file

@ -22,7 +22,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
@ -37,6 +36,10 @@ import org.keycloak.models.map.storage.MapStorage;
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator; import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria; import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING; import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria; import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria; import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
@ -135,27 +138,12 @@ public class MapRealmProvider implements RealmProvider {
if (realm == null) return false; if (realm == null) return false;
session.users().preRemove(realm); session.invalidate(REALM_BEFORE_REMOVE, realm);
session.clients().removeClients(realm);
session.clientScopes().removeClientScopes(realm);
session.roles().removeRoles(realm);
realm.getTopLevelGroupsStream().forEach(realm::removeGroup);
// TODO: Sending an event should be extracted to store layer
session.getKeycloakSessionFactory().publish(new RealmModel.RealmRemovedEvent() {
@Override
public RealmModel getRealm() {
return realm;
}
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
});
// TODO: ^^^^^^^ Up to here
tx.delete(id); tx.delete(id);
session.invalidate(REALM_AFTER_REMOVE, realm);
return true; return true;
} }

View file

@ -19,22 +19,34 @@ package org.keycloak.models.map.realm;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmProviderFactory; import org.keycloak.models.RealmProviderFactory;
import org.keycloak.provider.InvalidationHandler;
public class MapRealmProviderFactory extends AbstractMapProviderFactory<RealmProvider, MapRealmEntity, RealmModel> implements RealmProviderFactory { import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_AFTER_REMOVE;
public class MapRealmProviderFactory extends AbstractMapProviderFactory<MapRealmProvider, MapRealmEntity, RealmModel> implements RealmProviderFactory<MapRealmProvider>, InvalidationHandler {
public MapRealmProviderFactory() { public MapRealmProviderFactory() {
super(RealmModel.class); super(RealmModel.class, MapRealmProvider.class);
} }
@Override @Override
public RealmProvider create(KeycloakSession session) { public MapRealmProvider createNew(KeycloakSession session) {
return new MapRealmProvider(session, getStorage(session)); return new MapRealmProvider(session, getStorage(session));
} }
@Override @Override
public String getHelpText() { public String getHelpText() {
return "Realm provider"; return "Realm provider";
} }
@Override
public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (type == REALM_AFTER_REMOVE) {
session.getKeycloakSessionFactory().publish(new RealmModel.RealmRemovedEvent() {
@Override public RealmModel getRealm() { return (RealmModel) params[0]; }
@Override public KeycloakSession getKeycloakSession() { return session; }
});
}
}
} }

View file

@ -17,30 +17,29 @@
package org.keycloak.models.map.role; package org.keycloak.models.map.role;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.map.storage.MapKeycloakTransaction; import org.keycloak.models.map.storage.MapKeycloakTransaction;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorage;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel.SearchableFields; import org.keycloak.models.RoleModel.SearchableFields;
import org.keycloak.models.RoleProvider; import org.keycloak.models.RoleProvider;
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator; import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria; import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.ROLE_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.ROLE_BEFORE_REMOVE;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
public class MapRoleProvider implements RoleProvider { public class MapRoleProvider implements RoleProvider {
private static final Logger LOG = Logger.getLogger(MapRoleProvider.class); private static final Logger LOG = Logger.getLogger(MapRoleProvider.class);
@ -161,24 +160,12 @@ public class MapRoleProvider implements RoleProvider {
RealmModel realm = role.isClientRole() ? ((ClientModel)role.getContainer()).getRealm() : (RealmModel)role.getContainer(); RealmModel realm = role.isClientRole() ? ((ClientModel)role.getContainer()).getRealm() : (RealmModel)role.getContainer();
session.users().preRemove(realm, role); session.invalidate(ROLE_BEFORE_REMOVE, realm, role);
// TODO: Sending an event should be extracted to store layer
session.getKeycloakSessionFactory().publish(new RoleContainerModel.RoleRemovedEvent() {
@Override
public RoleModel getRole() {
return role;
}
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
});
// TODO: ^^^^^^^ Up to here
tx.delete(role.getId()); tx.delete(role.getId());
session.invalidate(ROLE_AFTER_REMOVE, realm, role);
return true; return true;
} }
@ -284,6 +271,14 @@ public class MapRoleProvider implements RoleProvider {
.map(entityToAdapterFunc(client.getRealm())); .map(entityToAdapterFunc(client.getRealm()));
} }
public void preRemove(RealmModel realm) {
LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
DefaultModelCriteria<RoleModel> mcb = criteria();
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
tx.delete(withCriteria(mcb));
}
@Override @Override
public void close() { public void close() {
} }

View file

@ -16,20 +16,27 @@
*/ */
package org.keycloak.models.map.role; package org.keycloak.models.map.role;
import org.keycloak.models.ClientModel;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.RoleProvider;
import org.keycloak.models.RoleProviderFactory; import org.keycloak.models.RoleProviderFactory;
import org.keycloak.provider.InvalidationHandler;
public class MapRoleProviderFactory extends AbstractMapProviderFactory<RoleProvider, MapRoleEntity, RoleModel> implements RoleProviderFactory { import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.ROLE_AFTER_REMOVE;
public class MapRoleProviderFactory extends AbstractMapProviderFactory<MapRoleProvider, MapRoleEntity, RoleModel> implements RoleProviderFactory<MapRoleProvider>, InvalidationHandler {
public MapRoleProviderFactory() { public MapRoleProviderFactory() {
super(RoleModel.class); super(RoleModel.class, MapRoleProvider.class);
} }
@Override @Override
public RoleProvider create(KeycloakSession session) { public MapRoleProvider createNew(KeycloakSession session) {
return new MapRoleProvider(session, getStorage(session)); return new MapRoleProvider(session, getStorage(session));
} }
@ -37,4 +44,18 @@ public class MapRoleProviderFactory extends AbstractMapProviderFactory<RoleProvi
public String getHelpText() { public String getHelpText() {
return "Role provider"; return "Role provider";
} }
@Override
public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (type == REALM_BEFORE_REMOVE) {
create(session).preRemove((RealmModel) params[0]);
} else if (type == CLIENT_BEFORE_REMOVE) {
create(session).removeRoles((ClientModel) params[1]);
} else if (type == ROLE_AFTER_REMOVE) {
session.getKeycloakSessionFactory().publish(new RoleContainerModel.RoleRemovedEvent() {
@Override public RoleModel getRole() { return (RoleModel) params[1]; }
@Override public KeycloakSession getKeycloakSession() { return session; }
});
}
}
} }

View file

@ -72,6 +72,8 @@ import static org.keycloak.models.UserModel.EMAIL_VERIFIED;
import static org.keycloak.models.UserModel.FIRST_NAME; import static org.keycloak.models.UserModel.FIRST_NAME;
import static org.keycloak.models.UserModel.LAST_NAME; import static org.keycloak.models.UserModel.LAST_NAME;
import static org.keycloak.models.UserModel.USERNAME; import static org.keycloak.models.UserModel.USERNAME;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.USER_AFTER_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.USER_BEFORE_REMOVE;
import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING; import static org.keycloak.models.map.storage.QueryParameters.Order.ASCENDING;
import static org.keycloak.models.map.storage.QueryParameters.withCriteria; import static org.keycloak.models.map.storage.QueryParameters.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria; import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
@ -727,7 +729,11 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
String userId = user.getId(); String userId = user.getId();
Optional<MapUserEntity> userById = getEntityById(realm, userId); Optional<MapUserEntity> userById = getEntityById(realm, userId);
if (userById.isPresent()) { if (userById.isPresent()) {
session.invalidate(USER_BEFORE_REMOVE, realm, user);
tx.delete(userId); tx.delete(userId);
session.invalidate(USER_AFTER_REMOVE, realm, user);
return true; return true;
} }

View file

@ -17,24 +17,35 @@
package org.keycloak.models.map.user; package org.keycloak.models.map.user;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserProviderFactory; import org.keycloak.models.UserProviderFactory;
import org.keycloak.models.map.common.AbstractMapProviderFactory; import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.provider.InvalidationHandler;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_SCOPE_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.GROUP_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.ROLE_BEFORE_REMOVE;
/** /**
* *
* @author mhajas * @author mhajas
*/ */
public class MapUserProviderFactory extends AbstractMapProviderFactory<UserProvider, MapUserEntity, UserModel> implements UserProviderFactory { public class MapUserProviderFactory extends AbstractMapProviderFactory<MapUserProvider, MapUserEntity, UserModel> implements UserProviderFactory<MapUserProvider>, InvalidationHandler {
public MapUserProviderFactory() { public MapUserProviderFactory() {
super(UserModel.class); super(UserModel.class, MapUserProvider.class);
} }
@Override @Override
public UserProvider create(KeycloakSession session) { public MapUserProvider createNew(KeycloakSession session) {
return new MapUserProvider(session, getStorage(session)); return new MapUserProvider(session, getStorage(session));
} }
@ -43,4 +54,18 @@ public class MapUserProviderFactory extends AbstractMapProviderFactory<UserProvi
return "User provider"; return "User provider";
} }
@Override
public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (type == REALM_BEFORE_REMOVE) {
create(session).preRemove((RealmModel) params[0]);
} else if (type == ROLE_BEFORE_REMOVE) {
create(session).preRemove((RealmModel) params[0], (RoleModel) params[1]);
} else if (type == CLIENT_SCOPE_BEFORE_REMOVE) {
create(session).preRemove((ClientScopeModel) params[1]);
} else if (type == CLIENT_BEFORE_REMOVE) {
create(session).preRemove((RealmModel) params[0], (ClientModel) params[1]);
} else if (type == GROUP_BEFORE_REMOVE) {
create(session).preRemove((RealmModel) params[0], (GroupModel) params[1]);
}
}
} }

View file

@ -22,6 +22,7 @@ import org.keycloak.component.AmphibianProviderFactory;
import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider; import org.keycloak.models.UserSessionProvider;
@ -30,27 +31,28 @@ import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorage;
import org.keycloak.models.map.storage.MapStorageProvider; import org.keycloak.models.map.storage.MapStorageProvider;
import org.keycloak.models.map.storage.MapStorageProviderFactory; import org.keycloak.models.map.storage.MapStorageProviderFactory;
import org.keycloak.models.map.storage.MapStorageSpi; import org.keycloak.models.map.storage.MapStorageSpi;
import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.InvalidationHandler;
import org.keycloak.provider.ProviderEventListener;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.USER_BEFORE_REMOVE;
import static org.keycloak.models.map.common.AbstractMapProviderFactory.uniqueCounter;
import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory; import static org.keycloak.models.utils.KeycloakModelUtils.getComponentFactory;
/** /**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a> * @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/ */
public class MapUserSessionProviderFactory<UK, CK> implements AmphibianProviderFactory<UserSessionProvider>, UserSessionProviderFactory, ProviderEventListener, EnvironmentDependentProviderFactory { public class MapUserSessionProviderFactory<UK, CK> implements AmphibianProviderFactory<UserSessionProvider>, UserSessionProviderFactory, EnvironmentDependentProviderFactory, InvalidationHandler {
public static final String CONFIG_STORAGE_USER_SESSIONS = "storage-user-sessions"; public static final String CONFIG_STORAGE_USER_SESSIONS = "storage-user-sessions";
public static final String CONFIG_STORAGE_CLIENT_SESSIONS = "storage-client-sessions"; public static final String CONFIG_STORAGE_CLIENT_SESSIONS = "storage-client-sessions";
public static final String PROVIDER_ID = AbstractMapProviderFactory.PROVIDER_ID; public static final String PROVIDER_ID = AbstractMapProviderFactory.PROVIDER_ID;
private final String uniqueKey = getClass().getName() + uniqueCounter.incrementAndGet();
private Scope storageConfigScopeUserSessions; private Scope storageConfigScopeUserSessions;
private Scope storageConfigScopeClientSessions; private Scope storageConfigScopeClientSessions;
private Runnable onClose;
@Override @Override
public String getId() { public String getId() {
return PROVIDER_ID; return PROVIDER_ID;
@ -64,14 +66,11 @@ public class MapUserSessionProviderFactory<UK, CK> implements AmphibianProviderF
@Override @Override
public void postInit(KeycloakSessionFactory factory) { public void postInit(KeycloakSessionFactory factory) {
factory.register(this);
onClose = () -> factory.unregister(this);
} }
@Override @Override
public void close() { public void close() {
AmphibianProviderFactory.super.close(); AmphibianProviderFactory.super.close();
onClose.run();
} }
@Override @Override
@ -79,7 +78,12 @@ public class MapUserSessionProviderFactory<UK, CK> implements AmphibianProviderF
} }
@Override @Override
@SuppressWarnings("unchecked")
public MapUserSessionProvider create(KeycloakSession session) { public MapUserSessionProvider create(KeycloakSession session) {
MapUserSessionProvider provider = session.getAttribute(uniqueKey, MapUserSessionProvider.class);
if (provider != null) return provider;
MapStorageProviderFactory storageProviderFactoryUs = (MapStorageProviderFactory) getComponentFactory(session.getKeycloakSessionFactory(), MapStorageProviderFactory storageProviderFactoryUs = (MapStorageProviderFactory) getComponentFactory(session.getKeycloakSessionFactory(),
MapStorageProvider.class, storageConfigScopeUserSessions, MapStorageSpi.NAME); MapStorageProvider.class, storageConfigScopeUserSessions, MapStorageSpi.NAME);
final MapStorageProvider factoryUs = storageProviderFactoryUs.create(session); final MapStorageProvider factoryUs = storageProviderFactoryUs.create(session);
@ -90,7 +94,9 @@ public class MapUserSessionProviderFactory<UK, CK> implements AmphibianProviderF
final MapStorageProvider factoryCs = storageProviderFactoryCs.create(session); final MapStorageProvider factoryCs = storageProviderFactoryCs.create(session);
MapStorage clientSessionStore = factoryCs.getStorage(AuthenticatedClientSessionModel.class); MapStorage clientSessionStore = factoryCs.getStorage(AuthenticatedClientSessionModel.class);
return new MapUserSessionProvider(session, userSessionStore, clientSessionStore); provider = new MapUserSessionProvider(session, userSessionStore, clientSessionStore);
session.setAttribute(uniqueKey, provider);
return provider;
} }
@Override @Override
@ -99,12 +105,9 @@ public class MapUserSessionProviderFactory<UK, CK> implements AmphibianProviderF
} }
@Override @Override
public void onEvent(ProviderEvent event) { public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
if (event instanceof UserModel.UserRemovedEvent) { if (type == USER_BEFORE_REMOVE) {
UserModel.UserRemovedEvent userRemovedEvent = (UserModel.UserRemovedEvent) event; create(session).removeUserSessions((RealmModel) params[0], (UserModel) params[1]);
MapUserSessionProvider provider = MapUserSessionProviderFactory.this.create(userRemovedEvent.getKeycloakSession());
provider.removeUserSessions(userRemovedEvent.getRealm(), userRemovedEvent.getUser());
} }
} }

View file

@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
public interface ClientProviderFactory extends ProviderFactory<ClientProvider> { public interface ClientProviderFactory<T extends ClientProvider> extends ProviderFactory<T> {
} }

View file

@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
public interface ClientScopeProviderFactory extends ProviderFactory<ClientScopeProvider> { public interface ClientScopeProviderFactory<T extends ClientScopeProvider> extends ProviderFactory<T> {
} }

View file

@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
public interface GroupProviderFactory extends ProviderFactory<GroupProvider> { public interface GroupProviderFactory<T extends GroupProvider> extends ProviderFactory<T> {
} }

View file

@ -23,5 +23,5 @@ import org.keycloak.provider.ProviderFactory;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface RealmProviderFactory extends ProviderFactory<RealmProvider> { public interface RealmProviderFactory<T extends RealmProvider> extends ProviderFactory<T> {
} }

View file

@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
public interface RoleProviderFactory extends ProviderFactory<RoleProvider> { public interface RoleProviderFactory<T extends RoleProvider> extends ProviderFactory<T> {
} }

View file

@ -21,6 +21,6 @@ import org.keycloak.provider.ProviderFactory;
/** /**
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a> * @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
*/ */
public interface UserLoginFailureProviderFactory extends ProviderFactory<UserLoginFailureProvider> { public interface UserLoginFailureProviderFactory<T extends UserLoginFailureProvider> extends ProviderFactory<T> {
} }

View file

@ -23,5 +23,5 @@ import org.keycloak.provider.ProviderFactory;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface UserProviderFactory extends ProviderFactory<UserProvider> { public interface UserProviderFactory<T extends UserProvider> extends ProviderFactory<T> {
} }

View file

@ -22,5 +22,5 @@ import org.keycloak.provider.ProviderFactory;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public interface AuthenticationSessionProviderFactory extends ProviderFactory<AuthenticationSessionProvider> { public interface AuthenticationSessionProviderFactory<T extends AuthenticationSessionProvider> extends ProviderFactory<T> {
} }

View file

@ -19,7 +19,7 @@ package org.keycloak.models;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.cache.UserCache; import org.keycloak.models.cache.UserCache;
import org.keycloak.provider.InvalidationHandler; import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import org.keycloak.services.clientpolicy.ClientPolicyManager; import org.keycloak.services.clientpolicy.ClientPolicyManager;
import org.keycloak.sessions.AuthenticationSessionProvider; import org.keycloak.sessions.AuthenticationSessionProvider;
@ -33,7 +33,7 @@ import java.util.function.Function;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface KeycloakSession extends InvalidationHandler { public interface KeycloakSession {
KeycloakContext getContext(); KeycloakContext getContext();
@ -128,10 +128,9 @@ public interface KeycloakSession extends InvalidationHandler {
/** /**
* Invalidates intermediate states of the given objects, both immediately and at the end of this session. * Invalidates intermediate states of the given objects, both immediately and at the end of this session.
* @param type Type of the objects to invalidate * @param type Type of the objects to invalidate
* @param ids Identifiers of the invalidated objects * @param params Parameters used for the invalidation
*/ */
@Override void invalidate(InvalidableObjectType type, Object... params);
void invalidate(InvalidableObjectType type, Object... ids);
void enlistForClose(Provider provider); void enlistForClose(Provider provider);

View file

@ -29,11 +29,9 @@ import org.keycloak.storage.client.ClientStorageProvider;
import org.keycloak.storage.client.ClientStorageProviderModel; import org.keycloak.storage.client.ClientStorageProviderModel;
import org.keycloak.storage.role.RoleStorageProvider; import org.keycloak.storage.role.RoleStorageProvider;
import org.keycloak.storage.role.RoleStorageProviderModel; import org.keycloak.storage.role.RoleStorageProviderModel;
import org.keycloak.utils.StringUtil;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;

View file

@ -16,6 +16,8 @@
*/ */
package org.keycloak.provider; package org.keycloak.provider;
import org.keycloak.models.KeycloakSession;
/** /**
* Handles invalidation requests. This interface is specifically implemented by * Handles invalidation requests. This interface is specifically implemented by
* providers that implement a cache of objects that might change in the outside. * providers that implement a cache of objects that might change in the outside.
@ -40,9 +42,10 @@ public interface InvalidationHandler {
/** /**
* Invalidates intermediate states of the given objects * Invalidates intermediate states of the given objects
* @param session KeycloakSession
* @param type Type of the objects to invalidate * @param type Type of the objects to invalidate
* @param ids Identifiers of the invalidated objects * @param params Parameters used for the invalidation
*/ */
void invalidate(InvalidableObjectType type, Object... ids); void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params);
} }

View file

@ -23,6 +23,7 @@ import org.keycloak.common.util.StackUtil;
import org.keycloak.component.ComponentFactoryProviderFactory; import org.keycloak.component.ComponentFactoryProviderFactory;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.component.ComponentModelScope; import org.keycloak.component.ComponentModelScope;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.InvalidationHandler; import org.keycloak.provider.InvalidationHandler;
@ -155,7 +156,7 @@ public class DefaultComponentFactoryProviderFactory implements ComponentFactoryP
} }
@Override @Override
public void invalidate(InvalidableObjectType type, Object... ids) { public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... ids) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debugf("Invalidating %s: %s", type, Arrays.asList(ids)); LOG.debugf("Invalidating %s: %s", type, Arrays.asList(ids));
} }
@ -169,25 +170,25 @@ public class DefaultComponentFactoryProviderFactory implements ComponentFactoryP
Stream.of(ids) Stream.of(ids)
.map(componentsMap.get()::remove).filter(Objects::nonNull) .map(componentsMap.get()::remove).filter(Objects::nonNull)
.forEach(ProviderFactory::close); .forEach(ProviderFactory::close);
propagateInvalidation(componentsMap.get(), type, ids); propagateInvalidation(session, componentsMap.get(), type, ids);
} else if (type == ObjectType.REALM || type == ObjectType.PROVIDER_FACTORY) { } else if (type == ObjectType.REALM || type == ObjectType.PROVIDER_FACTORY) {
Stream.of(ids) Stream.of(ids)
.map(dependentInvalidations::get).filter(Objects::nonNull).flatMap(Collection::stream) .map(dependentInvalidations::get).filter(Objects::nonNull).flatMap(Collection::stream)
.map(componentsMap.get()::remove).filter(Objects::nonNull) .map(componentsMap.get()::remove).filter(Objects::nonNull)
.forEach(ProviderFactory::close); .forEach(ProviderFactory::close);
Stream.of(ids).forEach(dependentInvalidations::remove); Stream.of(ids).forEach(dependentInvalidations::remove);
propagateInvalidation(componentsMap.get(), type, ids); propagateInvalidation(session, componentsMap.get(), type, ids);
} else { } else {
propagateInvalidation(componentsMap.get(), type, ids); propagateInvalidation(session, componentsMap.get(), type, ids);
} }
} }
private void propagateInvalidation(ConcurrentMap<String, ProviderFactory> componentsMap, InvalidableObjectType type, Object[] ids) { private void propagateInvalidation(KeycloakSession session, ConcurrentMap<String, ProviderFactory> componentsMap, InvalidableObjectType type, Object[] ids) {
componentsMap.values() componentsMap.values()
.stream() .stream()
.filter(InvalidationHandler.class::isInstance) .filter(InvalidationHandler.class::isInstance)
.map(InvalidationHandler.class::cast) .map(InvalidationHandler.class::cast)
.forEach(ih -> ih.invalidate(type, ids)); .forEach(ih -> ih.invalidate(session, type, ids));
} }
@Override @Override

View file

@ -41,10 +41,11 @@ import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache; import org.keycloak.models.cache.UserCache;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.InvalidationHandler.InvalidableObjectType;
import org.keycloak.provider.InvalidationHandler.ObjectType;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.keycloak.services.clientpolicy.ClientPolicyManager; import org.keycloak.services.clientpolicy.ClientPolicyManager;
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
import org.keycloak.sessions.AuthenticationSessionProvider; import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.ClientStorageManager; import org.keycloak.storage.ClientStorageManager;
import org.keycloak.storage.ClientScopeStorageManager; import org.keycloak.storage.ClientScopeStorageManager;
@ -169,8 +170,10 @@ public class DefaultKeycloakSession implements KeycloakSession {
@Override @Override
public void invalidate(InvalidableObjectType type, Object... ids) { public void invalidate(InvalidableObjectType type, Object... ids) {
factory.invalidate(type, ids); factory.invalidate(this, type, ids);
invalidationMap.computeIfAbsent(type, o -> new HashSet<>()).addAll(Arrays.asList(ids)); if (type == ObjectType.PROVIDER_FACTORY) {
invalidationMap.computeIfAbsent(type, o -> new HashSet<>()).addAll(Arrays.asList(ids));
}
} }
@Override @Override
@ -524,7 +527,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
providers.values().forEach(safeClose); providers.values().forEach(safeClose);
closable.forEach(safeClose); closable.forEach(safeClose);
for (Entry<InvalidableObjectType, Set<Object>> me : invalidationMap.entrySet()) { for (Entry<InvalidableObjectType, Set<Object>> me : invalidationMap.entrySet()) {
factory.invalidate(me.getKey(), me.getValue().toArray()); factory.invalidate(this, me.getKey(), me.getValue().toArray());
} }
} }

View file

@ -174,7 +174,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
checkProvider(); checkProvider();
boolean cfChanged = false; boolean cfChanged = false;
for (ProviderFactory factory : undeployed) { for (ProviderFactory factory : undeployed) {
invalidate(ObjectType.PROVIDER_FACTORY, factory.getClass()); invalidate(null, ObjectType.PROVIDER_FACTORY, factory.getClass());
factory.close(); factory.close();
cfChanged |= (componentFactoryPF == factory); cfChanged |= (componentFactoryPF == factory);
} }
@ -359,13 +359,13 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
} }
@Override @Override
public void invalidate(InvalidableObjectType type, Object... ids) { public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... ids) {
factoriesMap.values().stream() factoriesMap.values().stream()
.map(Map::values) .map(Map::values)
.flatMap(Collection::stream) .flatMap(Collection::stream)
.filter(InvalidationHandler.class::isInstance) .filter(InvalidationHandler.class::isInstance)
.map(InvalidationHandler.class::cast) .map(InvalidationHandler.class::cast)
.forEach(ih -> ih.invalidate(type, ids)); .forEach(ih -> ih.invalidate(session, type, ids));
} }
@Override @Override

View file

@ -36,6 +36,7 @@ import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.util.KeycloakUriBuilder; import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache; import org.keycloak.models.cache.UserCache;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
@ -720,6 +721,25 @@ public abstract class AbstractKeycloakTest {
return isProduct ? Profile.PRODUCT_NAME : Profile.PROJECT_NAME; return isProduct ? Profile.PRODUCT_NAME : Profile.PROJECT_NAME;
} }
/**
* MapRealmProvider uses session.invalidate() instead of calling e.g.
* session.clients().removeClients(realm); for clients (where clients are being removed one by one)
*
* Therefore it doesn't call session.users().preRemove(realm, client) for each client.
* Due to that JpaUserFederatedStorageProvider.preRemove(realm, client) is not called.
* So there remains objects in the database in user federation related tables after realm removal.
*
* Same for roles etc.
*
* Legacy federated storage is NOT supposed to work with map storage, so this method
* returns true if realm provider is "jpa" to be able to skip particular tests.
*/
protected boolean isJpaRealmProvider() {
String realmProvider = testingClient.server()
.fetchString(s -> s.getKeycloakSessionFactory().getProviderFactory(RealmProvider.class).getId());
return Objects.equals(realmProvider, "\"jpa\"");
}
protected boolean isRealmCacheEnabled() { protected boolean isRealmCacheEnabled() {
String realmCache = testingClient.server() String realmCache = testingClient.server()
.fetchString(s -> s.getKeycloakSessionFactory().getProviderFactory(CacheRealmProvider.class)); .fetchString(s -> s.getKeycloakSessionFactory().getProviderFactory(CacheRealmProvider.class));

View file

@ -18,6 +18,7 @@ package org.keycloak.testsuite.federation.storage;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
@ -42,7 +43,6 @@ import javax.ws.rs.NotFoundException;
import java.io.File; import java.io.File;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
@ -61,6 +61,8 @@ public class FederatedStorageExportImportTest extends AbstractAuthTest {
@Before @Before
public void setDirs() { public void setDirs() {
Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
File baseDir = new File(System.getProperty("auth.server.config.dir", "target")); File baseDir = new File(System.getProperty("auth.server.config.dir", "target"));
exportFileAbsolutePath = new File (baseDir, "singleFile-full.json").getAbsolutePath(); exportFileAbsolutePath = new File (baseDir, "singleFile-full.json").getAbsolutePath();

View file

@ -57,7 +57,10 @@ import org.keycloak.testsuite.util.OAuthClient;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.Assume;
import org.keycloak.models.RealmProvider;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
import org.keycloak.testsuite.util.ContainerAssume; import org.keycloak.testsuite.util.ContainerAssume;
@ -95,6 +98,8 @@ public class UserStorageFailureTest extends AbstractTestRealmKeycloakTest {
@Before @Before
public void addProvidersBeforeTest() { public void addProvidersBeforeTest() {
Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
ComponentRepresentation memProvider = new ComponentRepresentation(); ComponentRepresentation memProvider = new ComponentRepresentation();
memProvider.setName("failure"); memProvider.setName("failure");
memProvider.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID); memProvider.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID);

View file

@ -25,6 +25,7 @@ import java.util.List;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
@ -89,6 +90,8 @@ public class UserStorageOTPTest extends AbstractTestRealmKeycloakTest {
@Before @Before
public void addProvidersBeforeTest() throws URISyntaxException, IOException { public void addProvidersBeforeTest() throws URISyntaxException, IOException {
Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
ComponentRepresentation dummyProvider = new ComponentRepresentation(); ComponentRepresentation dummyProvider = new ComponentRepresentation();
dummyProvider.setName("dummy"); dummyProvider.setName("dummy");
dummyProvider.setId(componentId); dummyProvider.setId(componentId);

View file

@ -39,6 +39,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Assume;
import org.junit.Before;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
@ -53,6 +55,11 @@ public class SyncFederationTest extends AbstractAuthTest {
private static final Logger log = Logger.getLogger(SyncFederationTest.class); private static final Logger log = Logger.getLogger(SyncFederationTest.class);
@Before
public void enabled() {
Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
}
/** /**
* Test that period sync is triggered when creating a synchronized User Storage Provider * Test that period sync is triggered when creating a synchronized User Storage Provider
* *

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.model;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
@ -59,6 +60,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
@Before @Before
public void before() { public void before() {
Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
testingClient.server().run(UserConsentWithUserStorageModelTest::setupEnv); testingClient.server().run(UserConsentWithUserStorageModelTest::setupEnv);
} }

View file

@ -143,11 +143,11 @@ public class ConcurrentHashMapStorageTest extends KeycloakModelTest {
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2); assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
// Invalidate one component and check that the storage still contains what it should // Invalidate one component and check that the storage still contains what it should
getFactory().invalidate(ObjectType.COMPONENT, component1Id); getFactory().invalidate(null, ObjectType.COMPONENT, component1Id);
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2); assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
// Invalidate whole realm and check that the storage still contains what it should // Invalidate whole realm and check that the storage still contains what it should
getFactory().invalidate(ObjectType.REALM, realmId); getFactory().invalidate(null, ObjectType.REALM, realmId);
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2); assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
// Refresh factory (akin server restart) and check that the storage still contains what it should // Refresh factory (akin server restart) and check that the storage still contains what it should