diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
index acecf05e54..c5d71cfa70 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
@@ -1062,11 +1062,6 @@ public class RealmCacheSession implements CacheRealmProvider {
}
- @Override
- public void preRemove(RealmModel realm, RoleModel role) {
- getGroupDelegate().preRemove(realm, role);
- }
-
private void addGroupEventIfAbsent(InvalidationEvent eventToAdd) {
String groupId = eventToAdd.getId();
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
index e64f9f0e63..fb50cb5b55 100644
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
@@ -52,6 +52,7 @@ import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
import org.keycloak.models.RoleModel;
import org.keycloak.models.RoleProvider;
import org.keycloak.models.jpa.entities.ClientEntity;
@@ -335,14 +336,20 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, ClientSc
}
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate();
- realm.getClientsStream().forEach(c -> c.deleteScopeMapping(role));
em.createNamedQuery("deleteClientScopeRoleMappingByRole").setParameter("role", roleEntity).executeUpdate();
- session.groups().preRemove(realm, role);
em.flush();
em.remove(roleEntity);
- session.getKeycloakSessionFactory().publish(new RoleContainerModel.RoleRemovedEvent() {
+ session.getKeycloakSessionFactory().publish(roleRemovedEvent(role));
+
+ em.flush();
+ return true;
+
+ }
+
+ public RoleRemovedEvent roleRemovedEvent(RoleModel role) {
+ return new RoleContainerModel.RoleRemovedEvent() {
@Override
public RoleModel getRole() {
return role;
@@ -352,11 +359,7 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, ClientSc
public KeycloakSession getKeycloakSession() {
return session;
}
- });
-
- em.flush();
- return true;
-
+ };
}
@Override
@@ -584,11 +587,14 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, ClientSc
subGroup.setParent(null);
}
- @Override
public void preRemove(RealmModel realm, RoleModel role) {
// GroupProvider method implementation starts here
em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", role.getId()).executeUpdate();
// GroupProvider method implementation ends here
+
+ // ClientProvider implementation
+ String clientScopeMapping = JpaUtils.getTableNameForNativeQuery("SCOPE_MAPPING", em);
+ em.createNativeQuery("delete from " + clientScopeMapping + " where ROLE_ID = :role").setParameter("role", role.getId()).executeUpdate();
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProviderFactory.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProviderFactory.java
index 843d61982d..6a60fed198 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProviderFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProviderFactory.java
@@ -21,16 +21,24 @@ import org.keycloak.Config;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmProviderFactory;
import javax.persistence.EntityManager;
+import org.keycloak.models.ClientModel;
+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;
/**
* @author Bill Burke
* @version $Revision: 1 $
*/
-public class JpaRealmProviderFactory implements RealmProviderFactory {
+public class JpaRealmProviderFactory implements RealmProviderFactory, ProviderEventListener {
+
+ private Runnable onClose;
@Override
public void init(Config.Scope config) {
@@ -38,7 +46,8 @@ public class JpaRealmProviderFactory implements RealmProviderFactory {
@Override
public void postInit(KeycloakSessionFactory factory) {
-
+ factory.register(this);
+ onClose = () -> factory.unregister(this);
}
@Override
@@ -47,13 +56,31 @@ public class JpaRealmProviderFactory implements RealmProviderFactory {
}
@Override
- public RealmProvider create(KeycloakSession session) {
+ public JpaRealmProvider create(KeycloakSession session) {
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
return new JpaRealmProvider(session, em);
}
@Override
public void close() {
+ onClose.run();
}
+ @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;
+ }
+ create(e.getKeycloakSession()).preRemove(realm, role);
+ }
+ }
}
diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java
index bcabc99115..587f8d2c51 100644
--- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java
+++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java
@@ -58,7 +58,7 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi
public MapRootAuthenticationSessionProvider(KeycloakSession session, MapStorage sessionStore) {
this.session = session;
this.sessionStore = sessionStore;
- this.tx = sessionStore.createTransaction();
+ this.tx = sessionStore.createTransaction(session);
session.getTransactionManager().enlistAfterCompletion(tx);
}
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 b4bb27d627..d561b52879 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
@@ -25,6 +25,7 @@ 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.storage.MapKeycloakTransaction;
import org.keycloak.models.map.common.Serialization;
@@ -64,7 +65,7 @@ public class MapClientProvider implements ClientProvider {
this.session = session;
this.clientStore = clientStore;
this.clientRegisteredNodesStore = clientRegisteredNodesStore;
- this.tx = clientStore.createTransaction();
+ this.tx = clientStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
@@ -321,6 +322,18 @@ public class MapClientProvider implements ClientProvider {
.collect(Collectors.toMap(ClientScopeModel::getName, Function.identity()));
}
+ public void preRemove(RealmModel realm, RoleModel role) {
+ ModelCriteriaBuilder mcb = clientStore.createCriteriaBuilder()
+ .compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
+ .compare(SearchableFields.SCOPE_MAPPING_ROLE, Operator.EQ, role.getId());
+ try (Stream toRemove = tx.getUpdatedNotRemoved(mcb)) {
+ toRemove
+ .map(clientEntity -> session.clients().getClientById(realm, clientEntity.getId().toString()))
+ .filter(Objects::nonNull)
+ .forEach(clientModel -> clientModel.deleteScopeMapping(role));
+ }
+ }
+
@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 20e030f12a..24afd9bcb1 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
@@ -22,31 +22,66 @@ 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 java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.keycloak.models.map.storage.MapStorageProvider;
import org.keycloak.models.map.storage.MapStorage;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
/**
*
* @author hmlnarik
*/
-public class MapClientProviderFactory extends AbstractMapProviderFactory implements ClientProviderFactory {
+public class MapClientProviderFactory extends AbstractMapProviderFactory implements ClientProviderFactory, ProviderEventListener {
private final ConcurrentHashMap> REGISTERED_NODES_STORE = new ConcurrentHashMap<>();
private MapStorage store;
+ private Runnable onClose;
+
@Override
public void postInit(KeycloakSessionFactory factory) {
MapStorageProvider sp = (MapStorageProvider) factory.getProviderFactory(MapStorageProvider.class);
this.store = sp.getStorage("clients", UUID.class, MapClientEntity.class, ClientModel.class);
+
+ factory.register(this);
+ onClose = () -> factory.unregister(this);
}
@Override
- public ClientProvider create(KeycloakSession session) {
+ public MapClientProvider create(KeycloakSession session) {
return new MapClientProvider(session, store, REGISTERED_NODES_STORE);
}
+
+ @Override
+ public void close() {
+ super.close();
+ onClose.run();
+ }
+
+ @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;
+ }
+ create(e.getKeycloakSession()).preRemove(realm, role);
+ }
+ }
}
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 ebf52c7f6b..7b996043f6 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
@@ -53,7 +53,7 @@ public class MapClientScopeProvider implements ClientScopeProvider {
public MapClientScopeProvider(KeycloakSession session, MapStorage clientScopeStore) {
this.session = session;
this.clientScopeStore = clientScopeStore;
- this.tx = clientScopeStore.createTransaction();
+ this.tx = clientScopeStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
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 2a805c3d2d..3269855b8a 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
@@ -51,7 +51,7 @@ public class MapGroupProvider implements GroupProvider {
public MapGroupProvider(KeycloakSession session, MapStorage groupStore) {
this.session = session;
this.groupStore = groupStore;
- this.tx = groupStore.createTransaction();
+ this.tx = groupStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
@@ -295,7 +295,6 @@ public class MapGroupProvider implements GroupProvider {
subGroup.setParent(null);
}
- @Override
public void preRemove(RealmModel realm, RoleModel role) {
LOG.tracef("preRemove(%s, %s)%s", realm, role, getShortStackTrace());
ModelCriteriaBuilder mcb = groupStore.createCriteriaBuilder()
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 3e1b7ec525..36ce727f95 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
@@ -17,34 +17,70 @@
package org.keycloak.models.map.group;
+import org.keycloak.models.ClientModel;
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.models.map.common.AbstractMapProviderFactory;
import org.keycloak.models.map.storage.MapStorage;
import org.keycloak.models.map.storage.MapStorageProvider;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
import java.util.UUID;
/**
*
* @author mhajas
*/
-public class MapGroupProviderFactory extends AbstractMapProviderFactory implements GroupProviderFactory {
+public class MapGroupProviderFactory extends AbstractMapProviderFactory implements GroupProviderFactory, ProviderEventListener {
private MapStorage store;
+ private Runnable onClose;
+
@Override
public void postInit(KeycloakSessionFactory factory) {
MapStorageProvider sp = (MapStorageProvider) factory.getProviderFactory(MapStorageProvider.class);
this.store = sp.getStorage("groups", UUID.class, MapGroupEntity.class, GroupModel.class);
+
+ factory.register(this);
+ onClose = () -> factory.unregister(this);
}
@Override
- public GroupProvider create(KeycloakSession session) {
+ public MapGroupProvider create(KeycloakSession session) {
return new MapGroupProvider(session, store);
}
+
+ @Override
+ public void close() {
+ super.close();
+ onClose.run();
+ }
+
+ @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;
+ }
+ create(e.getKeycloakSession()).preRemove(realm, role);
+ }
+ }
}
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 dd436080ef..457ce30ad3 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
@@ -30,7 +30,6 @@ import java.util.Comparator;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
-import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.keycloak.models.map.storage.MapStorage;
@@ -67,7 +66,7 @@ public class MapRoleProvider implements RoleProvider {
public MapRoleProvider(KeycloakSession session, MapStorage roleStore) {
this.session = session;
this.roleStore = roleStore;
- this.tx = roleStore.createTransaction();
+ this.tx = roleStore.createTransaction(session);
session.getTransactionManager().enlist(tx);
}
@@ -210,8 +209,6 @@ public class MapRoleProvider implements RoleProvider {
}
});
- session.groups().preRemove(realm, role);
-
// TODO: Sending an event should be extracted to store layer
session.getKeycloakSessionFactory().publish(new RoleContainerModel.RoleRemovedEvent() {
@Override
diff --git a/model/map/src/main/java/org/keycloak/models/map/storage/MapFieldPredicates.java b/model/map/src/main/java/org/keycloak/models/map/storage/MapFieldPredicates.java
index ef8cc1448e..cb44ee52ff 100644
--- a/model/map/src/main/java/org/keycloak/models/map/storage/MapFieldPredicates.java
+++ b/model/map/src/main/java/org/keycloak/models/map/storage/MapFieldPredicates.java
@@ -62,6 +62,7 @@ public class MapFieldPredicates {
static {
put(CLIENT_PREDICATES, ClientModel.SearchableFields.REALM_ID, AbstractClientEntity::getRealmId);
put(CLIENT_PREDICATES, ClientModel.SearchableFields.CLIENT_ID, AbstractClientEntity::getClientId);
+ put(CLIENT_PREDICATES, ClientModel.SearchableFields.SCOPE_MAPPING_ROLE, MapFieldPredicates::checkScopeMappingRole);
put(CLIENT_SCOPE_PREDICATES, ClientScopeModel.SearchableFields.REALM_ID, AbstractClientScopeEntity::getRealmId);
put(CLIENT_SCOPE_PREDICATES, ClientScopeModel.SearchableFields.NAME, AbstractClientScopeEntity::getName);
@@ -136,6 +137,13 @@ public class MapFieldPredicates {
return s;
}
+ private static MapModelCriteriaBuilder