keycloak-aplcache
Changes
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java 3(+0 -3)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java 6(+0 -6)
authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java 6(+0 -6)
model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.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 8f7e631..a0e7874 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
@@ -78,9 +78,6 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory {
try {
if (clients.isEmpty()) {
- policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
- dependentPolicy.removeAssociatedPolicy(policy);
- });
policyStore.delete(policy.getId());
} else {
policy.getConfig().put("clients", JsonSerialization.writeValueAsString(clients));
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 90047bb..d5d3917 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
@@ -230,12 +230,6 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
try {
if (roles.isEmpty()) {
- policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
- dependentPolicy.removeAssociatedPolicy(policy);
- if (dependentPolicy.getAssociatedPolicies().isEmpty()) {
- policyStore.delete(dependentPolicy.getId());
- }
- });
policyStore.delete(policy.getId());
} else {
Map<String, String> config = policy.getConfig();
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 2d3c219..0fd54df 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
@@ -180,12 +180,6 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
try {
if (users.isEmpty()) {
- policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
- dependentPolicy.removeAssociatedPolicy(policy);
- if (dependentPolicy.getAssociatedPolicies().isEmpty()) {
- policyStore.delete(dependentPolicy.getId());
- }
- });
policyStore.delete(policy.getId());
} else {
policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
index 5bb3651..b517098 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
@@ -102,6 +102,10 @@ public class CachedPolicyStore implements PolicyStore {
@Override
public Policy findById(String id, String resourceServerId) {
+ if (resourceServerId == null) {
+ return getDelegate().findById(id, null);
+ }
+
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
List<CachedPolicy> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForPolicy);
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 76e6894..c5b75d3 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
@@ -128,7 +128,20 @@ public final class AuthorizationProvider implements Provider {
@Override
public void delete(String id) {
- policyStore.delete(id);
+ Policy policy = findById(id, null);
+
+ if (policy != null) {
+ ResourceServer resourceServer = policy.getResourceServer();
+
+ findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
+ dependentPolicy.removeAssociatedPolicy(policy);
+ if (dependentPolicy.getAssociatedPolicies().isEmpty()) {
+ delete(dependentPolicy.getId());
+ }
+ });
+
+ policyStore.delete(id);
+ }
}
@Override
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
index e2db57e..85e0943 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java
@@ -96,14 +96,6 @@ public class PolicyResourceService {
resource.onRemove(policy, authorization);
- policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
- if (dependentPolicy.getAssociatedPolicies().size() == 1) {
- policyStore.delete(dependentPolicy.getId());
- } else {
- dependentPolicy.removeAssociatedPolicy(policy);
- }
- });
-
policyStore.delete(policy.getId());
return Response.noContent().build();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AuthzCleanupTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AuthzCleanupTest.java
index 69d8d6b..4c472fb 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AuthzCleanupTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AuthzCleanupTest.java
@@ -23,20 +23,24 @@ import java.util.List;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.util.JsonSerialization;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -56,7 +60,17 @@ public class AuthzCleanupTest extends AbstractKeycloakTest {
.secret("secret")
.authorizationServicesEnabled(true)
.redirectUris("http://localhost/myclient")
- .defaultRoles("client-role-1", "client-role-2").build()).build());
+ .defaultRoles(
+ "client-role-1",
+ "client-role-2",
+ "Acme administrator",
+ "Acme viewer",
+ "tenant administrator",
+ "tenant viewer",
+ "tenant user"
+ )
+ .build())
+ .build());
}
public static void setup(KeycloakSession session) {
@@ -84,6 +98,12 @@ public class AuthzCleanupTest extends AbstractKeycloakTest {
@Test
public void testCreate() throws Exception {
+ ClientsResource clients = getAdminClient().realms().realm(TEST).clients();
+ ClientRepresentation client = clients.findByClientId("myclient").get(0);
+ ResourceServerRepresentation settings = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/acme-resource-server-cleanup-test.json"), ResourceServerRepresentation.class);
+
+ clients.get(client.getId()).authorization().importSettings(settings);
+
testingClient.server().run(AuthzCleanupTest::setup);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/acme-resource-server-cleanup-test.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/acme-resource-server-cleanup-test.json
new file mode 100644
index 0000000..3c1f55f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/acme-resource-server-cleanup-test.json
@@ -0,0 +1,195 @@
+{
+ "allowRemoteResourceManagement": false,
+ "policyEnforcementMode": "ENFORCING",
+ "resources": [
+ {
+ "name": "Administration resource",
+ "uri": "/admin/*",
+ "type": "http://acme.com/admin",
+ "scopes": [
+ {
+ "name": "urn:acme.com:scopes:admin:manage"
+ },
+ {
+ "name": "urn:acme.com:scopes:admin:view"
+ }
+ ],
+ "typedScopes": []
+ },
+ {
+ "name": "Role resource",
+ "uri": "/{REALM}/roles",
+ "type": "http://acme.com/roles",
+ "scopes": [
+ {
+ "name": "urn:acme.com:scopes:role:view"
+ }
+ ],
+ "typedScopes": []
+ },
+ {
+ "name": "User profile resource",
+ "uri": "/{REALM}/userprofiles/*",
+ "type": "http://acme.com/userprofiles",
+ "scopes": [
+ {
+ "name": "urn:acme.com:scopes:userprofile:manage"
+ },
+ {
+ "name": "urn:acme.com:scopes:userprofile:view"
+ }
+ ],
+ "typedScopes": []
+ },
+ {
+ "name": "Account resource",
+ "uri": "/{REALM}/account/*",
+ "type": "http://acme.com/account",
+ "scopes": [
+ {
+ "name": "urn:acme.com:scopes:account:manage"
+ }
+ ],
+ "typedScopes": []
+ }
+ ],
+ "policies": [
+ {
+ "name": "Acme admin policy",
+ "type": "role",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "roles": "[{\"id\":\"Acme administrator\",\"required\":true}]"
+ }
+ },
+ {
+ "name": "Acme viewer policy",
+ "type": "role",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "roles": "[{\"id\":\"Acme viewer\",\"required\":true}]"
+ }
+ },
+ {
+ "name": "Tenant user policy",
+ "type": "role",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "roles": "[{\"id\":\"tenant user\",\"required\":true}]"
+ }
+ },
+ {
+ "name": "Tenant administrator policy",
+ "type": "role",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "roles": "[{\"id\":\"tenant administrator\",\"required\":true}]"
+ }
+ },
+ {
+ "name": "Tenant viewer policy",
+ "type": "role",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "roles": "[{\"id\":\"tenant viewer\",\"required\":true}]"
+ }
+ },
+ {
+ "name": "Any user policy",
+ "description": "Defines that only users from well known clients are allowed to access",
+ "type": "aggregate",
+ "logic": "POSITIVE",
+ "decisionStrategy": "AFFIRMATIVE",
+ "config": {
+ "applyPolicies": "[\"Tenant user policy\",\"Acme admin policy\",\"Acme viewer policy\",\"Tenant viewer policy\",\"Tenant administrator policy\"]"
+ }
+ },
+ {
+ "name": "Super tenant admin permission",
+ "type": "scope",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "scopes": "[\"urn:acme.com:scopes:admin:manage\"]",
+ "applyPolicies": "[\"Acme admin policy\"]"
+ }
+ },
+ {
+ "name": "Super tenant admin read permission",
+ "type": "scope",
+ "logic": "POSITIVE",
+ "decisionStrategy": "AFFIRMATIVE",
+ "config": {
+ "scopes": "[\"urn:acme.com:scopes:admin:view\"]",
+ "applyPolicies": "[\"Acme admin policy\",\"Acme viewer policy\"]"
+ }
+ },
+ {
+ "name": "View tenant role permission",
+ "type": "scope",
+ "logic": "POSITIVE",
+ "decisionStrategy": "AFFIRMATIVE",
+ "config": {
+ "resources": "[\"Role resource\"]",
+ "scopes": "[\"urn:acme.com:scopes:role:view\"]",
+ "applyPolicies": "[\"Any user policy\"]"
+ }
+ },
+ {
+ "name": "Manage account permission",
+ "type": "scope",
+ "logic": "POSITIVE",
+ "decisionStrategy": "AFFIRMATIVE",
+ "config": {
+ "resources": "[\"Account resource\"]",
+ "scopes": "[\"urn:acme.com:scopes:account:manage\"]",
+ "applyPolicies": "[\"Any user policy\"]"
+ }
+ },
+ {
+ "name": "Manage user profile permission",
+ "type": "scope",
+ "logic": "POSITIVE",
+ "decisionStrategy": "AFFIRMATIVE",
+ "config": {
+ "scopes": "[\"urn:acme.com:scopes:userprofile:manage\"]",
+ "applyPolicies": "[\"Acme admin policy\",\"Tenant administrator policy\"]"
+ }
+ },
+ {
+ "name": "View user profile permission",
+ "type": "scope",
+ "logic": "POSITIVE",
+ "decisionStrategy": "AFFIRMATIVE",
+ "config": {
+ "scopes": "[\"urn:acme.com:scopes:userprofile:view\"]",
+ "applyPolicies": "[\"Acme admin policy\",\"Acme viewer policy\",\"Tenant viewer policy\",\"Tenant administrator policy\"]"
+ }
+ }
+ ],
+ "scopes": [
+ {
+ "name": "urn:acme.com:scopes:admin:manage"
+ },
+ {
+ "name": "urn:acme.com:scopes:admin:view"
+ },
+ {
+ "name": "urn:acme.com:scopes:role:view"
+ },
+ {
+ "name": "urn:acme.com:scopes:account:manage"
+ },
+ {
+ "name": "urn:acme.com:scopes:userprofile:view"
+ },
+ {
+ "name": "urn:acme.com:scopes:userprofile:manage"
+ }
+ ]
+}
\ No newline at end of file