keycloak-aplcache
Changes
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java 8(+2 -6)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java 4(+1 -3)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java 3(+2 -1)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java 10(+2 -8)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java 3(+2 -1)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java 7(+2 -5)
authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java 16(+7 -9)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java 21(+19 -2)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java 2(+2 -0)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/AbstractCachedStore.java 73(+0 -73)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java 500(+0 -500)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java 172(+0 -172)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java 321(+0 -321)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java 231(+0 -231)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java 166(+0 -166)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/StoreFactoryCacheManager.java 72(+0 -72)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedPolicy.java 122(+5 -117)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResource.java 61(+5 -56)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java 32(+5 -27)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedScope.java 49(+5 -44)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/InResourceServer.java 21(+5 -16)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java 36(+36 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java 36(+36 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java 29(+29 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java 36(+36 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/AuthorizationCacheInvalidationEvent.java 29(+7 -22)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java 56(+56 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java 56(+56 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java 56(+56 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java 54(+54 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java 54(+54 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java 56(+56 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java 56(+56 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java 56(+56 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/InfinispanCacheStoreFactoryProviderFactory.java 87(+50 -37)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java 280(+280 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java 184(+184 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java 127(+127 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java 127(+127 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java 93(+93 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java 667(+667 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java 35(+35 -0)
model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory 2(+1 -1)
model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java 30(+23 -7)
model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java 5(+3 -2)
model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java 52(+42 -10)
model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java 106(+106 -0)
server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java 2(+2 -0)
server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java 6(+3 -3)
server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java 3(+3 -0)
services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java 4(+4 -0)
Details
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
index d061357..49a54eb 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
@@ -107,7 +107,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
if (clients.isEmpty()) {
policyStore.delete(policy.getId());
} else {
- policy.getConfig().put("clients", JsonSerialization.writeValueAsString(clients));
+ policy.putConfig("clients", JsonSerialization.writeValueAsString(clients));
}
} catch (IOException e) {
throw new RuntimeException("Error while synchronizing clients with policy [" + policy.getName() + "].", e);
@@ -152,11 +152,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
}
try {
- Map<String, String> config = policy.getConfig();
-
- config.put("clients", JsonSerialization.writeValueAsString(updatedClients));
-
- policy.setConfig(config);
+ policy.putConfig("clients", JsonSerialization.writeValueAsString(updatedClients));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize clients", cause);
}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
index 1a1ed34..3e68d7f 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
@@ -70,9 +70,7 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRe
}
private void updatePolicy(Policy policy, String code) {
- Map<String, String> config = policy.getConfig();
- config.put("code", code);
- policy.setConfig(config);
+ policy.putConfig("code", code);
}
@Override
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
index 6ea7230..1de28f5 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
@@ -1,5 +1,6 @@
package org.keycloak.authorization.policy.provider.resource;
+import java.util.HashMap;
import java.util.Map;
import org.keycloak.Config;
@@ -64,7 +65,7 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory<Reso
//TODO: remove this check once we migrate to new API
if (ResourcePermissionRepresentation.class.equals(representation.getClass())) {
ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation);
- Map<String, String> config = policy.getConfig();
+ Map<String, String> config = new HashMap(policy.getConfig());
config.compute("defaultResourceType", (key, value) -> {
String resourceType = resourcePermission.getResourceType();
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
index 03ea156..64bcf49 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
@@ -163,11 +163,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
}
try {
- Map<String, String> config = policy.getConfig();
-
- config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
-
- policy.setConfig(config);
+ policy.putConfig("roles", JsonSerialization.writeValueAsString(updatedRoles));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize roles", cause);
}
@@ -224,9 +220,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
if (roles.isEmpty()) {
policyStore.delete(policy.getId());
} else {
- Map<String, String> config = policy.getConfig();
- config.put("roles", JsonSerialization.writeValueAsString(roles));
- policy.setConfig(config);
+ policy.putConfig("roles", JsonSerialization.writeValueAsString(roles));
}
} catch (IOException e) {
throw new RuntimeException("Error while synchronizing roles with policy [" + policy.getName() + "].", e);
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
index a3958b9..fc69f3b 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
@@ -1,6 +1,7 @@
package org.keycloak.authorization.policy.provider.time;
import java.text.SimpleDateFormat;
+import java.util.HashMap;
import java.util.Map;
import org.keycloak.Config;
@@ -118,7 +119,7 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory<TimePoli
validateFormat(noa);
}
- Map<String, String> config = policy.getConfig();
+ Map<String, String> config = new HashMap(policy.getConfig());
config.compute("nbf", (s, s2) -> nbf != null ? nbf : null);
config.compute("noa", (s, s2) -> noa != null ? noa : null);
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
index e4bbaf9..a21bf74 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
@@ -138,11 +138,8 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
}
try {
- Map<String, String> config = policy.getConfig();
- config.put("users", JsonSerialization.writeValueAsString(updatedUsers));
-
- policy.setConfig(config);
+ policy.putConfig("users", JsonSerialization.writeValueAsString(updatedUsers));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize users", cause);
}
@@ -181,7 +178,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
if (users.isEmpty()) {
policyStore.delete(policy.getId());
} else {
- policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
+ policy.putConfig("users", JsonSerialization.writeValueAsString(users));
}
} catch (IOException e) {
throw new RuntimeException("Error while synchronizing users with policy [" + policy.getName() + "].", e);
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
index 1fb3c1f..0a71317 100644
--- a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
@@ -120,17 +120,15 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory<RulePo
}
private void updateConfig(Policy policy, RulePolicyRepresentation representation) {
- Map<String, String> config = policy.getConfig();
- config.put("mavenArtifactGroupId", representation.getArtifactGroupId());
- config.put("mavenArtifactId", representation.getArtifactId());
- config.put("mavenArtifactVersion", representation.getArtifactVersion());
- config.put("scannerPeriod", representation.getScannerPeriod());
- config.put("scannerPeriodUnit", representation.getScannerPeriodUnit());
- config.put("sessionName", representation.getSessionName());
- config.put("moduleName", representation.getModuleName());
+ policy.putConfig("mavenArtifactGroupId", representation.getArtifactGroupId());
+ policy.putConfig("mavenArtifactId", representation.getArtifactId());
+ policy.putConfig("mavenArtifactVersion", representation.getArtifactVersion());
+ policy.putConfig("scannerPeriod", representation.getScannerPeriod());
+ policy.putConfig("scannerPeriodUnit", representation.getScannerPeriodUnit());
+ policy.putConfig("sessionName", representation.getSessionName());
+ policy.putConfig("moduleName", representation.getModuleName());
- policy.setConfig(config);
}
void update(Policy policy) {
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 1394d80..17ae121 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
@@ -126,6 +126,16 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
+ long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
+ authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
+ ? 2 * authzRevisionsMaxEntries
+ : InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
+
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
+ cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
+
+
+
logger.debugv("Using container managed Infinispan cache container, lookup={1}", cacheContainerLookup);
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve cache container", e);
@@ -157,6 +167,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
Configuration modelCacheConfiguration = modelCacheConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, modelCacheConfiguration);
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, modelCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_CACHE_NAME, modelCacheConfiguration);
ConfigurationBuilder sessionConfigBuilder = new ConfigurationBuilder();
@@ -186,14 +197,12 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
- cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, sessionCacheConfiguration);
// Retrieve caches to enforce rebalance
cacheManager.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, true);
- cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder();
@@ -236,6 +245,14 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, getActionTokenCacheConfig());
cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
+
+ long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
+ authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
+ ? 2 * authzRevisionsMaxEntries
+ : InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
+
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
+ cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
}
private Configuration getRevisionCacheConfig(long maxEntries) {
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
index 8e190cd..8618a69 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
@@ -39,6 +39,8 @@ public interface InfinispanConnectionProvider extends Provider {
String AUTHENTICATION_SESSIONS_CACHE_NAME = "authenticationSessions";
String WORK_CACHE_NAME = "work";
String AUTHORIZATION_CACHE_NAME = "authorization";
+ String AUTHORIZATION_REVISIONS_CACHE_NAME = "authorizationRevisions";
+ int AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX = 20000;
String ACTION_TOKEN_CACHE = "actionTokens";
int ACTION_TOKEN_CACHE_DEFAULT_MAX = -1;
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
new file mode 100755
index 0000000..1cbf044
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PolicyListQuery extends AbstractRevisioned implements InResourceServer {
+ private final Set<String> policies;
+ private final String serverId;
+
+ public PolicyListQuery(Long revision, String id, String policyId, String serverId) {
+ super(revision, id);
+ this.serverId = serverId;
+ policies = new HashSet<>();
+ policies.add(policyId);
+ }
+ public PolicyListQuery(Long revision, String id, Set<String> policies, String serverId) {
+ super(revision, id);
+ this.serverId = serverId;
+ this.policies = policies;
+ }
+
+ @Override
+ public String getResourceServerId() {
+ return serverId;
+ }
+
+ public Set<String> getPolicies() {
+ return policies;
+ }
+}
\ 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
new file mode 100755
index 0000000..d322b62
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceListQuery extends AbstractRevisioned implements InResourceServer {
+ private final Set<String> resources;
+ private final String serverId;
+
+ public ResourceListQuery(Long revision, String id, String resourceId, String serverId) {
+ super(revision, id);
+ this.serverId = serverId;
+ resources = new HashSet<>();
+ resources.add(resourceId);
+ }
+ public ResourceListQuery(Long revision, String id, Set<String> resources, String serverId) {
+ super(revision, id);
+ this.serverId = serverId;
+ this.resources = resources;
+ }
+
+ @Override
+ public String getResourceServerId() {
+ return serverId;
+ }
+
+ public Set<String> getResources() {
+ return resources;
+ }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java
new file mode 100755
index 0000000..7cfc122
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+import org.keycloak.models.cache.infinispan.entities.RealmQuery;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceServerListQuery extends AbstractRevisioned {
+ private final Set<String> servers;
+
+ public ResourceServerListQuery(Long revision, String id, String serverId) {
+ super(revision, id);
+ servers = new HashSet<>();
+ servers.add(serverId);
+ }
+ public ResourceServerListQuery(Long revision, String id, Set<String> servers) {
+ super(revision, id);
+ this.servers = servers;
+ }
+
+ public Set<String> getResourceServers() {
+ return servers;
+ }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java
new file mode 100755
index 0000000..2579e61
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeListQuery extends AbstractRevisioned implements InResourceServer {
+ private final Set<String> scopes;
+ private final String serverId;
+
+ public ScopeListQuery(Long revision, String id, String scopeId, String serverId) {
+ super(revision, id);
+ this.serverId = serverId;
+ scopes = new HashSet<>();
+ scopes.add(scopeId);
+ }
+ public ScopeListQuery(Long revision, String id, Set<String> scopes, String serverId) {
+ super(revision, id);
+ this.serverId = serverId;
+ this.scopes = scopes;
+ }
+
+ @Override
+ public String getResourceServerId() {
+ return serverId;
+ }
+
+ public Set<String> getScopes() {
+ return scopes;
+ }
+}
\ 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
new file mode 100644
index 0000000..3a721ba
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class PolicyRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String name;
+ private String serverId;
+
+ public static PolicyRemovedEvent create(String id, String name, String serverId) {
+ PolicyRemovedEvent event = new PolicyRemovedEvent();
+ event.id = id;
+ event.name = name;
+ event.serverId = serverId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PolicyRemovedEvent [ id=%s, name=%s]", id, name);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.policyRemoval(id, name, 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
new file mode 100644
index 0000000..1e1d992
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class PolicyUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String name;
+ private String serverId;
+
+ public static PolicyUpdatedEvent create(String id, String name, String serverId) {
+ PolicyUpdatedEvent event = new PolicyUpdatedEvent();
+ event.id = id;
+ event.name = name;
+ event.serverId = serverId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PolicyUpdatedEvent [ id=%s, name=%s ]", id, name);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.policyUpdated(id, name, 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
new file mode 100644
index 0000000..4e1a31f
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class ResourceRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String name;
+ private String serverId;
+
+ public static ResourceRemovedEvent create(String id, String name, String serverId) {
+ ResourceRemovedEvent event = new ResourceRemovedEvent();
+ event.id = id;
+ event.name = name;
+ event.serverId = serverId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ResourceRemovedEvent [ id=%s, name=%s ]", id, name);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.resourceRemoval(id, name, serverId, invalidations);
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
new file mode 100644
index 0000000..fbe5a7a
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
@@ -0,0 +1,54 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class ResourceServerRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String clientId;
+
+ public static ResourceServerRemovedEvent create(String id, String clientId) {
+ ResourceServerRemovedEvent event = new ResourceServerRemovedEvent();
+ event.id = id;
+ event.clientId = clientId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.resourceServerRemoval(id, clientId, invalidations);
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
new file mode 100644
index 0000000..2034c9b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
@@ -0,0 +1,54 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class ResourceServerUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String clientId;
+
+ public static ResourceServerUpdatedEvent create(String id, String clientId) {
+ ResourceServerUpdatedEvent event = new ResourceServerUpdatedEvent();
+ event.id = id;
+ event.clientId = clientId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.resourceServerUpdated(id, clientId, 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
new file mode 100644
index 0000000..113d5e0
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class ResourceUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String name;
+ private String serverId;
+
+ public static ResourceUpdatedEvent create(String id, String name, String serverId) {
+ ResourceUpdatedEvent event = new ResourceUpdatedEvent();
+ event.id = id;
+ event.name = name;
+ event.serverId = serverId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ResourceUpdatedEvent [ id=%s, name=%s ]", id, name);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.resourceUpdated(id, name, serverId, invalidations);
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java
new file mode 100644
index 0000000..eb2747c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class ScopeRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String name;
+ private String serverId;
+
+ public static ScopeRemovedEvent create(String id, String name, String serverId) {
+ ScopeRemovedEvent event = new ScopeRemovedEvent();
+ event.id = id;
+ event.name = name;
+ event.serverId = serverId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ScopeRemovedEvent [ id=%s, name=%s]", id, name);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.scopeRemoval(id, name, serverId, invalidations);
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java
new file mode 100644
index 0000000..9fbbd44
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.events;
+
+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>
+ */
+public class ScopeUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+ private String id;
+ private String name;
+ private String serverId;
+
+ public static ScopeUpdatedEvent create(String id, String name, String serverId) {
+ ScopeUpdatedEvent event = new ScopeUpdatedEvent();
+ event.id = id;
+ event.name = name;
+ event.serverId = serverId;
+ return event;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ScopeUpdatedEvent [ id=%s, name=%s ]", id, name);
+ }
+
+ @Override
+ public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+ cache.scopeUpdated(id, name, 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
new file mode 100644
index 0000000..a8cd379
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
@@ -0,0 +1,280 @@
+/*
+ * 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;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedPolicy;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+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;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PolicyAdapter implements Policy, CachedModel<Policy> {
+ protected CachedPolicy cached;
+ protected StoreFactoryCacheSession cacheSession;
+ protected Policy updated;
+
+ public PolicyAdapter(CachedPolicy cached, StoreFactoryCacheSession cacheSession) {
+ this.cached = cached;
+ this.cacheSession = cacheSession;
+ }
+
+ @Override
+ public Policy getDelegateForUpdate() {
+ if (updated == null) {
+ cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+ updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ }
+ return updated;
+ }
+
+ protected boolean invalidated;
+
+ protected void invalidateFlag() {
+ invalidated = true;
+
+ }
+
+ @Override
+ public void invalidate() {
+ invalidated = true;
+ getDelegateForUpdate();
+ }
+
+ @Override
+ public long getCacheTimestamp() {
+ return cached.getCacheTimestamp();
+ }
+
+ protected boolean isUpdated() {
+ if (updated != null) return true;
+ if (!invalidated) return false;
+ updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ return true;
+ }
+
+
+ @Override
+ public String getId() {
+ if (isUpdated()) return updated.getId();
+ return cached.getId();
+ }
+
+ @Override
+ public String getName() {
+ if (isUpdated()) return updated.getName();
+ return cached.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ getDelegateForUpdate();
+ updated.setName(name);
+
+ }
+
+ @Override
+ public ResourceServer getResourceServer() {
+ return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
+ }
+
+ @Override
+ public String getType() {
+ if (isUpdated()) return updated.getType();
+ return cached.getType();
+ }
+
+ @Override
+ public DecisionStrategy getDecisionStrategy() {
+ if (isUpdated()) return updated.getDecisionStrategy();
+ return cached.getDecisionStrategy();
+ }
+
+ @Override
+ public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+ getDelegateForUpdate();
+ updated.setDecisionStrategy(decisionStrategy);
+
+ }
+
+ @Override
+ public Logic getLogic() {
+ if (isUpdated()) return updated.getLogic();
+ return cached.getLogic();
+ }
+
+ @Override
+ public void setLogic(Logic logic) {
+ getDelegateForUpdate();
+ updated.setLogic(logic);
+
+ }
+
+ @Override
+ public Map<String, String> getConfig() {
+ if (isUpdated()) return updated.getConfig();
+ return cached.getConfig();
+ }
+
+ @Override
+ public void setConfig(Map<String, String> config) {
+ getDelegateForUpdate();
+ updated.setConfig(config);
+
+ }
+
+ @Override
+ public void removeConfig(String name) {
+ getDelegateForUpdate();
+ updated.removeConfig(name);
+
+ }
+
+ @Override
+ public void putConfig(String name, String value) {
+ getDelegateForUpdate();
+ updated.putConfig(name, value);
+ }
+
+ @Override
+ public String getDescription() {
+ if (isUpdated()) return updated.getDescription();
+ return cached.getDescription();
+ }
+
+ @Override
+ public void setDescription(String description) {
+ getDelegateForUpdate();
+ updated.setDescription(description);
+ }
+
+ protected Set<Policy> associatedPolicies;
+
+ @Override
+ public Set<Policy> getAssociatedPolicies() {
+ if (isUpdated()) return updated.getAssociatedPolicies();
+ if (associatedPolicies != null) return associatedPolicies;
+ associatedPolicies = new HashSet<>();
+ for (String scopeId : cached.getAssociatedPoliciesIds()) {
+ associatedPolicies.add(cacheSession.getPolicyStore().findById(scopeId, cached.getResourceServerId()));
+ }
+ associatedPolicies = Collections.unmodifiableSet(associatedPolicies);
+ return associatedPolicies;
+ }
+
+ protected Set<Resource> resources;
+ @Override
+ public Set<Resource> getResources() {
+ if (isUpdated()) return updated.getResources();
+ if (resources != null) return resources;
+ resources = new HashSet<>();
+ for (String resourceId : cached.getResourcesIds()) {
+ resources.add(cacheSession.getResourceStore().findById(resourceId, cached.getResourceServerId()));
+ }
+ resources = Collections.unmodifiableSet(resources);
+ return resources;
+ }
+
+ @Override
+ public void addScope(Scope scope) {
+ getDelegateForUpdate();
+ updated.addScope(scope);
+
+ }
+
+ @Override
+ public void removeScope(Scope scope) {
+ getDelegateForUpdate();
+ updated.removeScope(scope);
+
+ }
+
+ @Override
+ public void addAssociatedPolicy(Policy associatedPolicy) {
+ getDelegateForUpdate();
+ updated.addAssociatedPolicy(associatedPolicy);
+
+ }
+
+ @Override
+ public void removeAssociatedPolicy(Policy associatedPolicy) {
+ getDelegateForUpdate();
+ updated.removeAssociatedPolicy(associatedPolicy);
+
+ }
+
+ @Override
+ public void addResource(Resource resource) {
+ getDelegateForUpdate();
+ updated.addResource(resource);
+
+ }
+
+ @Override
+ public void removeResource(Resource resource) {
+ getDelegateForUpdate();
+ updated.removeResource(resource);
+
+ }
+
+ protected Set<Scope> scopes;
+
+ @Override
+ public Set<Scope> getScopes() {
+ if (isUpdated()) return updated.getScopes();
+ if (scopes != null) return scopes;
+ scopes = new HashSet<>();
+ for (String scopeId : cached.getScopesIds()) {
+ scopes.add(cacheSession.getScopeStore().findById(scopeId, cached.getResourceServerId()));
+ }
+ scopes = Collections.unmodifiableSet(scopes);
+ return scopes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof Policy)) return false;
+
+ Policy that = (Policy) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+
+
+
+}
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
new file mode 100644
index 0000000..d44cc7c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
@@ -0,0 +1,184 @@
+/*
+ * 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;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResource;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceAdapter implements Resource, CachedModel<Resource> {
+ protected CachedResource cached;
+ protected StoreFactoryCacheSession cacheSession;
+ protected Resource updated;
+
+ public ResourceAdapter(CachedResource cached, StoreFactoryCacheSession cacheSession) {
+ this.cached = cached;
+ this.cacheSession = cacheSession;
+ }
+
+ @Override
+ public Resource getDelegateForUpdate() {
+ if (updated == null) {
+ cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+ updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ }
+ return updated;
+ }
+
+ protected boolean invalidated;
+
+ protected void invalidateFlag() {
+ invalidated = true;
+
+ }
+
+ @Override
+ public void invalidate() {
+ invalidated = true;
+ getDelegateForUpdate();
+ }
+
+ @Override
+ public long getCacheTimestamp() {
+ return cached.getCacheTimestamp();
+ }
+
+ protected boolean isUpdated() {
+ if (updated != null) return true;
+ if (!invalidated) return false;
+ updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ return true;
+ }
+
+
+ @Override
+ public String getId() {
+ if (isUpdated()) return updated.getId();
+ return cached.getId();
+ }
+
+ @Override
+ public String getName() {
+ if (isUpdated()) return updated.getName();
+ return cached.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ getDelegateForUpdate();
+ updated.setName(name);
+
+ }
+
+ @Override
+ public String getIconUri() {
+ if (isUpdated()) return updated.getIconUri();
+ return cached.getIconUri();
+ }
+
+ @Override
+ public void setIconUri(String iconUri) {
+ getDelegateForUpdate();
+ updated.setIconUri(iconUri);
+
+ }
+
+ @Override
+ public ResourceServer getResourceServer() {
+ return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
+ }
+
+ @Override
+ public String getUri() {
+ if (isUpdated()) return updated.getUri();
+ return cached.getUri();
+ }
+
+ @Override
+ public void setUri(String uri) {
+ getDelegateForUpdate();
+ updated.setUri(uri);
+
+ }
+
+ @Override
+ public String getType() {
+ if (isUpdated()) return updated.getType();
+ return cached.getType();
+ }
+
+ @Override
+ public void setType(String type) {
+ getDelegateForUpdate();
+ updated.setType(type);
+
+ }
+
+ protected List<Scope> scopes;
+
+ @Override
+ public List<Scope> getScopes() {
+ if (isUpdated()) return updated.getScopes();
+ if (scopes != null) return scopes;
+ scopes = new LinkedList<>();
+ for (String scopeId : cached.getScopesIds()) {
+ scopes.add(cacheSession.getScopeStore().findById(scopeId, cached.getResourceServerId()));
+ }
+ scopes = Collections.unmodifiableList(scopes);
+ return scopes;
+ }
+
+ @Override
+ public String getOwner() {
+ if (isUpdated()) return updated.getOwner();
+ return cached.getOwner();
+ }
+
+ @Override
+ public void updateScopes(Set<Scope> scopes) {
+ getDelegateForUpdate();
+ updated.updateScopes(scopes);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof Resource)) return false;
+
+ Resource that = (Resource) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
new file mode 100644
index 0000000..bb3ec6c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * 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;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceServerAdapter implements ResourceServer, CachedModel<ResourceServer> {
+ protected CachedResourceServer cached;
+ protected StoreFactoryCacheSession cacheSession;
+ protected ResourceServer updated;
+
+ public ResourceServerAdapter(CachedResourceServer cached, StoreFactoryCacheSession cacheSession) {
+ this.cached = cached;
+ this.cacheSession = cacheSession;
+ }
+
+ @Override
+ public ResourceServer getDelegateForUpdate() {
+ if (updated == null) {
+ cacheSession.registerResourceServerInvalidation(cached.getId(), cached.getClientId());
+ updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ }
+ return updated;
+ }
+
+ protected boolean invalidated;
+
+ protected void invalidateFlag() {
+ invalidated = true;
+
+ }
+
+ @Override
+ public void invalidate() {
+ invalidated = true;
+ getDelegateForUpdate();
+ }
+
+ @Override
+ public long getCacheTimestamp() {
+ return cached.getCacheTimestamp();
+ }
+
+ protected boolean isUpdated() {
+ if (updated != null) return true;
+ if (!invalidated) return false;
+ updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ return true;
+ }
+
+
+ @Override
+ public String getId() {
+ if (isUpdated()) return updated.getId();
+ return cached.getId();
+ }
+
+ @Override
+ public String getClientId() {
+ if (isUpdated()) return updated.getClientId();
+ return cached.getClientId();
+ }
+
+ @Override
+ public boolean isAllowRemoteResourceManagement() {
+ if (isUpdated()) return updated.isAllowRemoteResourceManagement();
+ return cached.isAllowRemoteResourceManagement();
+ }
+
+ @Override
+ public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+ getDelegateForUpdate();
+ updated.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+ }
+
+ @Override
+ public PolicyEnforcementMode getPolicyEnforcementMode() {
+ if (isUpdated()) return updated.getPolicyEnforcementMode();
+ return cached.getPolicyEnforcementMode();
+ }
+
+ @Override
+ public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+ getDelegateForUpdate();
+ updated.setPolicyEnforcementMode(enforcementMode);
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof ResourceServer)) return false;
+
+ ResourceServer that = (ResourceServer) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java
new file mode 100644
index 0000000..d90b27a
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * 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;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeAdapter implements Scope, CachedModel<Scope> {
+ protected CachedScope cached;
+ protected StoreFactoryCacheSession cacheSession;
+ protected Scope updated;
+
+ public ScopeAdapter(CachedScope cached, StoreFactoryCacheSession cacheSession) {
+ this.cached = cached;
+ this.cacheSession = cacheSession;
+ }
+
+ @Override
+ public Scope getDelegateForUpdate() {
+ if (updated == null) {
+ cacheSession.registerScopeInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+ updated = cacheSession.getScopeStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ }
+ return updated;
+ }
+
+ protected boolean invalidated;
+
+ protected void invalidateFlag() {
+ invalidated = true;
+
+ }
+
+ @Override
+ public void invalidate() {
+ invalidated = true;
+ getDelegateForUpdate();
+ }
+
+ @Override
+ public long getCacheTimestamp() {
+ return cached.getCacheTimestamp();
+ }
+
+ protected boolean isUpdated() {
+ if (updated != null) return true;
+ if (!invalidated) return false;
+ updated = cacheSession.getScopeStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ return true;
+ }
+
+
+ @Override
+ public String getId() {
+ if (isUpdated()) return updated.getId();
+ return cached.getId();
+ }
+
+ @Override
+ public String getName() {
+ if (isUpdated()) return updated.getName();
+ return cached.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ getDelegateForUpdate();
+ updated.setName(name);
+
+ }
+
+ @Override
+ public String getIconUri() {
+ if (isUpdated()) return updated.getIconUri();
+ return cached.getIconUri();
+ }
+
+ @Override
+ public void setIconUri(String iconUri) {
+ getDelegateForUpdate();
+ updated.setIconUri(iconUri);
+
+ }
+
+ @Override
+ public ResourceServer getResourceServer() {
+ return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof Scope)) return false;
+
+ Scope that = (Scope) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+
+}
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
new file mode 100644
index 0000000..2c86648
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+import org.infinispan.Cache;
+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.InResourceServerPredicate;
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class StoreFactoryCacheManager extends CacheManager {
+ private static final Logger logger = Logger.getLogger(RealmCacheManager.class);
+
+ public StoreFactoryCacheManager(Cache<String, Revisioned> cache, Cache<String, Long> revisions) {
+ super(cache, revisions);
+ }
+ @Override
+ protected Logger getLogger() {
+ return logger;
+ }
+
+ @Override
+ protected void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations) {
+ if (event instanceof AuthorizationCacheInvalidationEvent) {
+ invalidations.add(event.getId());
+
+ ((AuthorizationCacheInvalidationEvent) event).addInvalidations(this, invalidations);
+ }
+ }
+
+ public void resourceServerUpdated(String id, String clientId, Set<String> invalidations) {
+ invalidations.add(id);
+ invalidations.add(StoreFactoryCacheSession.getResourceServerByClientCacheKey(clientId));
+ }
+
+ public void resourceServerRemoval(String id, String name, Set<String> invalidations) {
+ resourceServerUpdated(id, name, invalidations);
+
+ addInvalidations(InResourceServerPredicate.create().resourceServer(id), invalidations);
+ }
+
+ public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) {
+ invalidations.add(id);
+ invalidations.add(StoreFactoryCacheSession.getScopeByNameCacheKey(name, serverId));
+ }
+
+ public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) {
+ scopeUpdated(id, name, serverId, invalidations);
+ }
+
+ public void resourceUpdated(String id, String name, String serverId, Set<String> invalidations) {
+ invalidations.add(id);
+ invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
+ }
+
+ public void resourceRemoval(String id, String name, String serverId, Set<String> invalidations) {
+ resourceUpdated(id, name, serverId, invalidations);
+ }
+
+ public void policyUpdated(String id, String name, String serverId, Set<String> invalidations) {
+ invalidations.add(id);
+ invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
+ }
+
+ public void policyRemoval(String id, String name, String serverId, Set<String> invalidations) {
+ policyUpdated(id, name, 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
new file mode 100644
index 0000000..87f311b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -0,0 +1,667 @@
+/*
+ * 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;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedPolicy;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResource;
+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.ResourceListQuery;
+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;
+import org.keycloak.models.cache.infinispan.authorization.events.PolicyUpdatedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceRemovedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerRemovedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerUpdatedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceUpdatedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ScopeRemovedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEvent;
+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 $
+ */
+public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
+ protected static final Logger logger = Logger.getLogger(StoreFactoryCacheSession.class);
+
+ protected StoreFactoryCacheManager cache;
+ protected boolean transactionActive;
+ protected boolean setRollbackOnly;
+
+ protected Map<String, ResourceServerAdapter> managedResourceServers = new HashMap<>();
+ protected Map<String, ScopeAdapter> managedScopes = new HashMap<>();
+ protected Map<String, ResourceAdapter> managedResources = new HashMap<>();
+ protected Map<String, PolicyAdapter> managedPolicies = new HashMap<>();
+ protected Set<String> invalidations = new HashSet<>();
+ protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
+
+ protected boolean clearAll;
+ protected final long startupRevision;
+ protected StoreFactory delegate;
+ protected KeycloakSession session;
+ protected ResourceServerCache resourceServerCache;
+ protected ScopeCache scopeCache;
+ protected ResourceCache resourceCache;
+ protected PolicyCache policyCache;
+
+ public StoreFactoryCacheSession(StoreFactoryCacheManager cache, KeycloakSession session) {
+ this.cache = cache;
+ this.startupRevision = cache.getCurrentCounter();
+ this.session = session;
+ this.resourceServerCache = new ResourceServerCache();
+ this.scopeCache = new ScopeCache();
+ this.resourceCache = new ResourceCache();
+ this.policyCache = new PolicyCache();
+ session.getTransactionManager().enlistPrepare(getPrepareTransaction());
+ session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
+ }
+
+ @Override
+ public ResourceServerStore getResourceServerStore() {
+ return resourceServerCache;
+ }
+
+ @Override
+ public ScopeStore getScopeStore() {
+ return scopeCache;
+ }
+
+ @Override
+ public ResourceStore getResourceStore() {
+ return resourceCache;
+ }
+
+ @Override
+ public PolicyStore getPolicyStore() {
+ return policyCache;
+ }
+
+ public void close() {
+ }
+
+ private KeycloakTransaction getPrepareTransaction() {
+ return new KeycloakTransaction() {
+ @Override
+ public void begin() {
+ transactionActive = true;
+ }
+
+ @Override
+ public void commit() {
+ }
+
+ @Override
+ public void rollback() {
+ setRollbackOnly = true;
+ transactionActive = false;
+ }
+
+ @Override
+ public void setRollbackOnly() {
+ setRollbackOnly = true;
+ }
+
+ @Override
+ public boolean getRollbackOnly() {
+ return setRollbackOnly;
+ }
+
+ @Override
+ public boolean isActive() {
+ return transactionActive;
+ }
+ };
+ }
+
+ private KeycloakTransaction getAfterTransaction() {
+ return new KeycloakTransaction() {
+ @Override
+ public void begin() {
+ transactionActive = true;
+ }
+
+ @Override
+ public void commit() {
+ try {
+ if (getDelegate() == null) return;
+ if (clearAll) {
+ cache.clear();
+ }
+ runInvalidations();
+ transactionActive = false;
+ } finally {
+ cache.endRevisionBatch();
+ }
+ }
+
+ @Override
+ public void rollback() {
+ try {
+ setRollbackOnly = true;
+ runInvalidations();
+ transactionActive = false;
+ } finally {
+ cache.endRevisionBatch();
+ }
+ }
+
+ @Override
+ public void setRollbackOnly() {
+ setRollbackOnly = true;
+ }
+
+ @Override
+ public boolean getRollbackOnly() {
+ return setRollbackOnly;
+ }
+
+ @Override
+ public boolean isActive() {
+ return transactionActive;
+ }
+ };
+ }
+
+ protected void runInvalidations() {
+ for (String id : invalidations) {
+ cache.invalidateObject(id);
+ }
+
+ cache.sendInvalidationEvents(session, invalidationEvents);
+ }
+
+
+
+ public long getStartupRevision() {
+ return startupRevision;
+ }
+
+ public boolean isInvalid(String id) {
+ return invalidations.contains(id);
+ }
+
+ public void registerResourceServerInvalidation(String id, String clientId) {
+ cache.resourceServerUpdated(id, clientId, invalidations);
+ ResourceServerAdapter adapter = managedResourceServers.get(id);
+ if (adapter != null) adapter.invalidateFlag();
+
+ invalidationEvents.add(ResourceServerUpdatedEvent.create(id, clientId));
+ }
+
+ public void registerScopeInvalidation(String id, String name, String serverId) {
+ cache.scopeUpdated(id, name, serverId, invalidations);
+ ScopeAdapter adapter = managedScopes.get(id);
+ if (adapter != null) adapter.invalidateFlag();
+
+ invalidationEvents.add(ScopeUpdatedEvent.create(id, name, serverId));
+ }
+
+ public void registerResourceInvalidation(String id, String name, String serverId) {
+ cache.resourceUpdated(id, name, serverId, invalidations);
+ ResourceAdapter adapter = managedResources.get(id);
+ if (adapter != null) adapter.invalidateFlag();
+
+ invalidationEvents.add(ResourceUpdatedEvent.create(id, name, serverId));
+ }
+
+ public void registerPolicyInvalidation(String id, String name, String serverId) {
+ cache.policyUpdated(id, name, serverId, invalidations);
+ PolicyAdapter adapter = managedPolicies.get(id);
+ if (adapter != null) adapter.invalidateFlag();
+
+ invalidationEvents.add(PolicyUpdatedEvent.create(id, name, serverId));
+ }
+
+ public ResourceServerStore getResourceServerStoreDelegate() {
+ return getDelegate().getResourceServerStore();
+ }
+
+ public ScopeStore getScopeStoreDelegate() {
+ return getDelegate().getScopeStore();
+ }
+
+ public ResourceStore getResourceStoreDelegate() {
+ return getDelegate().getResourceStore();
+ }
+
+ public PolicyStore getPolicyStoreDelegate() {
+ return getDelegate().getPolicyStore();
+ }
+
+ public static String getResourceServerByClientCacheKey(String clientId) {
+ return "resource.server.client.id." + clientId;
+ }
+
+ public static String getScopeByNameCacheKey(String name, String serverId) {
+ return "scope.name." + name + "." + serverId;
+ }
+
+ public static String getResourceByNameCacheKey(String name, String serverId) {
+ return "resource.name." + name + "." + serverId;
+ }
+
+ public static String getPolicyByNameCacheKey(String name, String serverId) {
+ return "policy.name." + name + "." + serverId;
+ }
+
+ public StoreFactory getDelegate() {
+ if (delegate != null) return delegate;
+ delegate = session.getProvider(StoreFactory.class);
+ return delegate;
+ }
+
+
+ protected class ResourceServerCache implements ResourceServerStore {
+ @Override
+ public ResourceServer create(String clientId) {
+ ResourceServer server = getResourceServerStoreDelegate().create(clientId);
+ registerResourceServerInvalidation(server.getId(), server.getClientId());
+ return server;
+ }
+
+ @Override
+ public void delete(String id) {
+ if (id == null) return;
+ ResourceServer server = findById(id);
+ if (server == null) return;
+
+ cache.invalidateObject(id);
+ invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getClientId()));
+ cache.resourceServerRemoval(id, server.getClientId(), invalidations);
+ getResourceServerStoreDelegate().delete(id);
+
+ }
+
+ @Override
+ public ResourceServer findById(String id) {
+ if (id == null) return null;
+ CachedResourceServer cached = cache.get(id, CachedResourceServer.class);
+ if (cached != null) {
+ logger.tracev("by id cache hit: {0}", cached.getId());
+ }
+ boolean wasCached = false;
+ if (cached == null) {
+ Long loaded = cache.getCurrentRevision(id);
+ ResourceServer model = getResourceServerStoreDelegate().findById(id);
+ if (model == null) return null;
+ if (invalidations.contains(id)) return model;
+ cached = new CachedResourceServer(loaded, model);
+ cache.addRevisioned(cached, startupRevision);
+ wasCached =true;
+ } else if (invalidations.contains(id)) {
+ return getResourceServerStoreDelegate().findById(id);
+ } else if (managedResourceServers.containsKey(id)) {
+ return managedResourceServers.get(id);
+ }
+ ResourceServerAdapter adapter = new ResourceServerAdapter(cached, StoreFactoryCacheSession.this);
+ managedResourceServers.put(id, adapter);
+ return adapter;
+ }
+
+
+ @Override
+ public ResourceServer findByClient(String clientId) {
+ String cacheKey = getResourceServerByClientCacheKey(clientId);
+ ResourceServerListQuery query = cache.get(cacheKey, ResourceServerListQuery.class);
+ if (query != null) {
+ logger.tracev("ResourceServer by clientId cache hit: {0}", clientId);
+ }
+ if (query == null) {
+ Long loaded = cache.getCurrentRevision(cacheKey);
+ ResourceServer model = getResourceServerStoreDelegate().findByClient(clientId);
+ if (model == null) return null;
+ if (invalidations.contains(model.getId())) return model;
+ query = new ResourceServerListQuery(loaded, cacheKey, model.getId());
+ cache.addRevisioned(query, startupRevision);
+ return model;
+ } else if (invalidations.contains(cacheKey)) {
+ return getResourceServerStoreDelegate().findByClient(clientId);
+ } else {
+ String serverId = query.getResourceServers().iterator().next();
+ if (invalidations.contains(serverId)) {
+ return getResourceServerStoreDelegate().findByClient(clientId);
+ }
+ return findById(serverId);
+ }
+ }
+ }
+
+ protected class ScopeCache implements ScopeStore {
+ @Override
+ public Scope create(String name, ResourceServer resourceServer) {
+ Scope scope = getScopeStoreDelegate().create(name, resourceServer);
+ registerScopeInvalidation(scope.getId(), scope.getName(), resourceServer.getId());
+ return scope;
+ }
+
+ @Override
+ public void delete(String id) {
+ if (id == null) return;
+ Scope scope = findById(id, null);
+ if (scope == null) return;
+
+ cache.invalidateObject(id);
+ invalidationEvents.add(ScopeRemovedEvent.create(id, scope.getName(), scope.getResourceServer().getId()));
+ cache.scopeRemoval(id, scope.getName(), scope.getResourceServer().getId(), invalidations);
+ getScopeStoreDelegate().delete(id);
+ }
+
+ @Override
+ public Scope findById(String id, String resourceServerId) {
+ if (id == null) return null;
+ CachedScope cached = cache.get(id, CachedScope.class);
+ if (cached != null) {
+ logger.tracev("by id cache hit: {0}", cached.getId());
+ }
+ boolean wasCached = false;
+ if (cached == null) {
+ Long loaded = cache.getCurrentRevision(id);
+ Scope model = getScopeStoreDelegate().findById(id, resourceServerId);
+ if (model == null) return null;
+ if (invalidations.contains(id)) return model;
+ cached = new CachedScope(loaded, model);
+ cache.addRevisioned(cached, startupRevision);
+ wasCached =true;
+ } else if (invalidations.contains(id)) {
+ return getScopeStoreDelegate().findById(id, resourceServerId);
+ } else if (managedScopes.containsKey(id)) {
+ return managedScopes.get(id);
+ }
+ ScopeAdapter adapter = new ScopeAdapter(cached, StoreFactoryCacheSession.this);
+ managedScopes.put(id, adapter);
+ return adapter;
+ }
+
+ @Override
+ public Scope findByName(String name, String resourceServerId) {
+ if (name == null) return null;
+ String cacheKey = getScopeByNameCacheKey(name, resourceServerId);
+ ScopeListQuery query = cache.get(cacheKey, ScopeListQuery.class);
+ if (query != null) {
+ logger.tracev("scope by name cache hit: {0}", name);
+ }
+ if (query == null) {
+ Long loaded = cache.getCurrentRevision(cacheKey);
+ Scope model = getScopeStoreDelegate().findByName(name, resourceServerId);
+ if (model == null) return null;
+ if (invalidations.contains(model.getId())) return model;
+ query = new ScopeListQuery(loaded, cacheKey, model.getId(), resourceServerId);
+ cache.addRevisioned(query, startupRevision);
+ return model;
+ } else if (invalidations.contains(cacheKey)) {
+ return getScopeStoreDelegate().findByName(name, resourceServerId);
+ } else {
+ String id = query.getScopes().iterator().next();
+ if (invalidations.contains(id)) {
+ return getScopeStoreDelegate().findByName(name, resourceServerId);
+ }
+ return findById(id, query.getResourceServerId());
+ }
+ }
+
+ @Override
+ public List<Scope> findByResourceServer(String id) {
+ return getScopeStoreDelegate().findByResourceServer(id);
+ }
+
+ @Override
+ public List<Scope> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+ return getScopeStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
+ }
+ }
+
+ protected class ResourceCache implements ResourceStore {
+ @Override
+ public Resource create(String name, ResourceServer resourceServer, String owner) {
+ Resource resource = getResourceStoreDelegate().create(name, resourceServer, owner);
+ registerResourceInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
+ return resource;
+ }
+
+ @Override
+ public void delete(String id) {
+ if (id == null) return;
+ Resource resource = findById(id, null);
+ 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);
+ getResourceStoreDelegate().delete(id);
+
+ }
+
+ @Override
+ public Resource findById(String id, String resourceServerId) {
+ if (id == null) return null;
+ CachedResource cached = cache.get(id, CachedResource.class);
+ if (cached != null) {
+ logger.tracev("by id cache hit: {0}", cached.getId());
+ }
+ boolean wasCached = false;
+ if (cached == null) {
+ Long loaded = cache.getCurrentRevision(id);
+ Resource model = getResourceStoreDelegate().findById(id, resourceServerId);
+ if (model == null) return null;
+ if (invalidations.contains(id)) return model;
+ cached = new CachedResource(loaded, model);
+ cache.addRevisioned(cached, startupRevision);
+ wasCached =true;
+ } else if (invalidations.contains(id)) {
+ return getResourceStoreDelegate().findById(id, resourceServerId);
+ } else if (managedResources.containsKey(id)) {
+ return managedResources.get(id);
+ }
+ ResourceAdapter adapter = new ResourceAdapter(cached, StoreFactoryCacheSession.this);
+ managedResources.put(id, adapter);
+ return adapter;
+ }
+
+ @Override
+ 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);
+ }
+ return findById(id, query.getResourceServerId());
+ }
+ }
+
+ @Override
+ public List<Resource> findByOwner(String ownerId, String resourceServerId) {
+ return getResourceStoreDelegate().findByOwner(ownerId, resourceServerId);
+ }
+
+ @Override
+ public List<Resource> findByUri(String uri, String resourceServerId) {
+ return getResourceStoreDelegate().findByUri(uri, resourceServerId);
+ }
+
+ @Override
+ public List<Resource> findByResourceServer(String resourceServerId) {
+ return getResourceStoreDelegate().findByResourceServer(resourceServerId);
+ }
+
+ @Override
+ public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+ return getResourceStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
+ }
+
+ @Override
+ public List<Resource> findByScope(List<String> ids, String resourceServerId) {
+ return getResourceStoreDelegate().findByScope(ids, resourceServerId);
+ }
+
+ @Override
+ public List<Resource> findByType(String type, String resourceServerId) {
+ return getResourceStoreDelegate().findByType(type, resourceServerId);
+ }
+ }
+
+ 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;
+ }
+
+ @Override
+ public void delete(String id) {
+ if (id == null) return;
+ Policy policy = findById(id, null);
+ 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);
+ getPolicyStoreDelegate().delete(id);
+
+ }
+
+ @Override
+ public Policy findById(String id, String resourceServerId) {
+ if (id == null) return null;
+
+ CachedPolicy cached = cache.get(id, CachedPolicy.class);
+ if (cached != null) {
+ logger.tracev("by id cache hit: {0}", cached.getId());
+ }
+ boolean wasCached = false;
+ if (cached == null) {
+ Long loaded = cache.getCurrentRevision(id);
+ Policy model = getPolicyStoreDelegate().findById(id, resourceServerId);
+ if (model == null) return null;
+ if (invalidations.contains(id)) return model;
+ cached = new CachedPolicy(loaded, model);
+ cache.addRevisioned(cached, startupRevision);
+ wasCached =true;
+ } else if (invalidations.contains(id)) {
+ return getPolicyStoreDelegate().findById(id, resourceServerId);
+ } else if (managedPolicies.containsKey(id)) {
+ return managedPolicies.get(id);
+ }
+ PolicyAdapter adapter = new PolicyAdapter(cached, StoreFactoryCacheSession.this);
+ managedPolicies.put(id, adapter);
+ return adapter;
+ }
+
+ @Override
+ 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);
+ }
+ return findById(id, query.getResourceServerId());
+ }
+ }
+
+ @Override
+ public List<Policy> findByResourceServer(String resourceServerId) {
+ return getPolicyStoreDelegate().findByResourceServer(resourceServerId);
+ }
+
+ @Override
+ public List<Policy> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+ return getPolicyStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
+ }
+
+ @Override
+ public List<Policy> findByResource(String resourceId, String resourceServerId) {
+ return getPolicyStoreDelegate().findByResource(resourceId, resourceServerId);
+ }
+
+ @Override
+ public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
+ return getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId);
+ }
+
+ @Override
+ public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
+ return getPolicyStoreDelegate().findByScopeIds(scopeIds, resourceServerId);
+ }
+
+ @Override
+ public List<Policy> findByType(String type, String resourceServerId) {
+ return getPolicyStoreDelegate().findByType(type, resourceServerId);
+ }
+
+ @Override
+ public List<Policy> findDependentPolicies(String id, String resourceServerId) {
+ return getPolicyStoreDelegate().findDependentPolicies(id, resourceServerId);
+ }
+ }
+
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java
new file mode 100755
index 0000000..46782b8
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java
@@ -0,0 +1,35 @@
+package org.keycloak.models.cache.infinispan.authorization.stream;
+
+import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer;
+import org.keycloak.models.cache.infinispan.entities.InRealm;
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
+ private String serverId;
+
+ public static InResourceServerPredicate create() {
+ return new InResourceServerPredicate();
+ }
+
+ public InResourceServerPredicate resourceServer(String id) {
+ serverId = id;
+ return this;
+ }
+
+ @Override
+ public boolean test(Map.Entry<String, Revisioned> entry) {
+ Object value = entry.getValue();
+ if (value == null) return false;
+ if (!(value instanceof InResourceServer)) return false;
+
+ return serverId.equals(((InResourceServer)value).getResourceServerId());
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
index c254ea7..c9832ff 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
@@ -215,7 +215,7 @@ public abstract class CacheManager {
}
- protected void invalidationEventReceived(InvalidationEvent event) {
+ public void invalidationEventReceived(InvalidationEvent event) {
Set<String> invalidations = new HashSet<>();
addInvalidationsFromEvent(event, invalidations);
diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
index 0a46bb3..d9bed49 100644
--- a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
+++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
@@ -16,4 +16,4 @@
# limitations under the License.
#
-org.keycloak.models.authorization.infinispan.InfinispanStoreProviderFactory
\ No newline at end of file
+org.keycloak.models.cache.infinispan.authorization.InfinispanCacheStoreFactoryProviderFactory
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
index 0305ae5..dc11724 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
@@ -35,6 +35,8 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@@ -52,11 +54,25 @@ import org.keycloak.representations.idm.authorization.Logic;
@Table(name = "RESOURCE_SERVER_POLICY", uniqueConstraints = {
@UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
})
-public class PolicyEntity implements Policy {
+@NamedQueries(
+ {
+ @NamedQuery(name="findPolicyIdByServerId", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId "),
+ @NamedQuery(name="findPolicyIdByName", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.name = :name"),
+ @NamedQuery(name="findPolicyIdByResource", query="select p.id from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
+ @NamedQuery(name="findPolicyIdByScope", query="select pe.id from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))"),
+ @NamedQuery(name="findPolicyIdByType", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"),
+ @NamedQuery(name="findPolicyIdByResourceType", query="select p.id from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"),
+ @NamedQuery(name="findPolicyIdByDependentPolices", query="select p.id from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)"),
+ @NamedQuery(name="deletePolicyByResourceServer", query="delete from PolicyEntity p where p.resourceServer.id = :serverId")
+ }
+)
+
+public class PolicyEntity {
@Id
- @Column(name="ID", length = 36)
- @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
+ @Column(name = "ID", length = 36)
+ @Access(AccessType.PROPERTY)
+ // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
private String id;
@Column(name = "NAME")
@@ -75,9 +91,9 @@ public class PolicyEntity implements Policy {
private Logic logic = Logic.POSITIVE;
@ElementCollection(fetch = FetchType.LAZY)
- @MapKeyColumn(name="NAME")
- @Column(name="VALUE", columnDefinition = "TEXT")
- @CollectionTable(name="POLICY_CONFIG", joinColumns={ @JoinColumn(name="POLICY_ID") })
+ @MapKeyColumn(name = "NAME")
+ @Column(name = "VALUE", columnDefinition = "TEXT")
+ @CollectionTable(name = "POLICY_CONFIG", joinColumns = {@JoinColumn(name = "POLICY_ID")})
private Map<String, String> config = new HashMap();
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@@ -96,7 +112,6 @@ public class PolicyEntity implements Policy {
@JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
private Set<ScopeEntity> scopes = new HashSet<>();
- @Override
public String getId() {
return this.id;
}
@@ -105,7 +120,6 @@ public class PolicyEntity implements Policy {
this.id = id;
}
- @Override
public String getType() {
return this.type;
}
@@ -114,57 +128,46 @@ public class PolicyEntity implements Policy {
this.type = type;
}
- @Override
public DecisionStrategy getDecisionStrategy() {
return this.decisionStrategy;
}
- @Override
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
this.decisionStrategy = decisionStrategy;
}
- @Override
public Logic getLogic() {
return this.logic;
}
- @Override
public void setLogic(Logic logic) {
this.logic = logic;
}
- @Override
public Map<String, String> getConfig() {
return this.config;
}
- @Override
public void setConfig(Map<String, String> config) {
this.config = config;
}
- @Override
public String getName() {
return this.name;
}
- @Override
public void setName(String name) {
this.name = name;
}
- @Override
public String getDescription() {
return this.description;
}
- @Override
public void setDescription(String description) {
this.description = description;
}
- @Override
public ResourceServerEntity getResourceServer() {
return this.resourceServer;
}
@@ -173,16 +176,6 @@ public class PolicyEntity implements Policy {
this.resourceServer = resourceServer;
}
- @Override
- public <P extends Policy> Set<P> getAssociatedPolicies() {
- return (Set<P>) this.associatedPolicies;
- }
-
- public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
- this.associatedPolicies = associatedPolicies;
- }
-
- @Override
public Set<ResourceEntity> getResources() {
return this.resources;
}
@@ -191,7 +184,6 @@ public class PolicyEntity implements Policy {
this.resources = resources;
}
- @Override
public Set<ScopeEntity> getScopes() {
return this.scopes;
}
@@ -200,54 +192,26 @@ public class PolicyEntity implements Policy {
this.scopes = scopes;
}
- @Override
- public void addScope(Scope scope) {
- getScopes().add((ScopeEntity) scope);
- }
-
- @Override
- public void removeScope(Scope scope) {
- getScopes().remove(scope);
- }
-
- @Override
- public void addAssociatedPolicy(Policy associatedPolicy) {
- getAssociatedPolicies().add(associatedPolicy);
- }
-
- @Override
- public void removeAssociatedPolicy(Policy associatedPolicy) {
- getAssociatedPolicies().remove(associatedPolicy);
+ public Set<PolicyEntity> getAssociatedPolicies() {
+ return associatedPolicies;
}
- @Override
- public void addResource(Resource resource) {
- getResources().add((ResourceEntity) resource);
- }
-
- @Override
- public void removeResource(Resource resource) {
- getResources().remove(resource);
+ public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
+ this.associatedPolicies = associatedPolicies;
}
@Override
public boolean equals(Object o) {
- if (o == this) return true;
-
- if (this.id == null) return false;
-
- if (!Policy.class.isInstance(o)) return false;
-
- Policy that = (Policy) o;
-
- if (!getId().equals(that.getId())) return false;
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
- return true;
+ PolicyEntity that = (PolicyEntity) o;
+ return getId().equals(that.getId());
}
@Override
public int hashCode() {
- return id!=null ? id.hashCode() : super.hashCode();
+ return getId().hashCode();
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
index 29b5740..a717457 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
@@ -31,10 +31,13 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -45,7 +48,18 @@ import java.util.Set;
@Table(name = "RESOURCE_SERVER_RESOURCE", uniqueConstraints = {
@UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID", "OWNER"})
})
-public class ResourceEntity implements Resource {
+@NamedQueries(
+ {
+ @NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
+ @NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.uri = :uri"),
+ @NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.name = :name"),
+ @NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.type = :type"),
+ @NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId "),
+ @NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
+ @NamedQuery(name="deleteResourceByResourceServer", query="delete from ResourceEntity r where r.resourceServer.id = :serverId")
+ }
+)
+public class ResourceEntity {
@Id
@Column(name="ID", length = 36)
@@ -73,13 +87,12 @@ public class ResourceEntity implements Resource {
@ManyToMany(fetch = FetchType.LAZY, cascade = {})
@JoinTable(name = "RESOURCE_SCOPE", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
- private List<ScopeEntity> scopes = new ArrayList<>();
+ private List<ScopeEntity> scopes = new LinkedList<>();
@ManyToMany(fetch = FetchType.LAZY, cascade = {})
@JoinTable(name = "RESOURCE_POLICY", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
- private List<PolicyEntity> policies = new ArrayList<>();
+ private List<PolicyEntity> policies = new LinkedList<>();
- @Override
public String getId() {
return id;
}
@@ -88,52 +101,42 @@ public class ResourceEntity implements Resource {
this.id = id;
}
- @Override
public String getName() {
return name;
}
- @Override
public void setName(String name) {
this.name = name;
}
- @Override
public String getUri() {
return uri;
}
- @Override
public void setUri(String uri) {
this.uri = uri;
}
- @Override
public String getType() {
return type;
}
- @Override
public void setType(String type) {
this.type = type;
}
- @Override
public List<ScopeEntity> getScopes() {
return this.scopes;
}
- @Override
public String getIconUri() {
return iconUri;
}
- @Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
- @Override
public ResourceServerEntity getResourceServer() {
return resourceServer;
}
@@ -154,37 +157,23 @@ public class ResourceEntity implements Resource {
return this.policies;
}
- public void updateScopes(Set<Scope> toUpdate) {
- for (Scope scope : toUpdate) {
- boolean hasScope = false;
-
- for (Scope existingScope : this.scopes) {
- if (existingScope.equals(scope)) {
- hasScope = true;
- }
- }
- if (!hasScope) {
- this.scopes.add((ScopeEntity) scope);
- }
- }
+ public void setPolicies(List<PolicyEntity> policies) {
+ this.policies = policies;
+ }
- for (Scope scopeModel : new HashSet<Scope>(this.scopes)) {
- boolean hasScope = false;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
- for (Scope scope : toUpdate) {
- if (scopeModel.equals(scope)) {
- hasScope = true;
- }
- }
+ ResourceEntity that = (ResourceEntity) o;
- if (!hasScope) {
- this.scopes.remove(scopeModel);
- }
- }
+ return getId().equals(that.getId());
}
- public void setPolicies(List<PolicyEntity> policies) {
- this.policies = policies;
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
index a0be18a..9ee63b6 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
@@ -26,6 +26,8 @@ import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@@ -36,7 +38,12 @@ import java.util.List;
*/
@Entity
@Table(name = "RESOURCE_SERVER", uniqueConstraints = {@UniqueConstraint(columnNames = "CLIENT_ID")})
-public class ResourceServerEntity implements ResourceServer {
+@NamedQueries(
+ {
+ @NamedQuery(name="findResourceServerIdByClient", query="select r.id from ResourceServerEntity r where r.clientId = :clientId"),
+ }
+)
+public class ResourceServerEntity {
@Id
@Column(name="ID", length = 36)
@@ -58,7 +65,6 @@ public class ResourceServerEntity implements ResourceServer {
@OneToMany (mappedBy = "resourceServer")
private List<ScopeEntity> scopes;
- @Override
public String getId() {
return this.id;
}
@@ -67,7 +73,6 @@ public class ResourceServerEntity implements ResourceServer {
this.id = id;
}
- @Override
public String getClientId() {
return this.clientId;
}
@@ -76,22 +81,18 @@ public class ResourceServerEntity implements ResourceServer {
this.clientId = clientId;
}
- @Override
public boolean isAllowRemoteResourceManagement() {
return this.allowRemoteResourceManagement;
}
- @Override
public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
this.allowRemoteResourceManagement = allowRemoteResourceManagement;
}
- @Override
public PolicyEnforcementMode getPolicyEnforcementMode() {
return this.policyEnforcementMode;
}
- @Override
public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
this.policyEnforcementMode = policyEnforcementMode;
}
@@ -111,4 +112,19 @@ public class ResourceServerEntity implements ResourceServer {
public void setScopes(final List<ScopeEntity> scopes) {
this.scopes = scopes;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ResourceServerEntity that = (ResourceServerEntity) o;
+
+ return getId().equals(that.getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
index 523f38a..c1619f9 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
@@ -31,6 +31,8 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
@@ -44,7 +46,14 @@ import java.util.Objects;
@Table(name = "RESOURCE_SERVER_SCOPE", uniqueConstraints = {
@UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
})
-public class ScopeEntity implements Scope {
+@NamedQueries(
+ {
+ @NamedQuery(name="findScopeIdByName", query="select s.id from ScopeEntity s where s.resourceServer.id = :serverId and s.name = :name"),
+ @NamedQuery(name="findScopeIdByResourceServer", query="select s.id from ScopeEntity s where s.resourceServer.id = :serverId"),
+ @NamedQuery(name="deleteScopeByResourceServer", query="delete from ScopeEntity s where s.resourceServer.id = :serverId")
+ }
+)
+public class ScopeEntity {
@Id
@Column(name="ID", length = 36)
@@ -65,7 +74,6 @@ public class ScopeEntity implements Scope {
@JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "SCOPE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
private List<PolicyEntity> policies = new ArrayList<>();
- @Override
public String getId() {
return id;
}
@@ -74,33 +82,28 @@ public class ScopeEntity implements Scope {
this.id = id;
}
- @Override
public String getName() {
return name;
}
- @Override
public void setName(String name) {
this.name = name;
}
- @Override
public String getIconUri() {
return iconUri;
}
- @Override
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
- @Override
public ResourceServerEntity getResourceServer() {
return resourceServer;
}
- public List<? extends Policy> getPolicies() {
- return this.policies;
+ public List<PolicyEntity> getPolicies() {
+ return policies;
}
public void setPolicies(List<PolicyEntity> policies) {
@@ -114,13 +117,15 @@ public class ScopeEntity implements Scope {
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || !Scope.class.isInstance(o)) return false;
- Scope that = (Scope) o;
- return Objects.equals(id, that.getId());
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ScopeEntity that = (ScopeEntity) o;
+
+ return getId().equals(that.getId());
}
@Override
public int hashCode() {
- return Objects.hash(id);
+ return getId().hashCode();
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
index 8750807..9f17606 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
@@ -32,8 +32,9 @@ import org.keycloak.models.KeycloakSession;
*/
public class JPAAuthorizationStoreFactory implements AuthorizationStoreFactory {
@Override
- public StoreFactory create(KeycloakSession session) {
- return new JPAStoreFactory(getEntityManager(session));
+ public StoreFactory create(KeycloakSession session) {
+ AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
+ return new JPAStoreFactory(getEntityManager(session), provider);
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
index c6671de..eb350be 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
@@ -19,23 +19,29 @@ package org.keycloak.authorization.jpa.store;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
+import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.PolicyEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
/**
@@ -44,9 +50,10 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
public class JPAPolicyStore implements PolicyStore {
private final EntityManager entityManager;
-
- public JPAPolicyStore(EntityManager entityManager) {
+ private final AuthorizationProvider provider;
+ public JPAPolicyStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
+ this.provider = provider;
}
@Override
@@ -56,17 +63,17 @@ public class JPAPolicyStore implements PolicyStore {
entity.setId(KeycloakModelUtils.generateId());
entity.setType(representation.getType());
entity.setName(representation.getName());
- entity.setResourceServer((ResourceServerEntity) resourceServer);
+ entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
this.entityManager.persist(entity);
this.entityManager.flush();
- return entity;
+ Policy model = new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
+ return model;
}
@Override
public void delete(String id) {
- Policy policy = entityManager.find(PolicyEntity.class, id);
-
+ PolicyEntity policy = entityManager.find(PolicyEntity.class, id);
if (policy != null) {
this.entityManager.remove(policy);
}
@@ -79,39 +86,38 @@ public class JPAPolicyStore implements PolicyStore {
return null;
}
- if (resourceServerId == null) {
- return entityManager.find(PolicyEntity.class, id);
- }
-
- Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId and id = :id");
-
- query.setParameter("serverId", resourceServerId);
- query.setParameter("id", id);
+ PolicyEntity entity = entityManager.find(PolicyEntity.class, id);
+ if (entity == null) return null;
- return entityManager.find(PolicyEntity.class, id);
+ return new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public Policy findByName(String name, String resourceServerId) {
- try {
- Query query = entityManager.createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId");
-
- query.setParameter("name", name);
- query.setParameter("serverId", resourceServerId);
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByName", String.class);
- return (Policy) query.getSingleResult();
- } catch (NoResultException nre) {
+ query.setParameter("serverId", resourceServerId);
+ query.setParameter("name", name);
+ try {
+ String id = query.getSingleResult();
+ return provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId);
+ } catch (NoResultException ex) {
return null;
}
}
@Override
public List<Policy> findByResourceServer(final String resourceServerId) {
- Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId");
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
@@ -120,6 +126,7 @@ public class JPAPolicyStore implements PolicyStore {
CriteriaQuery<PolicyEntity> querybuilder = builder.createQuery(PolicyEntity.class);
Root<PolicyEntity> root = querybuilder.from(PolicyEntity.class);
List<Predicate> predicates = new ArrayList();
+ querybuilder.select(root.get("id"));
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@@ -148,27 +155,42 @@ public class JPAPolicyStore implements PolicyStore {
query.setMaxResults(maxResult);
}
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
public List<Policy> findByResource(final String resourceId, String resourceServerId) {
- Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)");
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByResource", String.class);
query.setParameter("resourceId", resourceId);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
public List<Policy> findByResourceType(final String resourceType, String resourceServerId) {
- Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type");
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByResourceType", String.class);
- query.setParameter("serverId", resourceServerId);
query.setParameter("type", resourceType);
+ query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
@@ -178,31 +200,47 @@ public class JPAPolicyStore implements PolicyStore {
}
// Use separate subquery to handle DB2 and MSSSQL
- Query query = entityManager.createQuery("select pe from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))");
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByScope", String.class);
- query.setParameter("serverId", resourceServerId);
query.setParameter("scopeIds", scopeIds);
+ query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
public List<Policy> findByType(String type, String resourceServerId) {
- Query query = entityManager.createQuery("select p from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type");
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByType", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("type", type);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
public List<Policy> findDependentPolicies(String policyId, String resourceServerId) {
- Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)");
+
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByDependentPolices", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("policyId", policyId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+ }
+ return list;
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
index 51d0369..20404e5 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
@@ -17,13 +17,19 @@
*/
package org.keycloak.authorization.jpa.store;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.PolicyEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -32,9 +38,11 @@ import java.util.List;
public class JPAResourceServerStore implements ResourceServerStore {
private final EntityManager entityManager;
+ private final AuthorizationProvider provider;
- public JPAResourceServerStore(EntityManager entityManager) {
+ public JPAResourceServerStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
+ this.provider = provider;
}
@Override
@@ -46,30 +54,54 @@ public class JPAResourceServerStore implements ResourceServerStore {
this.entityManager.persist(entity);
- return entity;
+ return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public void delete(String id) {
- this.entityManager.remove(findById(id));
+ ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
+ if (entity == null) return;
+ //This didn't work, had to loop through and remove each policy individually
+ //entityManager.createNamedQuery("deletePolicyByResourceServer")
+ // .setParameter("serverId", id).executeUpdate();
+
+ TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
+ query.setParameter("serverId", id);
+ List<String> result = query.getResultList();
+ List<Policy> list = new LinkedList<>();
+ for (String policyId : result) {
+ entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
+ }
+
+ entityManager.flush();
+ entityManager.createNamedQuery("deleteResourceByResourceServer")
+ .setParameter("serverId", id).executeUpdate();
+ entityManager.flush();
+ entityManager.createNamedQuery("deleteScopeByResourceServer")
+ .setParameter("serverId", id).executeUpdate();
+ entityManager.flush();
+
+ this.entityManager.remove(entity);
+ entityManager.flush();
}
@Override
public ResourceServer findById(String id) {
- return entityManager.find(ResourceServerEntity.class, id);
+ ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
+ if (entity == null) return null;
+ return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public ResourceServer findByClient(final String clientId) {
- Query query = entityManager.createQuery("from ResourceServerEntity where clientId = :clientId");
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceServerIdByClient", String.class);
query.setParameter("clientId", clientId);
- List result = query.getResultList();
-
- if (result.isEmpty()) {
+ try {
+ String id = query.getSingleResult();
+ return provider.getStoreFactory().getResourceServerStore().findById(id);
+ } catch (NoResultException ex) {
return null;
}
-
- return (ResourceServer) result.get(0);
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
index 0b04388..8a647d8 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
@@ -17,6 +17,7 @@
*/
package org.keycloak.authorization.jpa.store;
+import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceEntity;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.model.Resource;
@@ -25,13 +26,16 @@ import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -41,38 +45,34 @@ import java.util.Map;
public class JPAResourceStore implements ResourceStore {
private final EntityManager entityManager;
+ private final AuthorizationProvider provider;
- public JPAResourceStore(EntityManager entityManager) {
+ public JPAResourceStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
+ this.provider = provider;
}
@Override
public Resource create(String name, ResourceServer resourceServer, String owner) {
- if (!(resourceServer instanceof ResourceServerEntity)) {
- throw new RuntimeException("Unexpected type [" + resourceServer.getClass() + "].");
- }
-
ResourceEntity entity = new ResourceEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setName(name);
- entity.setResourceServer((ResourceServerEntity) resourceServer);
+ entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
entity.setOwner(owner);
this.entityManager.persist(entity);
- return entity;
+ return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public void delete(String id) {
- Resource resource = entityManager.find(ResourceEntity.class, id);
+ ResourceEntity resource = entityManager.find(ResourceEntity.class, id);
+ if (resource == null) return;
resource.getScopes().clear();
-
- if (resource != null) {
- this.entityManager.remove(resource);
- }
+ this.entityManager.remove(resource);
}
@Override
@@ -81,52 +81,61 @@ public class JPAResourceStore implements ResourceStore {
return null;
}
- if (resourceServerId == null) {
- return entityManager.find(ResourceEntity.class, id);
- }
-
- Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and id = :id");
-
- query.setParameter("serverId", resourceServerId);
- query.setParameter("id", id);
-
- return entityManager.find(ResourceEntity.class, id);
+ ResourceEntity entity = entityManager.find(ResourceEntity.class, id);
+ if (entity == null) return null;
+ return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public List<Resource> findByOwner(String ownerId, String resourceServerId) {
- Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and owner = :ownerId");
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByOwner", String.class);
- query.setParameter("ownerId", ownerId);
+ query.setParameter("owner", ownerId);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Resource> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
public List<Resource> findByUri(String uri, String resourceServerId) {
- Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and uri = :uri");
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByUri", String.class);
query.setParameter("uri", uri);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Resource> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
- public List findByResourceServer(String resourceServerId) {
- Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId");
+ public List<Resource> findByResourceServer(String resourceServerId) {
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByServerId", String.class);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Resource> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
- public List findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+ public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<ResourceEntity> querybuilder = builder.createQuery(ResourceEntity.class);
Root<ResourceEntity> root = querybuilder.from(ResourceEntity.class);
+ querybuilder.select(root.get("id"));
List<Predicate> predicates = new ArrayList();
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@@ -152,42 +161,55 @@ public class JPAResourceStore implements ResourceStore {
query.setMaxResults(maxResult);
}
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Resource> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
- public List<Resource> findByScope(List<String> id, String resourceServerId) {
- Query query = entityManager.createQuery("select r from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))");
+ public List<Resource> findByScope(List<String> scopes, String resourceServerId) {
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByScope", String.class);
- query.setParameter("scopeIds", id);
+ query.setParameter("scopeIds", scopes);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Resource> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+ }
+ return list;
}
@Override
public Resource findByName(String name, String resourceServerId) {
- Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and name = :name");
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
query.setParameter("serverId", resourceServerId);
query.setParameter("name", name);
-
- List<Resource> result = query.getResultList();
-
- if (!result.isEmpty()) {
- return result.get(0);
+ try {
+ String id = query.getSingleResult();
+ return provider.getStoreFactory().getResourceStore().findById(id, resourceServerId);
+ } catch (NoResultException ex) {
+ return null;
}
-
- return null;
}
@Override
public List<Resource> findByType(String type, String resourceServerId) {
- Query query = entityManager.createQuery("from ResourceEntity r where r.resourceServer.id = :serverId and type = :type");
+ TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByType", String.class);
query.setParameter("type", type);
query.setParameter("serverId", resourceServerId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Resource> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+ }
+ return list;
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
index 031eb4a..f8a9350 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
@@ -18,17 +18,20 @@
package org.keycloak.authorization.jpa.store;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
+import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
import org.keycloak.authorization.jpa.entities.ScopeEntity;
import org.keycloak.authorization.model.ResourceServer;
@@ -42,9 +45,11 @@ import org.keycloak.models.utils.KeycloakModelUtils;
public class JPAScopeStore implements ScopeStore {
private final EntityManager entityManager;
+ private final AuthorizationProvider provider;
- public JPAScopeStore(EntityManager entityManager) {
+ public JPAScopeStore(EntityManager entityManager, AuthorizationProvider provider) {
this.entityManager = entityManager;
+ this.provider = provider;
}
@Override
@@ -53,16 +58,16 @@ public class JPAScopeStore implements ScopeStore {
entity.setId(KeycloakModelUtils.generateId());
entity.setName(name);
- entity.setResourceServer((ResourceServerEntity) resourceServer);
+ entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
this.entityManager.persist(entity);
- return entity;
+ return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public void delete(String id) {
- Scope scope = entityManager.find(ScopeEntity.class, id);
+ ScopeEntity scope = entityManager.find(ScopeEntity.class, id);
if (scope != null) {
this.entityManager.remove(scope);
@@ -75,28 +80,21 @@ public class JPAScopeStore implements ScopeStore {
return null;
}
- if (resourceServerId == null) {
- return entityManager.find(ScopeEntity.class, id);
- }
-
- Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId and id = :id");
-
- query.setParameter("serverId", resourceServerId);
- query.setParameter("id", id);
-
- return entityManager.find(ScopeEntity.class, id);
+ ScopeEntity entity = entityManager.find(ScopeEntity.class, id);
+ if (entity == null) return null;
+ return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
}
@Override
public Scope findByName(String name, String resourceServerId) {
try {
- Query query = entityManager.createQuery("select s from ScopeEntity s inner join s.resourceServer rs where rs.id = :resourceServerId and name = :name");
+ TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByName", String.class);
- query.setParameter("resourceServerId", resourceServerId);
+ query.setParameter("serverId", resourceServerId);
query.setParameter("name", name);
-
- return (Scope) query.getSingleResult();
+ String id = query.getSingleResult();
+ return provider.getStoreFactory().getScopeStore().findById(id, resourceServerId);
} catch (NoResultException nre) {
return null;
}
@@ -104,11 +102,16 @@ public class JPAScopeStore implements ScopeStore {
@Override
public List<Scope> findByResourceServer(final String serverId) {
- Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId");
+ TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByResourceServer", String.class);
query.setParameter("serverId", serverId);
- return query.getResultList();
+ List<String> result = query.getResultList();
+ List<Scope> list = new LinkedList<>();
+ for (String id : result) {
+ list.add(provider.getStoreFactory().getScopeStore().findById(id, serverId));
+ }
+ return list;
}
@Override
@@ -116,6 +119,7 @@ public class JPAScopeStore implements ScopeStore {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<ScopeEntity> querybuilder = builder.createQuery(ScopeEntity.class);
Root<ScopeEntity> root = querybuilder.from(ScopeEntity.class);
+ querybuilder.select(root.get("id"));
List<Predicate> predicates = new ArrayList();
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@@ -139,6 +143,12 @@ public class JPAScopeStore implements ScopeStore {
query.setMaxResults(maxResult);
}
- return query.getResultList();
+ List result = query.getResultList();
+ List<Scope> list = new LinkedList<>();
+ for (Object id : result) {
+ list.add(provider.getStoreFactory().getScopeStore().findById((String)id, resourceServerId));
+ }
+ return list;
+
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
index e45d343..855f66a 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
@@ -20,6 +20,7 @@ package org.keycloak.authorization.jpa.store;
import javax.persistence.EntityManager;
+import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
@@ -36,11 +37,11 @@ public class JPAStoreFactory implements StoreFactory {
private final ResourceStore resourceStore;
private final ScopeStore scopeStore;
- public JPAStoreFactory(EntityManager entityManager) {
- policyStore = new JPAPolicyStore(entityManager);
- resourceServerStore = new JPAResourceServerStore(entityManager);
- resourceStore = new JPAResourceStore(entityManager);
- scopeStore = new JPAScopeStore(entityManager);
+ public JPAStoreFactory(EntityManager entityManager, AuthorizationProvider provider) {
+ policyStore = new JPAPolicyStore(entityManager, provider);
+ resourceServerStore = new JPAResourceServerStore(entityManager, provider);
+ resourceStore = new JPAResourceStore(entityManager, provider);
+ scopeStore = new JPAScopeStore(entityManager, provider);
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
new file mode 100644
index 0000000..6fc2d1e
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
@@ -0,0 +1,235 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.PolicyEntity;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.jpa.JpaModel;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import javax.persistence.EntityManager;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PolicyAdapter implements Policy, JpaModel<PolicyEntity> {
+ private PolicyEntity entity;
+ private EntityManager em;
+ private StoreFactory storeFactory;
+
+ public PolicyAdapter(PolicyEntity entity, EntityManager em, StoreFactory storeFactory) {
+ this.entity = entity;
+ this.em = em;
+ this.storeFactory = storeFactory;
+ }
+
+ @Override
+ public PolicyEntity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public String getId() {
+ return entity.getId();
+ }
+
+ @Override
+ public String getType() {
+ return entity.getType();
+ }
+
+ @Override
+ public DecisionStrategy getDecisionStrategy() {
+ return entity.getDecisionStrategy();
+ }
+
+ @Override
+ public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+ entity.setDecisionStrategy(decisionStrategy);
+
+ }
+
+ @Override
+ public Logic getLogic() {
+ return entity.getLogic();
+ }
+
+ @Override
+ public void setLogic(Logic logic) {
+ entity.setLogic(logic);
+ }
+
+ @Override
+ public Map<String, String> getConfig() {
+ Map<String, String> result = new HashMap<String, String>();
+ if (entity.getConfig() != null) result.putAll(entity.getConfig());
+ return Collections.unmodifiableMap(result);
+ }
+
+ @Override
+ public void setConfig(Map<String, String> config) {
+ if (entity.getConfig() == null) {
+ entity.setConfig(new HashMap<>());
+ } else {
+ entity.getConfig().clear();
+ }
+ entity.getConfig().putAll(config);
+ }
+
+ @Override
+ public void removeConfig(String name) {
+ if (entity.getConfig() == null) {
+ return;
+ }
+ entity.getConfig().remove(name);
+ }
+
+ @Override
+ public void putConfig(String name, String value) {
+ if (entity.getConfig() == null) {
+ entity.setConfig(new HashMap<>());
+ }
+ entity.getConfig().put(name, value);
+
+ }
+
+ @Override
+ public String getName() {
+ return entity.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ entity.setName(name);
+
+ }
+
+ @Override
+ public String getDescription() {
+ return entity.getDescription();
+ }
+
+ @Override
+ public void setDescription(String description) {
+ entity.setDescription(description);
+
+ }
+
+ @Override
+ public ResourceServer getResourceServer() {
+ return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
+ }
+
+ @Override
+ public Set<Policy> getAssociatedPolicies() {
+ Set<Policy> result = new HashSet<>();
+ for (PolicyEntity policy : entity.getAssociatedPolicies()) {
+ Policy p = storeFactory.getPolicyStore().findById(policy.getId(), entity.getResourceServer().getId());
+ result.add(p);
+ }
+ return Collections.unmodifiableSet(result);
+ }
+
+ @Override
+ public Set<Resource> getResources() {
+ Set<Resource> set = new HashSet<>();
+ for (ResourceEntity res : entity.getResources()) {
+ set.add(storeFactory.getResourceStore().findById(res.getId(), entity.getResourceServer().getId()));
+ }
+ return Collections.unmodifiableSet(set);
+ }
+
+ @Override
+ public Set<Scope> getScopes() {
+ Set<Scope> set = new HashSet<>();
+ for (ScopeEntity res : entity.getScopes()) {
+ set.add(storeFactory.getScopeStore().findById(res.getId(), entity.getResourceServer().getId()));
+ }
+ return Collections.unmodifiableSet(set);
+ }
+
+ @Override
+ public void addScope(Scope scope) {
+ entity.getScopes().add(ScopeAdapter.toEntity(em, scope));
+ }
+
+ @Override
+ public void removeScope(Scope scope) {
+ entity.getScopes().remove(ScopeAdapter.toEntity(em, scope));
+
+ }
+
+ @Override
+ public void addAssociatedPolicy(Policy associatedPolicy) {
+ entity.getAssociatedPolicies().add(toEntity(em, associatedPolicy));
+ }
+
+ @Override
+ public void removeAssociatedPolicy(Policy associatedPolicy) {
+ entity.getAssociatedPolicies().remove(toEntity(em, associatedPolicy));
+
+ }
+
+ @Override
+ public void addResource(Resource resource) {
+ entity.getResources().add(ResourceAdapter.toEntity(em, resource));
+ }
+
+ @Override
+ public void removeResource(Resource resource) {
+ entity.getResources().remove(ResourceAdapter.toEntity(em, resource));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof Policy)) return false;
+
+ Policy that = (Policy) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+ public static PolicyEntity toEntity(EntityManager em, Policy policy) {
+ if (policy instanceof PolicyAdapter) {
+ return ((PolicyAdapter)policy).getEntity();
+ } else {
+ return em.getReference(PolicyEntity.class, policy.getId());
+ }
+ }
+
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceAdapter.java
new file mode 100644
index 0000000..5c55114
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceAdapter.java
@@ -0,0 +1,166 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.jpa.JpaModel;
+
+import javax.persistence.EntityManager;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceAdapter implements Resource, JpaModel<ResourceEntity> {
+ private ResourceEntity entity;
+ private EntityManager em;
+ private StoreFactory storeFactory;
+
+ public ResourceAdapter(ResourceEntity entity, EntityManager em, StoreFactory storeFactory) {
+ this.entity = entity;
+ this.em = em;
+ this.storeFactory = storeFactory;
+ }
+
+ @Override
+ public ResourceEntity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public String getId() {
+ return entity.getId();
+ }
+
+ @Override
+ public String getName() {
+ return entity.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ entity.setName(name);
+
+ }
+
+ @Override
+ public String getUri() {
+ return entity.getUri();
+ }
+
+ @Override
+ public void setUri(String uri) {
+ entity.setUri(uri);
+
+ }
+
+ @Override
+ public String getType() {
+ return entity.getType();
+ }
+
+ @Override
+ public void setType(String type) {
+ entity.setType(type);
+
+ }
+
+ @Override
+ public List<Scope> getScopes() {
+ List<Scope> scopes = new LinkedList<>();
+ for (ScopeEntity scope : entity.getScopes()) {
+ scopes.add(storeFactory.getScopeStore().findById(scope.getId(), entity.getResourceServer().getId()));
+ }
+
+ return Collections.unmodifiableList(scopes);
+ }
+
+ @Override
+ public String getIconUri() {
+ return entity.getIconUri();
+ }
+
+ @Override
+ public void setIconUri(String iconUri) {
+ entity.setIconUri(iconUri);
+
+ }
+
+ @Override
+ public ResourceServer getResourceServer() {
+ return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
+ }
+
+ @Override
+ public String getOwner() {
+ return entity.getOwner();
+ }
+
+ @Override
+ public void updateScopes(Set<Scope> toUpdate) {
+ Set<String> ids = new HashSet<>();
+ for (Scope scope : toUpdate) {
+ ids.add(scope.getId());
+ }
+ Iterator<ScopeEntity> it = entity.getScopes().iterator();
+ while (it.hasNext()) {
+ ScopeEntity next = it.next();
+ if (!ids.contains(next.getId())) it.remove();
+ else ids.remove(next.getId());
+ }
+ for (String addId : ids) {
+ entity.getScopes().add(em.getReference(ScopeEntity.class, addId));
+ }
+ }
+
+
+ public static ResourceEntity toEntity(EntityManager em, Resource resource) {
+ if (resource instanceof ResourceAdapter) {
+ return ((ResourceAdapter)resource).getEntity();
+ } else {
+ return em.getReference(ResourceEntity.class, resource.getId());
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof Resource)) return false;
+
+ Resource that = (Resource) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java
new file mode 100644
index 0000000..56d5856
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java
@@ -0,0 +1,106 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.jpa.JpaModel;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceServerAdapter implements ResourceServer, JpaModel<ResourceServerEntity> {
+ private ResourceServerEntity entity;
+ private EntityManager em;
+ private StoreFactory storeFactory;
+
+ public ResourceServerAdapter(ResourceServerEntity entity, EntityManager em, StoreFactory storeFactory) {
+ this.entity = entity;
+ this.em = em;
+ this.storeFactory = storeFactory;
+ }
+
+ @Override
+ public ResourceServerEntity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public String getId() {
+ return entity.getId();
+ }
+
+ @Override
+ public String getClientId() {
+ return entity.getClientId();
+ }
+
+ @Override
+ public boolean isAllowRemoteResourceManagement() {
+ return entity.isAllowRemoteResourceManagement();
+ }
+
+ @Override
+ public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+ entity.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+
+ }
+
+ @Override
+ public PolicyEnforcementMode getPolicyEnforcementMode() {
+ return entity.getPolicyEnforcementMode();
+ }
+
+ @Override
+ public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+ entity.setPolicyEnforcementMode(enforcementMode);
+
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof ResourceServer)) return false;
+
+ ResourceServer that = (ResourceServer) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+ public static ResourceServerEntity toEntity(EntityManager em, ResourceServer resource) {
+ if (resource instanceof ResourceAdapter) {
+ return ((ResourceServerAdapter)resource).getEntity();
+ } else {
+ return em.getReference(ResourceServerEntity.class, resource.getId());
+ }
+ }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ScopeAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ScopeAdapter.java
new file mode 100644
index 0000000..6b59dc8
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ScopeAdapter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.jpa.JpaModel;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeAdapter implements Scope, JpaModel<ScopeEntity> {
+ private ScopeEntity entity;
+ private EntityManager em;
+ private StoreFactory storeFactory;
+
+ public ScopeAdapter(ScopeEntity entity, EntityManager em, StoreFactory storeFactory) {
+ this.entity = entity;
+ this.em = em;
+ this.storeFactory = storeFactory;
+ }
+
+ @Override
+ public ScopeEntity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public String getId() {
+ return entity.getId();
+ }
+
+ @Override
+ public String getName() {
+ return entity.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ entity.setName(name);
+
+ }
+
+ @Override
+ public String getIconUri() {
+ return entity.getIconUri();
+ }
+
+ @Override
+ public void setIconUri(String iconUri) {
+ entity.setIconUri(iconUri);
+
+ }
+
+ @Override
+ public ResourceServer getResourceServer() {
+ return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
+ }
+
+ public static ScopeEntity toEntity(EntityManager em, Scope scope) {
+ if (scope instanceof ScopeAdapter) {
+ return ((ScopeAdapter)scope).getEntity();
+ } else {
+ return em.getReference(ScopeEntity.class, scope.getId());
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof Scope)) return false;
+
+ Scope that = (Scope) o;
+ return that.getId().equals(getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
index c5b75d3..8a55ff1 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -28,6 +28,7 @@ import org.keycloak.authorization.permission.evaluator.Evaluators;
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.AuthorizationStoreFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
import org.keycloak.authorization.store.ResourceStore;
@@ -35,13 +36,15 @@ import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.provider.Provider;
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
/**
* <p>The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances. Usually
- * an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.core.permission.evaluator.PermissionEvaluator}
+ * an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator}
* from the {@link #evaluators()} method.
*
* <p>The internal state of a {@link AuthorizationProvider} is immutable. This internal state includes all of the metadata
@@ -69,14 +72,14 @@ public final class AuthorizationProvider implements Provider {
private final DefaultPolicyEvaluator policyEvaluator;
private StoreFactory storeFactory;
+ private StoreFactory storeFactoryDelegate;
private final Map<String, PolicyProviderFactory> policyProviderFactories;
private final KeycloakSession keycloakSession;
private final RealmModel realm;
- public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Map<String, PolicyProviderFactory> policyProviderFactories) {
+ public AuthorizationProvider(KeycloakSession session, RealmModel realm, Map<String, PolicyProviderFactory> policyProviderFactories) {
this.keycloakSession = session;
this.realm = realm;
- this.storeFactory = storeFactory;
this.policyProviderFactories = policyProviderFactories;
this.policyEvaluator = new DefaultPolicyEvaluator(this);
}
@@ -92,15 +95,32 @@ public final class AuthorizationProvider implements Provider {
}
/**
+ * Cache sits in front of this
+ *
* Returns a {@link StoreFactory}.
*
* @return the {@link StoreFactory}
*/
public StoreFactory getStoreFactory() {
- return createStoreFactory();
+ if (storeFactory != null) return storeFactory;
+ storeFactory = keycloakSession.getProvider(CachedStoreFactoryProvider.class);
+ if (storeFactory == null) storeFactory = getLocalStoreFactory();
+ storeFactory = createStoreFactory(storeFactory);
+ return storeFactory;
}
- private StoreFactory createStoreFactory() {
+ /**
+ * No cache sits in front of this
+ *
+ * @return
+ */
+ public StoreFactory getLocalStoreFactory() {
+ if (storeFactoryDelegate != null) return storeFactoryDelegate;
+ storeFactoryDelegate = keycloakSession.getProvider(StoreFactory.class);
+ return storeFactoryDelegate;
+ }
+
+ private StoreFactory createStoreFactory(StoreFactory storeFactory) {
return new StoreFactory() {
@Override
public ResourceStore getResourceStore() {
@@ -222,7 +242,7 @@ public final class AuthorizationProvider implements Provider {
* Returns a {@link PolicyProviderFactory} given a <code>type</code>.
*
* @param type the type of the policy provider
- * @param <F> the expected type of the provider
+ * @param <P> the expected type of the provider
* @return a {@link PolicyProvider} with the given <code>type</code>
*/
public <P extends PolicyProvider> P getProvider(String type) {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/CachedModel.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/CachedModel.java
new file mode 100644
index 0000000..d908a84
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/CachedModel.java
@@ -0,0 +1,45 @@
+/*
+ * 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.authorization.model;
+
+/**
+ * Cached authorization model classes will implement this interface.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface CachedModel<Model> {
+ /**
+ * Invalidates the cache for this model and returns a delegate that represents the actual data provider
+ *
+ * @return
+ */
+ Model getDelegateForUpdate();
+
+ /**
+ * Invalidate the cache for this model
+ *
+ */
+ void invalidate();
+
+ /**
+ * When was the model was loaded from database.
+ *
+ * @return
+ */
+ long getCacheTimestamp();
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
index 03596d9..f46f61a 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
@@ -76,10 +76,11 @@ public interface Policy {
/**
* Returns a {@link Map} holding string-based key/value pairs representing any additional configuration for this policy.
*
- * @return a map with any additional configuration defined for this policy.
+ * @return a unmodifiable map with any additional configuration defined for this policy.
*/
Map<String, String> getConfig();
+
/**
* Sets a {@link Map} with string-based key/value pairs representing any additional configuration for this policy.
*
@@ -87,6 +88,9 @@ public interface Policy {
*/
void setConfig(Map<String, String> config);
+ void removeConfig(String name);
+ void putConfig(String name, String value);
+
/**
* Returns the name of this policy.
*
@@ -120,7 +124,7 @@ public interface Policy {
*
* @return a resource server
*/
- <R extends ResourceServer> R getResourceServer();
+ ResourceServer getResourceServer();
/**
* Returns the {@link Policy} instances associated with this policy and used to evaluate authorization decisions when
@@ -128,21 +132,21 @@ public interface Policy {
*
* @return the associated policies or an empty set if no policy is associated with this policy
*/
- <P extends Policy> Set<P> getAssociatedPolicies();
+ Set<Policy> getAssociatedPolicies();
/**
* Returns the {@link Resource} instances where this policy applies.
*
* @return a set with all resource instances where this policy applies. Or an empty set if there is no resource associated with this policy
*/
- <R extends Resource> Set<R> getResources();
+ Set<Resource> getResources();
/**
* Returns the {@link Scope} instances where this policy applies.
*
* @return a set with all scope instances where this policy applies. Or an empty set if there is no scope associated with this policy
*/
- <S extends Scope> Set<S> getScopes();
+ Set<Scope> getScopes();
void addScope(Scope scope);
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java
index 2bf2c6f..4c2521c 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java
@@ -82,7 +82,7 @@ public interface Resource {
*
* @return a list with all scopes associated with this resource
*/
- <S extends Scope> List<S> getScopes();
+ List<Scope> getScopes();
/**
* Returns an icon {@link java.net.URI} for this resource.
@@ -103,7 +103,7 @@ public interface Resource {
*
* @return the resource server associated with this resource
*/
- <R extends ResourceServer> R getResourceServer();
+ ResourceServer getResourceServer();
/**
* Returns the resource's owner, which is usually an identifier that uniquely identifies the resource's owner.
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
index 76a3fab..1c9c0df 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
@@ -21,10 +21,12 @@ package org.keycloak.authorization.store;
import java.util.HashMap;
import java.util.Map;
+import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
import org.keycloak.authorization.store.syncronization.Synchronizer;
import org.keycloak.authorization.store.syncronization.UserSynchronizer;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel.ClientRemovedEvent;
import org.keycloak.models.RealmModel.RealmRemovedEvent;
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
index b55ec74..9a2ac51 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
@@ -66,7 +66,7 @@ public interface ResourceStore {
/**
* Finds all {@link Resource} instances with the given uri.
*
- * @param ownerId the identifier of the owner
+ * @param uri the identifier of the uri
* @return a list with all resource instances owned by the given owner
*/
List<Resource> findByUri(String uri, String resourceServerId);
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
index 686eeef..aeb039d 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
@@ -41,9 +41,9 @@ public class ClientApplicationSynchronizer implements Synchronizer<ClientRemoved
if (resourceServer != null) {
String id = resourceServer.getId();
- storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
- storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
- storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
+ //storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
+ //storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
+ //storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
storeFactory.getResourceServerStore().delete(id);
}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
index f8844f1..d1e0ca2 100644
--- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
+++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
@@ -71,7 +71,7 @@ public class MigrateTo2_1_0 implements Migration {
if (resourceServer != null) {
policyStore.findByType("role", resourceServer.getId()).forEach(policy -> {
- Map<String, String> config = policy.getConfig();
+ Map<String, String> config = new HashMap(policy.getConfig());
String roles = config.get("roles");
List roleConfig;
diff --git a/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
index b8563cb..d466f7a 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
@@ -18,6 +18,9 @@
package org.keycloak.models.cache.authorization;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ProviderFactory;
/**
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 1c90b0f..7e528fb 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -2110,7 +2110,7 @@ public class RepresentationToModel {
}
}
- policy.getConfig().remove("scopes");
+ policy.removeConfig("scopes");
}
private static void updateAssociatedPolicies(Set<String> policyIds, Policy policy, StoreFactory storeFactory) {
@@ -2163,7 +2163,7 @@ public class RepresentationToModel {
}
}
- policy.getConfig().remove("applyPolicies");
+ policy.removeConfig("applyPolicies");
}
private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
@@ -2209,7 +2209,7 @@ public class RepresentationToModel {
}
}
- policy.getConfig().remove("resources");
+ policy.removeConfig("resources");
}
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
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 fb28054..3a9337e 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -16,6 +16,7 @@
*/
package org.keycloak.authorization.authorization;
+import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
@@ -46,6 +47,7 @@ import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.Cors;
+import org.keycloak.services.resources.RealmsResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.OPTIONS;
@@ -72,6 +74,7 @@ import java.util.stream.Stream;
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationTokenService {
+ protected static final Logger logger = Logger.getLogger(AuthorizationTokenService.class);
private final AuthorizationProvider authorization;
@@ -131,6 +134,7 @@ public class AuthorizationTokenService {
@Override
public void onError(Throwable cause) {
+ logger.error("failed authorize", cause);
asyncResponse.resume(cause);
}
});
diff --git a/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java b/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
index cc06284..d9d7b2d 100644
--- a/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
+++ b/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
@@ -65,11 +65,7 @@ public class DefaultAuthorizationProviderFactory implements AuthorizationProvide
@Override
public AuthorizationProvider create(KeycloakSession session, RealmModel realm) {
- StoreFactory storeFactory = session.getProvider(CachedStoreFactoryProvider.class);
- if (storeFactory == null) {
- storeFactory = session.getProvider(StoreFactory.class);
- }
- return new AuthorizationProvider(session, realm, storeFactory, policyProviderFactories);
+ return new AuthorizationProvider(session, realm, policyProviderFactories);
}
private Map<String, PolicyProviderFactory> configurePolicyProviderFactories(KeycloakSessionFactory keycloakSessionFactory) {
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 326deb6..463ff0b 100644
--- a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
@@ -41,10 +41,12 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.authorization.AuthorizationTokenService;
import org.keycloak.authorization.common.KeycloakEvaluationContext;
import org.keycloak.authorization.common.KeycloakIdentity;
import org.keycloak.authorization.entitlement.representation.EntitlementRequest;
@@ -79,6 +81,7 @@ import org.keycloak.services.resources.Cors;
*/
public class EntitlementService {
+ protected static final Logger logger = Logger.getLogger(EntitlementService.class);
private final AuthorizationProvider authorization;
@Context
@@ -122,6 +125,7 @@ public class EntitlementService {
@Override
public void onError(Throwable cause) {
+ logger.error("failed", cause);
asyncResponse.resume(cause);
}
@@ -175,6 +179,7 @@ public class EntitlementService {
authorization.evaluators().from(createPermissions(entitlementRequest, resourceServer, authorization), new KeycloakEvaluationContext(this.authorization.getKeycloakSession())).evaluate(new DecisionResultCollector() {
@Override
public void onError(Throwable cause) {
+ logger.error("failed", cause);
asyncResponse.resume(cause);
}
diff --git a/services/src/main/java/org/keycloak/authorization/util/Permissions.java b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
index 2e2c4a8..a805fbc 100644
--- a/services/src/main/java/org/keycloak/authorization/util/Permissions.java
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -21,6 +21,7 @@ package org.keycloak.authorization.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -61,8 +62,8 @@ public final class Permissions {
StoreFactory storeFactory = authorization.getStoreFactory();
ResourceStore resourceStore = storeFactory.getResourceStore();
- resourceStore.findByOwner(resourceServer.getClientId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, resource.getScopes(), authorization)));
- resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, resource.getScopes(), authorization)));
+ resourceStore.findByOwner(resourceServer.getClientId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
+ resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
return permissions;
}
@@ -74,7 +75,7 @@ public final class Permissions {
List<Scope> scopes;
if (requestedScopes.isEmpty()) {
- scopes = resource.getScopes();
+ scopes = new LinkedList<>(resource.getScopes());
// check if there is a typed resource whose scopes are inherited by the resource being requested. In this case, we assume that parent resource
// is owned by the resource server itself
if (type != null && !resource.getOwner().equals(resourceServer.getClientId())) {
@@ -102,7 +103,6 @@ public final class Permissions {
return byName;
}).collect(Collectors.toList());
}
-
permissions.add(new ResourcePermission(resource, scopes, resource.getResourceServer()));
return permissions;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java
index 45a937c..450820e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java
@@ -213,7 +213,7 @@ public class ConflictingScopePermissionTest extends AbstractKeycloakTest {
}
representation.addScope(scopes.toArray(new String[scopes.size()]));
- representation.addPolicy(scopes.toArray(new String[policies.size()]));
+ representation.addPolicy(policies.toArray(new String[policies.size()]));
authorization.permissions().scope().create(representation);
}
diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
index 0d3b4aa..818626a 100755
--- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
+++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.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"/>