diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index a69b412cfb..0fd18a1478 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -477,16 +477,16 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.registerListener(REALM_CLEAR_CACHE_EVENTS, (ClusterEvent event) -> {
if (event instanceof ClearCacheEvent) {
- sessionFactory.invalidate(ObjectType._ALL_);
+ sessionFactory.invalidate(null, ObjectType._ALL_);
}
});
cluster.registerListener(REALM_INVALIDATION_EVENTS, (ClusterEvent event) -> {
if (event instanceof RealmUpdatedEvent) {
RealmUpdatedEvent rr = (RealmUpdatedEvent) event;
- sessionFactory.invalidate(ObjectType.REALM, rr.getId());
+ sessionFactory.invalidate(null, ObjectType.REALM, rr.getId());
} else if (event instanceof RealmRemovedEvent) {
RealmRemovedEvent rr = (RealmRemovedEvent) event;
- sessionFactory.invalidate(ObjectType.REALM, rr.getId());
+ sessionFactory.invalidate(null, ObjectType.REALM, rr.getId());
}
});
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProviderFactory.java
index 38b174e3df..a80db1a981 100644
--- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProviderFactory.java
@@ -18,7 +18,6 @@ package org.keycloak.models.map.authSession;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
-import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.sessions.AuthenticationSessionProviderFactory;
import org.keycloak.sessions.RootAuthenticationSessionModel;
@@ -26,15 +25,15 @@ import org.keycloak.sessions.RootAuthenticationSessionModel;
/**
* @author Martin Kanis
*/
-public class MapRootAuthenticationSessionProviderFactory extends AbstractMapProviderFactory
- implements AuthenticationSessionProviderFactory {
+public class MapRootAuthenticationSessionProviderFactory extends AbstractMapProviderFactory
+ implements AuthenticationSessionProviderFactory {
public MapRootAuthenticationSessionProviderFactory() {
- super(RootAuthenticationSessionModel.class);
+ super(RootAuthenticationSessionModel.class, MapRootAuthenticationSessionProvider.class);
}
@Override
- public AuthenticationSessionProvider create(KeycloakSession session) {
+ public MapRootAuthenticationSessionProvider createNew(KeycloakSession session) {
return new MapRootAuthenticationSessionProvider(session, getStorage(session));
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java
index f5207aac29..d431b627d5 100644
--- a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java
+++ b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProvider.java
@@ -17,21 +17,8 @@
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.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -41,18 +28,30 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
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.criteria.DefaultModelCriteria;
import static org.keycloak.common.util.StackUtil.getShortStackTrace;
-import org.keycloak.models.ClientScopeModel;
-import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
-import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
+import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_AFTER_REMOVE;
+import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.CLIENT_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;
-import java.util.HashSet;
-
public class MapClientProvider implements ClientProvider {
private static final Logger LOG = Logger.getLogger(MapClientProvider.class);
@@ -196,33 +195,19 @@ public class MapClientProvider implements ClientProvider {
@Override
public boolean removeClient(RealmModel realm, String id) {
- if (id == null) {
- return false;
- }
+ if (id == null) return false;
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);
if (client == null) return false;
- session.users().preRemove(realm, client);
- session.roles().removeRoles(client);
- session.getKeycloakSessionFactory().publish(new ClientModel.ClientRemovedEvent() {
- @Override
- public ClientModel getClient() {
- return client;
- }
-
- @Override
- public KeycloakSession getKeycloakSession() {
- return session;
- }
- });
- // TODO: ^^^^^^^ Up to here
+ session.invalidate(CLIENT_BEFORE_REMOVE, realm, client);
tx.delete(id);
+ session.invalidate(CLIENT_AFTER_REMOVE, client);
+
return true;
}
@@ -374,6 +359,14 @@ public class MapClientProvider implements ClientProvider {
}
}
+ public void preRemove(RealmModel realm) {
+ LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
+ DefaultModelCriteria mcb = criteria();
+ mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
+
+ tx.delete(withCriteria(mcb));
+ }
+
@Override
public void close() {
diff --git a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java
index af6a64be4b..14ad9193c7 100644
--- a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java
@@ -16,72 +16,54 @@
*/
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.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
*/
-public class MapClientProviderFactory extends AbstractMapProviderFactory implements ClientProviderFactory, ProviderEventListener {
+public class MapClientProviderFactory extends AbstractMapProviderFactory implements ClientProviderFactory, InvalidationHandler {
private final ConcurrentHashMap> REGISTERED_NODES_STORE = new ConcurrentHashMap<>();
- private Runnable onClose;
-
public MapClientProviderFactory() {
- super(ClientModel.class);
+ super(ClientModel.class, MapClientProvider.class);
}
@Override
- public void postInit(KeycloakSessionFactory factory) {
- factory.register(this);
- onClose = () -> factory.unregister(this);
- }
-
- @Override
- public MapClientProvider create(KeycloakSession session) {
+ public MapClientProvider createNew(KeycloakSession session) {
return new MapClientProvider(session, getStorage(session), REGISTERED_NODES_STORE);
}
- @Override
- public void close() {
- super.close();
- onClose.run();
- }
-
@Override
public String getHelpText() {
return "Client provider";
}
@Override
- public void onEvent(ProviderEvent event) {
- if (event instanceof RoleContainerModel.RoleRemovedEvent) {
- RoleRemovedEvent e = (RoleContainerModel.RoleRemovedEvent) event;
- RoleModel role = e.getRole();
- RoleContainerModel container = role.getContainer();
- RealmModel realm;
- if (container instanceof RealmModel) {
- realm = (RealmModel) container;
- } else if (container instanceof ClientModel) {
- realm = ((ClientModel) container).getRealm();
- } else {
- return;
- }
- ((MapClientProvider) e.getKeycloakSession().getProvider(ClientProvider.class)).preRemove(realm, role);
+ 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_AFTER_REMOVE) {
+ session.getKeycloakSessionFactory().publish(new ClientModel.ClientRemovedEvent() {
+ @Override public ClientModel getClient() { return (ClientModel) params[0]; }
+ @Override public KeycloakSession getKeycloakSession() { return session; }
+ });
}
}
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java b/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java
index 5a47075b5e..c299837639 100644
--- a/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java
+++ b/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProvider.java
@@ -23,7 +23,6 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jboss.logging.Logger;
-import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import org.keycloak.models.ClientScopeModel.SearchableFields;
import org.keycloak.models.ClientScopeModel;
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.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.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
@@ -106,23 +108,12 @@ public class MapClientScopeProvider implements ClientScopeProvider {
ClientScopeModel clientScope = getClientScopeById(realm, id);
if (clientScope == null) return false;
- session.users().preRemove(clientScope);
- realm.removeDefaultClientScope(clientScope);
-
- session.getKeycloakSessionFactory().publish(new ClientScopeModel.ClientScopeRemovedEvent() {
-
- @Override
- public KeycloakSession getKeycloakSession() {
- return session;
- }
-
- @Override
- public ClientScopeModel getClientScope() {
- return clientScope;
- }
- });
+ session.invalidate(CLIENT_SCOPE_BEFORE_REMOVE, realm, clientScope);
tx.delete(id);
+
+ session.invalidate(CLIENT_SCOPE_AFTER_REMOVE, clientScope);
+
return true;
}
@@ -150,6 +141,14 @@ public class MapClientScopeProvider implements ClientScopeProvider {
: entityToAdapterFunc(realm).apply(entity);
}
+ public void preRemove(RealmModel realm) {
+ LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
+ DefaultModelCriteria mcb = criteria();
+ mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
+
+ tx.delete(withCriteria(mcb));
+ }
+
@Override
public void close() {
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProviderFactory.java
index 60d7e6edad..ad35cc55b9 100644
--- a/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/clientscope/MapClientScopeProviderFactory.java
@@ -17,19 +17,24 @@
package org.keycloak.models.map.clientscope;
import org.keycloak.models.ClientScopeModel;
-import org.keycloak.models.ClientScopeProvider;
import org.keycloak.models.ClientScopeProviderFactory;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
+import org.keycloak.provider.InvalidationHandler;
-public class MapClientScopeProviderFactory extends AbstractMapProviderFactory 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 implements ClientScopeProviderFactory, InvalidationHandler {
public MapClientScopeProviderFactory() {
- super(ClientScopeModel.class);
+ super(ClientScopeModel.class, MapClientScopeProvider.class);
}
@Override
- public ClientScopeProvider create(KeycloakSession session) {
+ public MapClientScopeProvider createNew(KeycloakSession session) {
return new MapClientScopeProvider(session, getStorage(session));
}
@@ -37,4 +42,18 @@ public class MapClientScopeProviderFactory extends AbstractMapProviderFactory modelType;
+ private final Class providerType;
private Scope storageConfigScope;
- @SuppressWarnings("unchecked")
- protected AbstractMapProviderFactory(Class modelType) {
+ protected AbstractMapProviderFactory(Class modelType, Class providerType) {
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
diff --git a/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java b/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java
index ed6077df75..23f11a4d8f 100644
--- a/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java
+++ b/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProvider.java
@@ -36,10 +36,11 @@ import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.UnaryOperator;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
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.withCriteria;
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());
if (group == null) return false;
- // TODO: Sending an event (, user group removal and realm default groups) should be extracted to store layer
- 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
+ session.invalidate(GROUP_BEFORE_REMOVE, realm, group);
tx.delete(group.getId());
+ session.invalidate(GROUP_AFTER_REMOVE, realm, group);
+
return true;
}
@@ -306,9 +285,16 @@ public class MapGroupProvider implements GroupProvider {
}
}
+ public void preRemove(RealmModel realm) {
+ LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
+ DefaultModelCriteria mcb = criteria();
+ mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
+
+ tx.delete(withCriteria(mcb));
+ }
+
@Override
public void close() {
-
}
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProviderFactory.java
index 22736d888a..a7133304f7 100644
--- a/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/group/MapGroupProviderFactory.java
@@ -16,70 +16,58 @@
*/
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.GroupProvider;
import org.keycloak.models.GroupProviderFactory;
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 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
*/
-public class MapGroupProviderFactory extends AbstractMapProviderFactory implements GroupProviderFactory, ProviderEventListener {
-
- private Runnable onClose;
+public class MapGroupProviderFactory extends AbstractMapProviderFactory implements GroupProviderFactory, InvalidationHandler {
public MapGroupProviderFactory() {
- super(GroupModel.class);
+ super(GroupModel.class, MapGroupProvider.class);
}
@Override
- public void postInit(KeycloakSessionFactory factory) {
- factory.register(this);
- onClose = () -> factory.unregister(this);
- }
-
- @Override
- public MapGroupProvider create(KeycloakSession session) {
+ public MapGroupProvider createNew(KeycloakSession session) {
return new MapGroupProvider(session, getStorage(session));
}
- @Override
- public void close() {
- super.close();
- onClose.run();
- }
-
@Override
public String getHelpText() {
return "Group provider";
}
@Override
- public void onEvent(ProviderEvent event) {
- if (event instanceof RoleContainerModel.RoleRemovedEvent) {
- RoleRemovedEvent e = (RoleContainerModel.RoleRemovedEvent) event;
- RoleModel role = e.getRole();
- RoleContainerModel container = role.getContainer();
- RealmModel realm;
- if (container instanceof RealmModel) {
- realm = (RealmModel) container;
- } else if (container instanceof ClientModel) {
- realm = ((ClientModel) container).getRealm();
- } else {
- return;
- }
- ((MapGroupProvider) e.getKeycloakSession().getProvider(GroupProvider.class)).preRemove(realm, role);
+ 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 == GROUP_BEFORE_REMOVE) {
+ RealmModel realm = (RealmModel) params[0];
+ GroupModel group = (GroupModel) params[1];
+
+ realm.removeDefaultGroup(group);
+ group.getSubGroupsStream().collect(Collectors.toSet()).forEach(subGroup -> create(session).removeGroup(realm, subGroup));
+ } else if (type == GROUP_AFTER_REMOVE) {
+ session.getKeycloakSessionFactory().publish(new GroupModel.GroupRemovedEvent() {
+ @Override public RealmModel getRealm() { return (RealmModel) params[0]; }
+ @Override public GroupModel getGroup() { return (GroupModel) params[1]; }
+ @Override public KeycloakSession getKeycloakSession() { return session; }
+ });
}
}
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureProviderFactory.java
index e03b6ef9d4..63b4c9a70e 100644
--- a/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureProviderFactory.java
@@ -17,43 +17,28 @@
package org.keycloak.models.map.loginFailure;
import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserLoginFailureProviderFactory;
import org.keycloak.models.UserLoginFailureModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
-import org.keycloak.provider.ProviderEvent;
-import org.keycloak.provider.ProviderEventListener;
+import org.keycloak.provider.InvalidationHandler;
+
+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 Martin Kanis
*/
-public class MapUserLoginFailureProviderFactory extends AbstractMapProviderFactory
- implements UserLoginFailureProviderFactory, ProviderEventListener {
-
- private Runnable onClose;
+public class MapUserLoginFailureProviderFactory extends AbstractMapProviderFactory
+ implements UserLoginFailureProviderFactory, InvalidationHandler {
public MapUserLoginFailureProviderFactory() {
- super(UserLoginFailureModel.class);
+ super(UserLoginFailureModel.class, MapUserLoginFailureProvider.class);
}
@Override
- public void postInit(KeycloakSessionFactory factory) {
- factory.register(this);
- onClose = () -> factory.unregister(this);
- }
-
- @Override
- public void close() {
- super.close();
- onClose.run();
- }
-
- @Override
- public MapUserLoginFailureProvider create(KeycloakSession session) {
+ public MapUserLoginFailureProvider createNew(KeycloakSession session) {
return new MapUserLoginFailureProvider(session, getStorage(session));
}
@@ -63,17 +48,11 @@ public class MapUserLoginFailureProviderFactory extends AbstractMapProviderFacto
}
@Override
- public void onEvent(ProviderEvent event) {
- if (event instanceof UserModel.UserRemovedEvent) {
- UserModel.UserRemovedEvent userRemovedEvent = (UserModel.UserRemovedEvent) event;
-
- MapUserLoginFailureProvider provider = MapUserLoginFailureProviderFactory.this.create(userRemovedEvent.getKeycloakSession());
- 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());
+ public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
+ if (type == REALM_BEFORE_REMOVE) {
+ create(session).removeAllUserLoginFailures((RealmModel) params[0]);
+ } else if (type == USER_BEFORE_REMOVE) {
+ create(session).removeUserLoginFailure((RealmModel) params[0], ((UserModel) params[1]).getId());
}
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java
index 4699ab0226..669981fd9b 100644
--- a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java
+++ b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProvider.java
@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import org.jboss.logging.Logger;
-import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel;
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.criteria.DefaultModelCriteria;
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.withCriteria;
import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.criteria;
@@ -135,27 +138,12 @@ public class MapRealmProvider implements RealmProvider {
if (realm == null) return false;
- session.users().preRemove(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
+ session.invalidate(REALM_BEFORE_REMOVE, realm);
tx.delete(id);
+
+ session.invalidate(REALM_AFTER_REMOVE, realm);
+
return true;
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProviderFactory.java
index 6a1431a95d..7c98202eac 100644
--- a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmProviderFactory.java
@@ -19,22 +19,34 @@ package org.keycloak.models.map.realm;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmProviderFactory;
+import org.keycloak.provider.InvalidationHandler;
-public class MapRealmProviderFactory extends AbstractMapProviderFactory implements RealmProviderFactory {
+import static org.keycloak.models.map.common.AbstractMapProviderFactory.MapProviderObjectType.REALM_AFTER_REMOVE;
+
+public class MapRealmProviderFactory extends AbstractMapProviderFactory implements RealmProviderFactory, InvalidationHandler {
public MapRealmProviderFactory() {
- super(RealmModel.class);
+ super(RealmModel.class, MapRealmProvider.class);
}
@Override
- public RealmProvider create(KeycloakSession session) {
+ public MapRealmProvider createNew(KeycloakSession session) {
return new MapRealmProvider(session, getStorage(session));
}
@Override
public String getHelpText() {
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; }
+ });
+ }
+ }
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java b/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java
index 734036abf2..767d700b10 100644
--- a/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java
+++ b/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProvider.java
@@ -17,30 +17,29 @@
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.keycloak.models.ClientModel;
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.storage.MapKeycloakTransaction;
-
-import java.util.Objects;
-import java.util.function.Function;
-import java.util.stream.Stream;
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.RoleProvider;
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
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 {
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();
- session.users().preRemove(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
+ session.invalidate(ROLE_BEFORE_REMOVE, realm, role);
tx.delete(role.getId());
+ session.invalidate(ROLE_AFTER_REMOVE, realm, role);
+
return true;
}
@@ -284,6 +271,14 @@ public class MapRoleProvider implements RoleProvider {
.map(entityToAdapterFunc(client.getRealm()));
}
+ public void preRemove(RealmModel realm) {
+ LOG.tracef("preRemove(%s)%s", realm, getShortStackTrace());
+ DefaultModelCriteria mcb = criteria();
+ mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId());
+
+ tx.delete(withCriteria(mcb));
+ }
+
@Override
public void close() {
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProviderFactory.java
index 0bbf3c8e3c..74b7420ee0 100644
--- a/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/role/MapRoleProviderFactory.java
@@ -16,20 +16,27 @@
*/
package org.keycloak.models.map.role;
+import org.keycloak.models.ClientModel;
import org.keycloak.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.RoleProvider;
import org.keycloak.models.RoleProviderFactory;
+import org.keycloak.provider.InvalidationHandler;
-public class MapRoleProviderFactory extends AbstractMapProviderFactory 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 implements RoleProviderFactory, InvalidationHandler {
public MapRoleProviderFactory() {
- super(RoleModel.class);
+ super(RoleModel.class, MapRoleProvider.class);
}
@Override
- public RoleProvider create(KeycloakSession session) {
+ public MapRoleProvider createNew(KeycloakSession session) {
return new MapRoleProvider(session, getStorage(session));
}
@@ -37,4 +44,18 @@ public class MapRoleProviderFactory extends AbstractMapProviderFactory userById = getEntityById(realm, userId);
if (userById.isPresent()) {
+ session.invalidate(USER_BEFORE_REMOVE, realm, user);
+
tx.delete(userId);
+
+ session.invalidate(USER_AFTER_REMOVE, realm, user);
return true;
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/user/MapUserProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/user/MapUserProviderFactory.java
index 3a4a85f6b2..1fac8b044c 100644
--- a/model/map/src/main/java/org/keycloak/models/map/user/MapUserProviderFactory.java
+++ b/model/map/src/main/java/org/keycloak/models/map/user/MapUserProviderFactory.java
@@ -17,24 +17,35 @@
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.RealmModel;
+import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.UserProvider;
import org.keycloak.models.UserProviderFactory;
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
*/
-public class MapUserProviderFactory extends AbstractMapProviderFactory implements UserProviderFactory {
+public class MapUserProviderFactory extends AbstractMapProviderFactory implements UserProviderFactory, InvalidationHandler {
public MapUserProviderFactory() {
- super(UserModel.class);
+ super(UserModel.class, MapUserProvider.class);
}
@Override
- public UserProvider create(KeycloakSession session) {
+ public MapUserProvider createNew(KeycloakSession session) {
return new MapUserProvider(session, getStorage(session));
}
@@ -43,4 +54,18 @@ public class MapUserProviderFactory extends AbstractMapProviderFactoryMartin Kanis
*/
-public class MapUserSessionProviderFactory implements AmphibianProviderFactory, UserSessionProviderFactory, ProviderEventListener, EnvironmentDependentProviderFactory {
+public class MapUserSessionProviderFactory implements AmphibianProviderFactory, UserSessionProviderFactory, EnvironmentDependentProviderFactory, InvalidationHandler {
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 PROVIDER_ID = AbstractMapProviderFactory.PROVIDER_ID;
+ private final String uniqueKey = getClass().getName() + uniqueCounter.incrementAndGet();
+
private Scope storageConfigScopeUserSessions;
private Scope storageConfigScopeClientSessions;
- private Runnable onClose;
-
@Override
public String getId() {
return PROVIDER_ID;
@@ -64,14 +66,11 @@ public class MapUserSessionProviderFactory implements AmphibianProviderF
@Override
public void postInit(KeycloakSessionFactory factory) {
- factory.register(this);
- onClose = () -> factory.unregister(this);
}
@Override
public void close() {
AmphibianProviderFactory.super.close();
- onClose.run();
}
@Override
@@ -79,7 +78,12 @@ public class MapUserSessionProviderFactory implements AmphibianProviderF
}
@Override
+ @SuppressWarnings("unchecked")
public MapUserSessionProvider create(KeycloakSession session) {
+ MapUserSessionProvider provider = session.getAttribute(uniqueKey, MapUserSessionProvider.class);
+
+ if (provider != null) return provider;
+
MapStorageProviderFactory storageProviderFactoryUs = (MapStorageProviderFactory) getComponentFactory(session.getKeycloakSessionFactory(),
MapStorageProvider.class, storageConfigScopeUserSessions, MapStorageSpi.NAME);
final MapStorageProvider factoryUs = storageProviderFactoryUs.create(session);
@@ -90,7 +94,9 @@ public class MapUserSessionProviderFactory implements AmphibianProviderF
final MapStorageProvider factoryCs = storageProviderFactoryCs.create(session);
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
@@ -99,12 +105,9 @@ public class MapUserSessionProviderFactory implements AmphibianProviderF
}
@Override
- public void onEvent(ProviderEvent event) {
- if (event instanceof UserModel.UserRemovedEvent) {
- UserModel.UserRemovedEvent userRemovedEvent = (UserModel.UserRemovedEvent) event;
-
- MapUserSessionProvider provider = MapUserSessionProviderFactory.this.create(userRemovedEvent.getKeycloakSession());
- provider.removeUserSessions(userRemovedEvent.getRealm(), userRemovedEvent.getUser());
+ public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... params) {
+ if (type == USER_BEFORE_REMOVE) {
+ create(session).removeUserSessions((RealmModel) params[0], (UserModel) params[1]);
}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/ClientProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/ClientProviderFactory.java
index 3117fd080c..c8eefb29a4 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/ClientProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/ClientProviderFactory.java
@@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory;
-public interface ClientProviderFactory extends ProviderFactory {
+public interface ClientProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/ClientScopeProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/ClientScopeProviderFactory.java
index a1b0fca590..f10ac36395 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/ClientScopeProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/ClientScopeProviderFactory.java
@@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory;
-public interface ClientScopeProviderFactory extends ProviderFactory {
+public interface ClientScopeProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/GroupProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/GroupProviderFactory.java
index 2d1e783bae..7409a7acf8 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/GroupProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/GroupProviderFactory.java
@@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory;
-public interface GroupProviderFactory extends ProviderFactory {
+public interface GroupProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/RealmProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/RealmProviderFactory.java
index 95ca89479a..e73d379a02 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/RealmProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/RealmProviderFactory.java
@@ -23,5 +23,5 @@ import org.keycloak.provider.ProviderFactory;
* @author Bill Burke
* @version $Revision: 1 $
*/
-public interface RealmProviderFactory extends ProviderFactory {
+public interface RealmProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/RoleProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/RoleProviderFactory.java
index 3d49f65b21..7293caed5d 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/RoleProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/RoleProviderFactory.java
@@ -19,5 +19,5 @@ package org.keycloak.models;
import org.keycloak.provider.ProviderFactory;
-public interface RoleProviderFactory extends ProviderFactory {
+public interface RoleProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/UserLoginFailureProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/UserLoginFailureProviderFactory.java
index 192d934564..9c27d669ed 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/UserLoginFailureProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/UserLoginFailureProviderFactory.java
@@ -21,6 +21,6 @@ import org.keycloak.provider.ProviderFactory;
/**
* @author Martin Kanis
*/
-public interface UserLoginFailureProviderFactory extends ProviderFactory {
+public interface UserLoginFailureProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/UserProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/UserProviderFactory.java
index 6cd9f136ab..91a587197a 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/UserProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/UserProviderFactory.java
@@ -23,5 +23,5 @@ import org.keycloak.provider.ProviderFactory;
* @author Bill Burke
* @version $Revision: 1 $
*/
-public interface UserProviderFactory extends ProviderFactory {
+public interface UserProviderFactory extends ProviderFactory {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/sessions/AuthenticationSessionProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/sessions/AuthenticationSessionProviderFactory.java
index b182458b5e..442a44415f 100644
--- a/server-spi-private/src/main/java/org/keycloak/sessions/AuthenticationSessionProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/sessions/AuthenticationSessionProviderFactory.java
@@ -22,5 +22,5 @@ import org.keycloak.provider.ProviderFactory;
/**
* @author Marek Posolda
*/
-public interface AuthenticationSessionProviderFactory extends ProviderFactory {
+public interface AuthenticationSessionProviderFactory extends ProviderFactory {
}
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
index 6442a2a8d4..bb2a838755 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -19,7 +19,7 @@ package org.keycloak.models;
import org.keycloak.component.ComponentModel;
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.services.clientpolicy.ClientPolicyManager;
import org.keycloak.sessions.AuthenticationSessionProvider;
@@ -33,7 +33,7 @@ import java.util.function.Function;
* @author Bill Burke
* @version $Revision: 1 $
*/
-public interface KeycloakSession extends InvalidationHandler {
+public interface KeycloakSession {
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.
* @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... ids);
+ void invalidate(InvalidableObjectType type, Object... params);
void enlistForClose(Provider provider);
diff --git a/server-spi/src/main/java/org/keycloak/models/RealmModel.java b/server-spi/src/main/java/org/keycloak/models/RealmModel.java
index a2999583c9..8717a7a40b 100755
--- a/server-spi/src/main/java/org/keycloak/models/RealmModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/RealmModel.java
@@ -29,11 +29,9 @@ import org.keycloak.storage.client.ClientStorageProvider;
import org.keycloak.storage.client.ClientStorageProviderModel;
import org.keycloak.storage.role.RoleStorageProvider;
import org.keycloak.storage.role.RoleStorageProviderModel;
-import org.keycloak.utils.StringUtil;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
diff --git a/server-spi/src/main/java/org/keycloak/provider/InvalidationHandler.java b/server-spi/src/main/java/org/keycloak/provider/InvalidationHandler.java
index 462305a3c7..c23f681954 100644
--- a/server-spi/src/main/java/org/keycloak/provider/InvalidationHandler.java
+++ b/server-spi/src/main/java/org/keycloak/provider/InvalidationHandler.java
@@ -16,6 +16,8 @@
*/
package org.keycloak.provider;
+import org.keycloak.models.KeycloakSession;
+
/**
* Handles invalidation requests. This interface is specifically implemented by
* 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
+ * @param session KeycloakSession
* @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);
}
diff --git a/services/src/main/java/org/keycloak/services/DefaultComponentFactoryProviderFactory.java b/services/src/main/java/org/keycloak/services/DefaultComponentFactoryProviderFactory.java
index e2d34f8e28..6d358c228f 100644
--- a/services/src/main/java/org/keycloak/services/DefaultComponentFactoryProviderFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultComponentFactoryProviderFactory.java
@@ -23,6 +23,7 @@ import org.keycloak.common.util.StackUtil;
import org.keycloak.component.ComponentFactoryProviderFactory;
import org.keycloak.component.ComponentModel;
import org.keycloak.component.ComponentModelScope;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.InvalidationHandler;
@@ -155,7 +156,7 @@ public class DefaultComponentFactoryProviderFactory implements ComponentFactoryP
}
@Override
- public void invalidate(InvalidableObjectType type, Object... ids) {
+ public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... ids) {
if (LOG.isDebugEnabled()) {
LOG.debugf("Invalidating %s: %s", type, Arrays.asList(ids));
}
@@ -169,25 +170,25 @@ public class DefaultComponentFactoryProviderFactory implements ComponentFactoryP
Stream.of(ids)
.map(componentsMap.get()::remove).filter(Objects::nonNull)
.forEach(ProviderFactory::close);
- propagateInvalidation(componentsMap.get(), type, ids);
+ propagateInvalidation(session, componentsMap.get(), type, ids);
} else if (type == ObjectType.REALM || type == ObjectType.PROVIDER_FACTORY) {
Stream.of(ids)
.map(dependentInvalidations::get).filter(Objects::nonNull).flatMap(Collection::stream)
.map(componentsMap.get()::remove).filter(Objects::nonNull)
.forEach(ProviderFactory::close);
Stream.of(ids).forEach(dependentInvalidations::remove);
- propagateInvalidation(componentsMap.get(), type, ids);
+ propagateInvalidation(session, componentsMap.get(), type, ids);
} else {
- propagateInvalidation(componentsMap.get(), type, ids);
+ propagateInvalidation(session, componentsMap.get(), type, ids);
}
}
- private void propagateInvalidation(ConcurrentMap componentsMap, InvalidableObjectType type, Object[] ids) {
+ private void propagateInvalidation(KeycloakSession session, ConcurrentMap componentsMap, InvalidableObjectType type, Object[] ids) {
componentsMap.values()
.stream()
.filter(InvalidationHandler.class::isInstance)
.map(InvalidationHandler.class::cast)
- .forEach(ih -> ih.invalidate(type, ids));
+ .forEach(ih -> ih.invalidate(session, type, ids));
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 69e71e4e9f..cd423c8df1 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -41,10 +41,11 @@ import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache;
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.ProviderFactory;
import org.keycloak.services.clientpolicy.ClientPolicyManager;
-import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.ClientStorageManager;
import org.keycloak.storage.ClientScopeStorageManager;
@@ -169,8 +170,10 @@ public class DefaultKeycloakSession implements KeycloakSession {
@Override
public void invalidate(InvalidableObjectType type, Object... ids) {
- factory.invalidate(type, ids);
- invalidationMap.computeIfAbsent(type, o -> new HashSet<>()).addAll(Arrays.asList(ids));
+ factory.invalidate(this, type, ids);
+ if (type == ObjectType.PROVIDER_FACTORY) {
+ invalidationMap.computeIfAbsent(type, o -> new HashSet<>()).addAll(Arrays.asList(ids));
+ }
}
@Override
@@ -524,7 +527,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
providers.values().forEach(safeClose);
closable.forEach(safeClose);
for (Entry> me : invalidationMap.entrySet()) {
- factory.invalidate(me.getKey(), me.getValue().toArray());
+ factory.invalidate(this, me.getKey(), me.getValue().toArray());
}
}
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index af506feeca..8ebc320332 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -174,7 +174,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
checkProvider();
boolean cfChanged = false;
for (ProviderFactory factory : undeployed) {
- invalidate(ObjectType.PROVIDER_FACTORY, factory.getClass());
+ invalidate(null, ObjectType.PROVIDER_FACTORY, factory.getClass());
factory.close();
cfChanged |= (componentFactoryPF == factory);
}
@@ -359,13 +359,13 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
}
@Override
- public void invalidate(InvalidableObjectType type, Object... ids) {
+ public void invalidate(KeycloakSession session, InvalidableObjectType type, Object... ids) {
factoriesMap.values().stream()
.map(Map::values)
.flatMap(Collection::stream)
.filter(InvalidationHandler.class::isInstance)
.map(InvalidationHandler.class::cast)
- .forEach(ih -> ih.invalidate(type, ids));
+ .forEach(ih -> ih.invalidate(session, type, ids));
}
@Override
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index 448aedc25e..1b44f45610 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -36,6 +36,7 @@ import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.common.Profile;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.Time;
+import org.keycloak.models.RealmProvider;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache;
import org.keycloak.representations.idm.ClientRepresentation;
@@ -720,6 +721,25 @@ public abstract class AbstractKeycloakTest {
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() {
String realmCache = testingClient.server()
.fetchString(s -> s.getKeycloakSessionFactory().getProviderFactory(CacheRealmProvider.class));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java
index 002c06f841..60bfba1933 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java
@@ -18,6 +18,7 @@ package org.keycloak.testsuite.federation.storage;
import org.junit.After;
import org.junit.Assert;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
@@ -42,7 +43,6 @@ import javax.ws.rs.NotFoundException;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
-import java.util.Objects;
import java.util.stream.Collectors;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
@@ -61,6 +61,8 @@ public class FederatedStorageExportImportTest extends AbstractAuthTest {
@Before
public void setDirs() {
+ Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
+
File baseDir = new File(System.getProperty("auth.server.config.dir", "target"));
exportFileAbsolutePath = new File (baseDir, "singleFile-full.json").getAbsolutePath();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java
index 8e4de26bf4..631ab3ebfa 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java
@@ -57,7 +57,10 @@ import org.keycloak.testsuite.util.OAuthClient;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
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.util.ContainerAssume;
@@ -95,6 +98,8 @@ public class UserStorageFailureTest extends AbstractTestRealmKeycloakTest {
@Before
public void addProvidersBeforeTest() {
+ Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
+
ComponentRepresentation memProvider = new ComponentRepresentation();
memProvider.setName("failure");
memProvider.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageOTPTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageOTPTest.java
index e061e3df93..103aef3814 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageOTPTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageOTPTest.java
@@ -25,6 +25,7 @@ import java.util.List;
import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -89,6 +90,8 @@ public class UserStorageOTPTest extends AbstractTestRealmKeycloakTest {
@Before
public void addProvidersBeforeTest() throws URISyntaxException, IOException {
+ Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
+
ComponentRepresentation dummyProvider = new ComponentRepresentation();
dummyProvider.setName("dummy");
dummyProvider.setId(componentId);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
index e2499800b0..64ffd69dd2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
@@ -39,6 +39,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
+import org.junit.Assume;
+import org.junit.Before;
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);
+ @Before
+ public void enabled() {
+ Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
+ }
+
/**
* Test that period sync is triggered when creating a synchronized User Storage Provider
*
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java
index 659f2d5cce..a8a5cb9af9 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java
@@ -19,6 +19,7 @@ package org.keycloak.testsuite.model;
import org.junit.After;
import org.junit.Assert;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.component.ComponentModel;
@@ -59,6 +60,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
@Before
public void before() {
+ Assume.assumeTrue("RealmProvider is not 'jpa'", isJpaRealmProvider());
testingClient.server().run(UserConsentWithUserStorageModelTest::setupEnv);
}
diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/ConcurrentHashMapStorageTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/ConcurrentHashMapStorageTest.java
index 1d9f8b150e..e4b0df97d0 100644
--- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/ConcurrentHashMapStorageTest.java
+++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/ConcurrentHashMapStorageTest.java
@@ -143,11 +143,11 @@ public class ConcurrentHashMapStorageTest extends KeycloakModelTest {
assertClientsPersisted(component1Id, component2Id, idMain, id1, id2);
// 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);
// 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);
// Refresh factory (akin server restart) and check that the storage still contains what it should