keycloak-aplcache

Merge pull request #4171 from pedroigor/KEYCLOAK-4913 [KEYCLOAK-4913]

5/23/2017 5:40:51 PM

Changes

Details

diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl
index d78ff75..5ea7e93 100755
--- a/distribution/demo-dist/src/main/xslt/standalone.xsl
+++ b/distribution/demo-dist/src/main/xslt/standalone.xsl
@@ -92,7 +92,9 @@
                 <local-cache name="authenticationSessions"/>
                 <local-cache name="offlineSessions"/>
                 <local-cache name="loginFailures"/>
-                <local-cache name="authorization"/>
+                <local-cache name="authorization">
+                    <eviction max-entries="10000" strategy="LRU"/>
+                </local-cache>
                 <local-cache name="actionTokens"/>
                 <local-cache name="work"/>
                 <local-cache name="keys">
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InResource.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InResource.java
new file mode 100644
index 0000000..e316b1c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InResource.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface InResource {
+    String getResourceId();
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InScope.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InScope.java
new file mode 100644
index 0000000..c345677
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InScope.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface InScope {
+    String getScopeId();
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java
index 1cbf044..0b2227a 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java
@@ -9,7 +9,7 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class PolicyListQuery extends AbstractRevisioned implements InResourceServer {
+public class PolicyListQuery extends AbstractRevisioned implements PolicyQuery {
     private final Set<String> policies;
     private final String serverId;
 
@@ -33,4 +33,9 @@ public class PolicyListQuery extends AbstractRevisioned implements InResourceSer
     public Set<String> getPolicies() {
         return policies;
     }
+
+    @Override
+    public boolean isInvalid(Set<String> invalidations) {
+        return invalidations.contains(getId()) || invalidations.contains(getResourceServerId());
+    }
 }
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyQuery.java
new file mode 100644
index 0000000..a844b25
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyQuery.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import java.util.Set;
+
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyQuery extends InResourceServer, Revisioned {
+
+    Set<String> getPolicies();
+    boolean isInvalid(Set<String> invalidations);
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyResourceListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyResourceListQuery.java
new file mode 100755
index 0000000..d0af77b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyResourceListQuery.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyResourceListQuery extends PolicyListQuery implements InResource {
+
+    private final String resourceId;
+
+    public PolicyResourceListQuery(Long revision, String id, String resourceId, Set<String> policies, String serverId) {
+        super(revision, id, policies, serverId);
+        this.resourceId = resourceId;
+    }
+
+    @Override
+    public boolean isInvalid(Set<String> invalidations) {
+        return super.isInvalid(invalidations) || invalidations.contains(getResourceId());
+    }
+
+    @Override
+    public String getResourceId() {
+        return resourceId;
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyScopeListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyScopeListQuery.java
new file mode 100755
index 0000000..7db8a01
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyScopeListQuery.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyScopeListQuery extends PolicyListQuery implements InScope {
+
+    private final String scopeId;
+
+    public PolicyScopeListQuery(Long revision, String id, String scopeId, Set<String> resources, String serverId) {
+        super(revision, id, resources, serverId);
+        this.scopeId = scopeId;
+    }
+
+    @Override
+    public String getScopeId() {
+        return scopeId;
+    }
+
+    @Override
+    public boolean isInvalid(Set<String> invalidations) {
+        return super.isInvalid(invalidations) || invalidations.contains(getScopeId());
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java
index d322b62..d8db81b 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java
@@ -9,7 +9,7 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class ResourceListQuery extends AbstractRevisioned implements InResourceServer {
+public class ResourceListQuery extends AbstractRevisioned implements ResourceQuery, InResourceServer {
     private final Set<String> resources;
     private final String serverId;
 
@@ -33,4 +33,9 @@ public class ResourceListQuery extends AbstractRevisioned implements InResourceS
     public Set<String> getResources() {
         return resources;
     }
+
+    @Override
+    public boolean isInvalid(Set<String> invalidations) {
+        return invalidations.contains(getId()) || invalidations.contains(getResourceServerId());
+    }
 }
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceQuery.java
new file mode 100644
index 0000000..db07bc8
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceQuery.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import java.util.Set;
+
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceQuery extends Revisioned {
+
+    Set<String> getResources();
+    boolean isInvalid(Set<String> invalidations);
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceScopeListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceScopeListQuery.java
new file mode 100755
index 0000000..ee73344
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceScopeListQuery.java
@@ -0,0 +1,26 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceScopeListQuery extends ResourceListQuery implements InScope {
+
+    private final String scopeId;
+
+    public ResourceScopeListQuery(Long revision, String id, String scopeId, Set<String> resources, String serverId) {
+        super(revision, id, resources, serverId);
+        this.scopeId = scopeId;
+    }
+
+    @Override
+    public String getScopeId() {
+        return scopeId;
+    }
+
+    @Override
+    public boolean isInvalid(Set<String> invalidations) {
+        return super.isInvalid(invalidations) || invalidations.contains(getScopeId());
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java
index 3a721ba..759c284 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java
@@ -17,11 +17,11 @@
 
 package org.keycloak.models.cache.infinispan.authorization.events;
 
+import java.util.Set;
+
 import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
 import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
 
-import java.util.Set;
-
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
@@ -29,12 +29,14 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
 
     private String id;
     private String name;
+    private Set<String> resources;
     private String serverId;
 
-    public static PolicyRemovedEvent create(String id, String name, String serverId) {
+    public static PolicyRemovedEvent create(String id, String name, Set<String> resources, String serverId) {
         PolicyRemovedEvent event = new PolicyRemovedEvent();
         event.id = id;
         event.name = name;
+        event.resources = resources;
         event.serverId = serverId;
         return event;
     }
@@ -51,6 +53,6 @@ public class PolicyRemovedEvent extends InvalidationEvent implements Authorizati
 
     @Override
     public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
-        cache.policyRemoval(id, name, serverId, invalidations);
+        cache.policyRemoval(id, name, resources, serverId, invalidations);
     }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java
index 1e1d992..b576bda 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java
@@ -29,12 +29,14 @@ public class PolicyUpdatedEvent extends InvalidationEvent implements Authorizati
 
     private String id;
     private String name;
+    private static Set<String> resources;
     private String serverId;
 
-    public static PolicyUpdatedEvent create(String id, String name, String serverId) {
+    public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, String serverId) {
         PolicyUpdatedEvent event = new PolicyUpdatedEvent();
         event.id = id;
         event.name = name;
+        event.resources = resources;
         event.serverId = serverId;
         return event;
     }
@@ -51,6 +53,6 @@ public class PolicyUpdatedEvent extends InvalidationEvent implements Authorizati
 
     @Override
     public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
-        cache.policyUpdated(id, name, serverId, invalidations);
+        cache.policyUpdated(id, name, resources, serverId, invalidations);
     }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java
index 4e1a31f..15964a6 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java
@@ -29,12 +29,20 @@ public class ResourceRemovedEvent extends InvalidationEvent implements Authoriza
 
     private String id;
     private String name;
+    private String owner;
     private String serverId;
+    private String type;
+    private String uri;
+    private Set<String> scopes;
 
-    public static ResourceRemovedEvent create(String id, String name, String serverId) {
+    public static ResourceRemovedEvent create(String id, String name, String type, String uri, String owner, Set<String> scopes, String serverId) {
         ResourceRemovedEvent event = new ResourceRemovedEvent();
         event.id = id;
         event.name = name;
+        event.type = type;
+        event.uri = uri;
+        event.owner = owner;
+        event.scopes = scopes;
         event.serverId = serverId;
         return event;
     }
@@ -51,6 +59,6 @@ public class ResourceRemovedEvent extends InvalidationEvent implements Authoriza
 
     @Override
     public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
-        cache.resourceRemoval(id, name, serverId, invalidations);
+        cache.resourceRemoval(id, name, type, uri, owner, scopes, serverId, invalidations);
     }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
index 113d5e0..cc30f23 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
@@ -30,11 +30,17 @@ public class ResourceUpdatedEvent extends InvalidationEvent implements Authoriza
     private String id;
     private String name;
     private String serverId;
+    private String type;
+    private String uri;
+    private Set<String> scopes;
 
-    public static ResourceUpdatedEvent create(String id, String name, String serverId) {
+    public static ResourceUpdatedEvent create(String id, String name, String type, String uri, Set<String> scopes, String serverId) {
         ResourceUpdatedEvent event = new ResourceUpdatedEvent();
         event.id = id;
         event.name = name;
+        event.type = type;
+        event.uri = uri;
+        event.scopes = scopes;
         event.serverId = serverId;
         return event;
     }
@@ -51,6 +57,6 @@ public class ResourceUpdatedEvent extends InvalidationEvent implements Authoriza
 
     @Override
     public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
-        cache.resourceUpdated(id, name, serverId, invalidations);
+        cache.resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
     }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
index a8cd379..970d1b9 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
@@ -27,8 +27,6 @@ import org.keycloak.representations.idm.authorization.Logic;
 
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -49,7 +47,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
     @Override
     public Policy getDelegateForUpdate() {
         if (updated == null) {
-            cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+            cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourcesIds(), cached.getResourceServerId());
             updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
             if (updated == null) throw new IllegalStateException("Not found in database");
         }
@@ -98,6 +96,7 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
     @Override
     public void setName(String name) {
         getDelegateForUpdate();
+        cacheSession.registerPolicyInvalidation(cached.getId(), name, cached.getResourcesIds(), cached.getResourceServerId());
         updated.setName(name);
 
     }
@@ -208,7 +207,6 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
     public void addScope(Scope scope) {
         getDelegateForUpdate();
         updated.addScope(scope);
-
     }
 
     @Override
@@ -235,6 +233,9 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
     @Override
     public void addResource(Resource resource) {
         getDelegateForUpdate();
+        HashSet<String> resources = new HashSet<>();
+        resources.add(resource.getId());
+        cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getResourceServerId());
         updated.addResource(resource);
 
     }
@@ -242,6 +243,9 @@ public class PolicyAdapter implements Policy, CachedModel<Policy> {
     @Override
     public void removeResource(Resource resource) {
         getDelegateForUpdate();
+        HashSet<String> resources = new HashSet<>();
+        resources.add(resource.getId());
+        cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), resources, cached.getResourceServerId());
         updated.removeResource(resource);
 
     }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
index d44cc7c..dc721b7 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
@@ -26,6 +26,8 @@ import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -44,7 +46,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
     @Override
     public Resource getDelegateForUpdate() {
         if (updated == null) {
-            cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+            cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
             updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
             if (updated == null) throw new IllegalStateException("Not found in database");
         }
@@ -93,6 +95,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
     @Override
     public void setName(String name) {
         getDelegateForUpdate();
+        cacheSession.registerResourceInvalidation(cached.getId(), name, cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
         updated.setName(name);
 
     }
@@ -124,8 +127,8 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
     @Override
     public void setUri(String uri) {
         getDelegateForUpdate();
+        cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), uri, cached.getScopesIds(), cached.getResourceServerId());
         updated.setUri(uri);
-
     }
 
     @Override
@@ -137,6 +140,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
     @Override
     public void setType(String type) {
         getDelegateForUpdate();
+        cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), type, cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
         updated.setType(type);
 
     }
@@ -164,6 +168,7 @@ public class ResourceAdapter implements Resource, CachedModel<Resource> {
     @Override
     public void updateScopes(Set<Scope> scopes) {
         getDelegateForUpdate();
+        cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUri(), scopes.stream().map(scope1 -> scope1.getId()).collect(Collectors.toSet()), cached.getResourceServerId());
         updated.updateScopes(scopes);
     }
 
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
index 2c86648..7943589 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
@@ -21,7 +21,9 @@ import org.jboss.logging.Logger;
 import org.keycloak.models.cache.infinispan.CacheManager;
 import org.keycloak.models.cache.infinispan.RealmCacheManager;
 import org.keycloak.models.cache.infinispan.authorization.events.AuthorizationCacheInvalidationEvent;
+import org.keycloak.models.cache.infinispan.authorization.stream.InResourcePredicate;
 import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
+import org.keycloak.models.cache.infinispan.authorization.stream.InScopePredicate;
 import org.keycloak.models.cache.infinispan.entities.Revisioned;
 import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
 
@@ -65,28 +67,54 @@ public class StoreFactoryCacheManager extends CacheManager {
     public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) {
         invalidations.add(id);
         invalidations.add(StoreFactoryCacheSession.getScopeByNameCacheKey(name, serverId));
+        invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(id, serverId));
     }
 
     public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) {
         scopeUpdated(id, name, serverId, invalidations);
+        addInvalidations(InScopePredicate.create().scope(id), invalidations);
     }
 
-    public void resourceUpdated(String id, String name, String serverId, Set<String> invalidations) {
+    public void resourceUpdated(String id, String name, String type, String uri, Set<String> scopes, String serverId, Set<String> invalidations) {
         invalidations.add(id);
         invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
+
+        if (type != null) {
+            invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
+            addInvalidations(InResourcePredicate.create().resource(type), invalidations);
+        }
+
+        if (uri != null) {
+            invalidations.add(StoreFactoryCacheSession.getResourceByUriCacheKey(uri, serverId));
+        }
+
+        if (scopes != null) {
+            for (String scope : scopes) {
+                invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(scope, serverId));
+                addInvalidations(InScopePredicate.create().scope(scope), invalidations);
+            }
+        }
     }
 
-    public void resourceRemoval(String id, String name, String serverId, Set<String> invalidations) {
-        resourceUpdated(id, name, serverId, invalidations);
+    public void resourceRemoval(String id, String name, String type, String uri, String owner, Set<String> scopes, String serverId, Set<String> invalidations) {
+        resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
+        invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
+        addInvalidations(InResourcePredicate.create().resource(id), invalidations);
     }
 
-    public void policyUpdated(String id, String name, String serverId, Set<String> invalidations) {
+    public void policyUpdated(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
         invalidations.add(id);
         invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
+
+        if (resources != null) {
+            for (String resource : resources) {
+                invalidations.add(StoreFactoryCacheSession.getPolicyByResource(resource, serverId));
+            }
+        }
     }
 
-    public void policyRemoval(String id, String name, String serverId, Set<String> invalidations) {
-        policyUpdated(id, name, serverId, invalidations);
+    public void policyRemoval(String id, String name, Set<String> resources, String serverId, Set<String> invalidations) {
+        policyUpdated(id, name, resources, serverId, invalidations);
     }
 
 
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
index 87f311b..3e4c205 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -16,6 +16,18 @@
  */
 package org.keycloak.models.cache.infinispan.authorization;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
 import org.jboss.logging.Logger;
 import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.Resource;
@@ -34,7 +46,12 @@ import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourc
 import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
 import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
 import org.keycloak.models.cache.infinispan.authorization.entities.PolicyListQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.PolicyQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.PolicyResourceListQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.PolicyScopeListQuery;
 import org.keycloak.models.cache.infinispan.authorization.entities.ResourceListQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.ResourceQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.ResourceScopeListQuery;
 import org.keycloak.models.cache.infinispan.authorization.entities.ResourceServerListQuery;
 import org.keycloak.models.cache.infinispan.authorization.entities.ScopeListQuery;
 import org.keycloak.models.cache.infinispan.authorization.events.PolicyRemovedEvent;
@@ -48,12 +65,6 @@ import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEve
 import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -233,20 +244,20 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         invalidationEvents.add(ScopeUpdatedEvent.create(id, name, serverId));
     }
 
-    public void registerResourceInvalidation(String id, String name, String serverId) {
-        cache.resourceUpdated(id, name, serverId, invalidations);
+    public void registerResourceInvalidation(String id, String name, String type, String uri, Set<String> scopes, String serverId) {
+        cache.resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
         ResourceAdapter adapter = managedResources.get(id);
         if (adapter != null) adapter.invalidateFlag();
 
-        invalidationEvents.add(ResourceUpdatedEvent.create(id, name, serverId));
+        invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uri, scopes, serverId));
     }
 
-    public void registerPolicyInvalidation(String id, String name, String serverId) {
-        cache.policyUpdated(id, name, serverId, invalidations);
+    public void registerPolicyInvalidation(String id, String name, Set<String> resources, String serverId) {
+        cache.policyUpdated(id, name, resources, serverId, invalidations);
         PolicyAdapter adapter = managedPolicies.get(id);
         if (adapter != null) adapter.invalidateFlag();
 
-        invalidationEvents.add(PolicyUpdatedEvent.create(id, name, serverId));
+        invalidationEvents.add(PolicyUpdatedEvent.create(id, name, resources, serverId));
     }
 
     public ResourceServerStore getResourceServerStoreDelegate() {
@@ -277,10 +288,38 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         return "resource.name." + name + "." + serverId;
     }
 
+    public static String getResourceByOwnerCacheKey(String owner, String serverId) {
+        return "resource.owner." + owner + "." + serverId;
+    }
+
+    public static String getResourceByTypeCacheKey(String type, String serverId) {
+        return "resource.type." + type + "." + serverId;
+    }
+
+    public static String getResourceByUriCacheKey(String uri, String serverId) {
+        return "resource.uri." + uri + "." + serverId;
+    }
+
+    public static String getResourceByScopeCacheKey(String scopeId, String serverId) {
+        return "resource.scope." + scopeId + "." + serverId;
+    }
+
     public static String getPolicyByNameCacheKey(String name, String serverId) {
         return "policy.name." + name + "." + serverId;
     }
 
+    public static String getPolicyByResource(String resourceId, String serverId) {
+        return "policy.resource." + resourceId + "." + serverId;
+    }
+
+    public static String getPolicyByResourceType(String type, String serverId) {
+        return "policy.resource.type." + type + "." + serverId;
+    }
+
+    public static String getPolicyByScope(String scope, String serverId) {
+        return "policy.scope." + scope + "." + serverId;
+    }
+
     public StoreFactory getDelegate() {
         if (delegate != null) return delegate;
         delegate = session.getProvider(StoreFactory.class);
@@ -451,7 +490,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         @Override
         public Resource create(String name, ResourceServer resourceServer, String owner) {
             Resource resource = getResourceStoreDelegate().create(name, resourceServer, owner);
-            registerResourceInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
+            registerResourceInvalidation(resource.getId(), resource.getName(), resource.getType(), resource.getUri(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resourceServer.getId());
             return resource;
         }
 
@@ -462,8 +501,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (resource == null) return;
 
             cache.invalidateObject(id);
-            invalidationEvents.add(ResourceRemovedEvent.create(id, resource.getName(), resource.getResourceServer().getId()));
-            cache.resourceRemoval(id, resource.getName(), resource.getResourceServer().getId(), invalidations);
+            invalidationEvents.add(ResourceRemovedEvent.create(id, resource.getName(), resource.getType(), resource.getUri(), resource.getOwner(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resource.getResourceServer().getId()));
+            cache.resourceRemoval(id, resource.getName(), resource.getType(), resource.getUri(), resource.getOwner(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resource.getResourceServer().getId(), invalidations);
             getResourceStoreDelegate().delete(id);
 
         }
@@ -498,37 +537,37 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         public Resource findByName(String name, String resourceServerId) {
             if (name == null) return null;
             String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
-            ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
-            if (query != null) {
-                logger.tracev("resource by name cache hit: {0}", name);
-            }
-            if (query == null) {
-                Long loaded = cache.getCurrentRevision(cacheKey);
-                Resource model = getResourceStoreDelegate().findByName(name, resourceServerId);
-                if (model == null) return null;
-                if (invalidations.contains(model.getId())) return model;
-                query = new ResourceListQuery(loaded, cacheKey, model.getId(), resourceServerId);
-                cache.addRevisioned(query, startupRevision);
-                return model;
-            } else if (invalidations.contains(cacheKey)) {
-                return getResourceStoreDelegate().findByName(name, resourceServerId);
-            } else {
-                String id = query.getResources().iterator().next();
-                if (invalidations.contains(id)) {
-                    return getResourceStoreDelegate().findByName(name, resourceServerId);
+            List<Resource> result = cacheQuery(cacheKey, ResourceListQuery.class, () -> {
+                Resource resource = getResourceStoreDelegate().findByName(name, resourceServerId);
+
+                if (resource == null) {
+                    return Collections.emptyList();
                 }
-                return findById(id, query.getResourceServerId());
+
+                return Arrays.asList(resource);
+            },
+                    (revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
+
+            if (result.isEmpty()) {
+                return null;
             }
+
+            return result.get(0);
         }
 
         @Override
         public List<Resource> findByOwner(String ownerId, String resourceServerId) {
-            return getResourceStoreDelegate().findByOwner(ownerId, resourceServerId);
+            String cacheKey = getResourceByOwnerCacheKey(ownerId, resourceServerId);
+            return cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByOwner(ownerId, resourceServerId),
+                    (revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
         }
 
         @Override
         public List<Resource> findByUri(String uri, String resourceServerId) {
-            return getResourceStoreDelegate().findByUri(uri, resourceServerId);
+            if (uri == null) return null;
+            String cacheKey = getResourceByUriCacheKey(uri, resourceServerId);
+            return cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByUri(uri, resourceServerId),
+                    (revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
         }
 
         @Override
@@ -543,21 +582,52 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
 
         @Override
         public List<Resource> findByScope(List<String> ids, String resourceServerId) {
-            return getResourceStoreDelegate().findByScope(ids, resourceServerId);
+            if (ids == null) return null;
+            List<Resource> result = new ArrayList<>();
+
+            for (String id : ids) {
+                String cacheKey = getResourceByScopeCacheKey(id, resourceServerId);
+                result.addAll(cacheQuery(cacheKey, ResourceScopeListQuery.class, () -> getResourceStoreDelegate().findByScope(Arrays.asList(id), resourceServerId), (revision, resources) -> new ResourceScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId));
+            }
+
+            return result;
         }
 
          @Override
         public List<Resource> findByType(String type, String resourceServerId) {
-             return getResourceStoreDelegate().findByType(type, resourceServerId);
+             if (type == null) return null;
+             String cacheKey = getResourceByTypeCacheKey(type, resourceServerId);
+             return cacheQuery(cacheKey, ResourceListQuery.class, () -> getResourceStoreDelegate().findByType(type, resourceServerId),
+                     (revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
+        }
+
+        private <R, Q extends ResourceQuery> List<R> cacheQuery(String cacheKey, Class<Q> queryType, Supplier<List<R>> resultSupplier, BiFunction<Long, List<R>, Q> querySupplier, String resourceServerId) {
+            Q query = cache.get(cacheKey, queryType);
+            if (query != null) {
+                logger.tracev("cache hit for key: {0}", cacheKey);
+            }
+            if (query == null) {
+                Long loaded = cache.getCurrentRevision(cacheKey);
+                List<R> model = resultSupplier.get();
+                if (model == null) return null;
+                if (invalidations.contains(cacheKey)) return model;
+                query = querySupplier.apply(loaded, model);
+                cache.addRevisioned(query, startupRevision);
+                return model;
+            } else if (query.isInvalid(invalidations)) {
+                return resultSupplier.get();
+            } else {
+                return query.getResources().stream().map(resourceId -> (R) findById(resourceId, resourceServerId)).collect(Collectors.toList());
+            }
         }
     }
 
     protected class PolicyCache implements PolicyStore {
         @Override
         public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
-            Policy resource = getPolicyStoreDelegate().create(representation, resourceServer);
-            registerPolicyInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
-            return resource;
+            Policy policy = getPolicyStoreDelegate().create(representation, resourceServer);
+            registerPolicyInvalidation(policy.getId(), policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), resourceServer.getId());
+            return policy;
         }
 
         @Override
@@ -567,8 +637,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (policy == null) return;
 
             cache.invalidateObject(id);
-            invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), policy.getResourceServer().getId()));
-            cache.policyRemoval(id, policy.getName(), policy.getResourceServer().getId(), invalidations);
+            invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId()));
+            cache.policyRemoval(id, policy.getName(), policy.getResources().stream().map(resource1 -> resource1.getId()).collect(Collectors.toSet()), policy.getResourceServer().getId(), invalidations);
             getPolicyStoreDelegate().delete(id);
 
         }
@@ -604,27 +674,22 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         public Policy findByName(String name, String resourceServerId) {
             if (name == null) return null;
             String cacheKey = getPolicyByNameCacheKey(name, resourceServerId);
-            PolicyListQuery query = cache.get(cacheKey, PolicyListQuery.class);
-            if (query != null) {
-                logger.tracev("policy by name cache hit: {0}", name);
-            }
-            if (query == null) {
-                Long loaded = cache.getCurrentRevision(cacheKey);
-                Policy model = getPolicyStoreDelegate().findByName(name, resourceServerId);
-                if (model == null) return null;
-                if (invalidations.contains(model.getId())) return model;
-                query = new PolicyListQuery(loaded, cacheKey, model.getId(), resourceServerId);
-                cache.addRevisioned(query, startupRevision);
-                return model;
-            } else if (invalidations.contains(cacheKey)) {
-                return getPolicyStoreDelegate().findByName(name, resourceServerId);
-            } else {
-                String id = query.getPolicies().iterator().next();
-                if (invalidations.contains(id)) {
-                    return getPolicyStoreDelegate().findByName(name, resourceServerId);
+            List<Policy> result = cacheQuery(cacheKey, PolicyListQuery.class, () -> {
+                Policy policy = getPolicyStoreDelegate().findByName(name, resourceServerId);
+
+                if (policy == null) {
+                    return Collections.emptyList();
                 }
-                return findById(id, query.getResourceServerId());
+
+                return Arrays.asList(policy);
+            },
+                    (revision, policies) -> new PolicyListQuery(revision, cacheKey, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
+
+            if (result.isEmpty()) {
+                return null;
             }
+
+            return result.get(0);
         }
 
         @Override
@@ -639,17 +704,29 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
 
         @Override
         public List<Policy> findByResource(String resourceId, String resourceServerId) {
-            return getPolicyStoreDelegate().findByResource(resourceId, resourceServerId);
+            String cacheKey = getPolicyByResource(resourceId, resourceServerId);
+            return cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> getPolicyStoreDelegate().findByResource(resourceId, resourceServerId),
+                    (revision, policies) -> new PolicyResourceListQuery(revision, cacheKey, resourceId, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
         }
 
         @Override
         public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
-            return getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId);
+            String cacheKey = getPolicyByResourceType(resourceType, resourceServerId);
+            return cacheQuery(cacheKey, PolicyResourceListQuery.class, () -> getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId),
+                    (revision, policies) -> new PolicyResourceListQuery(revision, cacheKey, resourceType, policies.stream().map(policy -> policy.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
         }
 
         @Override
         public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
-            return getPolicyStoreDelegate().findByScopeIds(scopeIds, resourceServerId);
+            if (scopeIds == null) return null;
+            List<Policy> result = new ArrayList<>();
+
+            for (String id : scopeIds) {
+                String cacheKey = getPolicyByScope(id, resourceServerId);
+                result.addAll(cacheQuery(cacheKey, PolicyScopeListQuery.class, () -> getPolicyStoreDelegate().findByScopeIds(Arrays.asList(id), resourceServerId), (revision, resources) -> new PolicyScopeListQuery(revision, cacheKey, id, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId));
+            }
+
+            return result;
         }
 
         @Override
@@ -661,6 +738,26 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         public List<Policy> findDependentPolicies(String id, String resourceServerId) {
             return getPolicyStoreDelegate().findDependentPolicies(id, resourceServerId);
         }
+
+        private <R, Q extends PolicyQuery> List<R> cacheQuery(String cacheKey, Class<Q> queryType, Supplier<List<R>> resultSupplier, BiFunction<Long, List<R>, Q> querySupplier, String resourceServerId) {
+            Q query = cache.get(cacheKey, queryType);
+            if (query != null) {
+                logger.tracev("cache hit for key: {0}", cacheKey);
+            }
+            if (query == null) {
+                Long loaded = cache.getCurrentRevision(cacheKey);
+                List<R> model = resultSupplier.get();
+                if (model == null) return null;
+                if (invalidations.contains(cacheKey)) return model;
+                query = querySupplier.apply(loaded, model);
+                cache.addRevisioned(query, startupRevision);
+                return model;
+            } else if (query.isInvalid(invalidations)) {
+                return resultSupplier.get();
+            } else {
+                return query.getPolicies().stream().map(resourceId -> (R) findById(resourceId, resourceServerId)).collect(Collectors.toList());
+            }
+        }
     }
 
 
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java
new file mode 100755
index 0000000..f72de49
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.authorization.stream;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import org.keycloak.models.cache.infinispan.authorization.entities.InResource;
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class InResourcePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
+
+    private String resourceId;
+
+    public static InResourcePredicate create() {
+        return new InResourcePredicate();
+    }
+
+    public InResourcePredicate resource(String id) {
+        resourceId = id;
+        return this;
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, Revisioned> entry) {
+        Object value = entry.getValue();
+        if (value == null) return false;
+        if (!(value instanceof InResource)) return false;
+
+        return resourceId.equals(((InResource)value).getResourceId());
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java
new file mode 100755
index 0000000..3a2a197
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java
@@ -0,0 +1,35 @@
+package org.keycloak.models.cache.infinispan.authorization.stream;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer;
+import org.keycloak.models.cache.infinispan.authorization.entities.InScope;
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class InScopePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
+    private String scopeId;
+
+    public static InScopePredicate create() {
+        return new InScopePredicate();
+    }
+
+    public InScopePredicate scope(String id) {
+        scopeId = id;
+        return this;
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, Revisioned> entry) {
+        Object value = entry.getValue();
+        if (value == null) return false;
+        if (!(value instanceof InScope)) return false;
+
+        return scopeId.equals(((InScope)value).getScopeId());
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index 3a9337e..875a0e0 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -65,6 +65,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -238,10 +239,7 @@ public class AuthorizationTokenService {
 
                     if ("$KC_SCOPE_PERMISSION".equals(key)) {
                         ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
-                        List<Scope> scopes = entry.getValue().stream().map(scopeName -> {
-                            Scope byName = scopeStore.findByName(scopeName, resourceServer.getId());
-                            return byName;
-                        }).collect(Collectors.toList());
+                        List<Scope> scopes = entry.getValue().stream().map(scopeName -> scopeStore.findByName(scopeName, resourceServer.getId())).filter(scope -> Objects.nonNull(scope)).collect(Collectors.toList());
                         return Arrays.asList(new ResourcePermission(null, scopes, resourceServer)).stream();
                     } else {
                         Resource entryResource = storeFactory.getResourceStore().findById(key, resourceServer.getId());
diff --git a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
index 463ff0b..71058ac 100644
--- a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
@@ -23,8 +23,10 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -319,10 +321,7 @@ public class EntitlementService {
 
                     if ("$KC_SCOPE_PERMISSION".equals(key)) {
                         ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
-                        List<Scope> scopes = entry.getValue().stream().map(scopeName -> {
-                            Scope byName = scopeStore.findByName(scopeName, resourceServer.getId());
-                            return byName;
-                        }).collect(Collectors.toList());
+                        List<Scope> scopes = entry.getValue().stream().map(scopeName -> scopeStore.findByName(scopeName, resourceServer.getId())).filter(scope -> Objects.nonNull(scope)).collect(Collectors.toList());
                         return Arrays.asList(new ResourcePermission(null, scopes, resourceServer)).stream();
                     } else {
                         Resource entryResource = storeFactory.getResourceStore().findById(key, resourceServer.getId());
diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan2.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan2.xml
index a76162b..839ecdf 100755
--- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan2.xml
+++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan2.xml
@@ -37,7 +37,7 @@
                 <local-cache name="loginFailures"/>
                 <local-cache name="work"/>
                 <local-cache name="authorization">
-                    <eviction max-entries="100" strategy="LRU"/>
+                    <eviction max-entries="10000" strategy="LRU"/>
                 </local-cache>
                 <local-cache name="keys">
                     <eviction max-entries="1000" strategy="LRU"/>