keycloak-uncached

Details

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 2a78a41..b4ed669 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
@@ -728,8 +728,8 @@ public class RealmCacheSession implements CacheRealmProvider {
             RoleModel model = getDelegate().getRoleById(id, realm);
             if (model == null) return null;
             if (invalidations.contains(id)) return model;
-            if (model.getContainer() instanceof ClientModel) {
-                cached = new CachedClientRole(loaded, ((ClientModel) model.getContainer()).getId(), model, realm);
+            if (model.isClientRole()) {
+                cached = new CachedClientRole(loaded, model.getContainerId(), model, realm);
             } else {
                 cached = new CachedRealmRole(loaded, model, realm);
             }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
index d81f95f..c391f3d 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java
@@ -144,6 +144,21 @@ public class RoleAdapter implements RoleModel {
     }
 
     @Override
+    public boolean isClientRole() {
+        return cached instanceof CachedClientRole;
+    }
+
+    @Override
+    public String getContainerId() {
+        if (isClientRole()) {
+            CachedClientRole appRole = (CachedClientRole)cached;
+            return appRole.getClientId();
+        } else {
+            return realm.getId();
+        }
+    }
+
+    @Override
     public RoleContainerModel getContainer() {
         if (cached instanceof CachedRealmRole) {
             return realm;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 6c081cb..5b7bc8b 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -222,7 +222,7 @@ public class ClientAdapter implements ClientModel, JpaModel<ClientEntity> {
     }
 
     @Override
-         public Set<RoleModel> getRealmScopeMappings() {
+    public Set<RoleModel> getRealmScopeMappings() {
         Set<RoleModel> roleMappings = getScopeMappings();
 
         Set<RoleModel> appRoles = new HashSet<>();
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
index 61cf70c..135d6f4 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
@@ -137,6 +137,17 @@ public class RoleAdapter implements RoleModel, JpaModel<RoleEntity> {
     }
 
     @Override
+    public boolean isClientRole() {
+        return role.isClientRole();
+    }
+
+    @Override
+    public String getContainerId() {
+        if (isClientRole()) return role.getClient().getId();
+        else return realm.getId();
+    }
+
+    @Override
     public RoleContainerModel getContainer() {
         if (role.isClientRole()) {
             return realm.getClientById(role.getClient().getId());
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
index 9af9729..ccc8330 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
@@ -134,6 +134,19 @@ public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implement
     }
 
     @Override
+    public boolean isClientRole() {
+        return role.getClientId() != null;
+    }
+
+
+
+    @Override
+    public String getContainerId() {
+        if (isClientRole()) return role.getClientId();
+        else return role.getRealmId();
+    }
+
+    @Override
     public RoleContainerModel getContainer() {
         if (roleContainer == null) {
             // Compute it
diff --git a/server-spi/src/main/java/org/keycloak/models/RoleModel.java b/server-spi/src/main/java/org/keycloak/models/RoleModel.java
index b9c24d0..ac88058 100755
--- a/server-spi/src/main/java/org/keycloak/models/RoleModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/RoleModel.java
@@ -46,6 +46,10 @@ public interface RoleModel {
 
     Set<RoleModel> getComposites();
 
+    boolean isClientRole();
+
+    String getContainerId();
+
     RoleContainerModel getContainer();
 
     boolean hasRole(RoleModel role);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
index 4edb420..2af9f2b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
@@ -144,6 +144,23 @@ public class ClientModelTest extends AbstractModelTest {
 
     }
 
+    @Test
+    public void testCircularClientScopes() throws Exception {
+        ClientModel scoped1 = realm.addClient("scoped");
+        RoleModel role1 = scoped1.addRole("role1");
+        ClientModel scoped2 = realm.addClient("scoped2");
+        RoleModel role2 = scoped2.addRole("role2");
+        scoped1.addScopeMapping(role2);
+        scoped2.addScopeMapping(role1);
+        commit();
+        realm = session.realms().getRealmByName("original");
+
+        // this hit the circular cache and failed with a stack overflow
+        scoped1 = realm.getClientByClientId("scoped");
+
+
+    }
+
 
     @Test
     public void persist() {