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 8a647d8a85..7d1a731a8c 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 @@ -68,7 +68,7 @@ public class JPAResourceStore implements ResourceStore { @Override public void delete(String id) { - ResourceEntity resource = entityManager.find(ResourceEntity.class, id); + ResourceEntity resource = entityManager.getReference(ResourceEntity.class, id); if (resource == null) return; resource.getScopes().clear(); @@ -95,9 +95,12 @@ public class JPAResourceStore implements ResourceStore { List result = query.getResultList(); List list = new LinkedList<>(); + ResourceStore resourceStore = provider.getStoreFactory().getResourceStore(); + for (String id : result) { - list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId)); + list.add(resourceStore.findById(id, resourceServerId)); } + return list; } @@ -110,9 +113,12 @@ public class JPAResourceStore implements ResourceStore { List result = query.getResultList(); List list = new LinkedList<>(); + ResourceStore resourceStore = provider.getStoreFactory().getResourceStore(); + for (String id : result) { - list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId)); + list.add(resourceStore.findById(id, resourceServerId)); } + return list; } @@ -124,9 +130,12 @@ public class JPAResourceStore implements ResourceStore { List result = query.getResultList(); List list = new LinkedList<>(); + ResourceStore resourceStore = provider.getStoreFactory().getResourceStore(); + for (String id : result) { - list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId)); + list.add(resourceStore.findById(id, resourceServerId)); } + return list; } @@ -163,9 +172,12 @@ public class JPAResourceStore implements ResourceStore { List result = query.getResultList(); List list = new LinkedList<>(); + ResourceStore resourceStore = provider.getStoreFactory().getResourceStore(); + for (String id : result) { - list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId)); + list.add(resourceStore.findById(id, resourceServerId)); } + return list; } @@ -178,9 +190,12 @@ public class JPAResourceStore implements ResourceStore { List result = query.getResultList(); List list = new LinkedList<>(); + ResourceStore resourceStore = provider.getStoreFactory().getResourceStore(); + for (String id : result) { - list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId)); + list.add(resourceStore.findById(id, resourceServerId)); } + return list; } @@ -207,9 +222,12 @@ public class JPAResourceStore implements ResourceStore { List result = query.getResultList(); List list = new LinkedList<>(); + ResourceStore resourceStore = provider.getStoreFactory().getResourceStore(); + for (String id : result) { - list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId)); + list.add(resourceStore.findById(id, resourceServerId)); } + return list; } } diff --git a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java index 535634bd72..3d4f163363 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java @@ -35,13 +35,11 @@ public class AuthorizationService { private final AdminPermissionEvaluator auth; private final ClientModel client; - private final KeycloakSession session; - private final ResourceServer resourceServer; + private ResourceServer resourceServer; private final AuthorizationProvider authorization; private final AdminEventBuilder adminEvent; public AuthorizationService(KeycloakSession session, ClientModel client, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) { - this.session = session; this.client = client; this.authorization = session.getProvider(AuthorizationProvider.class); this.adminEvent = adminEvent; @@ -60,7 +58,7 @@ public class AuthorizationService { public void enable(boolean newClient) { if (!isEnabled()) { - resourceServer().create(newClient); + this.resourceServer = resourceServer().create(newClient); } } diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java index e52da9a8b5..9c7a291559 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java @@ -19,7 +19,6 @@ package org.keycloak.authorization.admin; import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation; -import java.io.IOException; import java.util.HashMap; import javax.ws.rs.Consumes; @@ -36,10 +35,6 @@ import javax.ws.rs.core.UriInfo; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.model.ResourceServer; -import org.keycloak.authorization.store.PolicyStore; -import org.keycloak.authorization.store.ResourceStore; -import org.keycloak.authorization.store.ScopeStore; -import org.keycloak.authorization.store.StoreFactory; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; import org.keycloak.exportimport.util.ExportUtils; @@ -56,8 +51,8 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; -import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; import org.keycloak.services.resources.admin.AdminEventBuilder; +import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; /** * @author Pedro Igor @@ -83,7 +78,11 @@ public class ResourceServerService { this.adminEvent = adminEvent; } - public void create(boolean newClient) { + public ResourceServer create(boolean newClient) { + if (resourceServer != null) { + throw new IllegalStateException("Resource server already created"); + } + this.auth.realm().requireManageAuthorization(); UserModel serviceAccount = this.session.users().getServiceAccount(client); @@ -96,6 +95,8 @@ public class ResourceServerService { createDefaultRoles(serviceAccount); createDefaultPermission(createDefaultResource(), createDefaultPolicy()); audit(OperationType.CREATE, uriInfo, newClient); + + return resourceServer; } @PUT @@ -111,22 +112,7 @@ public class ResourceServerService { public void delete() { this.auth.realm().requireManageAuthorization(); - StoreFactory storeFactory = authorization.getStoreFactory(); - ResourceStore resourceStore = storeFactory.getResourceStore(); - String id = resourceServer.getId(); - - PolicyStore policyStore = storeFactory.getPolicyStore(); - - policyStore.findByResourceServer(id).forEach(scope -> policyStore.delete(scope.getId())); - - resourceStore.findByResourceServer(id).forEach(resource -> resourceStore.delete(resource.getId())); - - ScopeStore scopeStore = storeFactory.getScopeStore(); - - scopeStore.findByResourceServer(id).forEach(scope -> scopeStore.delete(scope.getId())); - - storeFactory.getResourceServerStore().delete(id); - + authorization.getStoreFactory().getResourceServerStore().delete(resourceServer.getId()); audit(OperationType.DELETE, uriInfo, false); } @@ -148,7 +134,7 @@ public class ResourceServerService { @Path("/import") @POST @Consumes(MediaType.APPLICATION_JSON) - public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) throws IOException { + public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) { this.auth.realm().requireManageAuthorization(); rep.setClientId(client.getId()); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java index decb4da636..c0ea7df937 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java @@ -33,6 +33,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ForbiddenException; @@ -188,7 +189,15 @@ public class ClientsResource { if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) { if (TRUE.equals(rep.getAuthorizationServicesEnabled())) { - getAuthorizationService(clientModel).enable(true); + AuthorizationService authorizationService = getAuthorizationService(clientModel); + + authorizationService.enable(true); + + ResourceServerRepresentation authorizationSettings = rep.getAuthorizationSettings(); + + if (authorizationSettings != null) { + authorizationService.resourceServer().importSettings(uriInfo, authorizationSettings); + } } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceServerManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceServerManagementTest.java new file mode 100644 index 0000000000..73e1961d30 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceServerManagementTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.testsuite.admin.client.authorization; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; +import org.keycloak.admin.client.resource.AuthorizationResource; +import org.keycloak.admin.client.resource.ClientsResource; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.authorization.PolicyEnforcementMode; +import org.keycloak.util.JsonSerialization; + +/** + * + * @author Pedro Igor + */ +public class ResourceServerManagementTest extends AbstractAuthorizationTest { + + @Test + public void testCreateAndDeleteResourceServer() throws Exception { + ClientsResource clientsResource = testRealmResource().clients(); + + clientsResource.create(JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/client-with-authz-settings.json"), ClientRepresentation.class)).close(); + + List clients = clientsResource.findByClientId("authz-client"); + + assertFalse(clients.isEmpty()); + + String clientId = clients.get(0).getId(); + AuthorizationResource settings = clientsResource.get(clientId).authorization(); + + assertEquals(PolicyEnforcementMode.PERMISSIVE, settings.exportSettings().getPolicyEnforcementMode()); + + assertFalse(settings.resources().findByName("Resource 1").isEmpty()); + assertFalse(settings.resources().findByName("Resource 15").isEmpty()); + assertFalse(settings.resources().findByName("Resource 20").isEmpty()); + + assertNotNull(settings.permissions().resource().findByName("Resource 15 Permission")); + assertNotNull(settings.policies().role().findByName("Resource 1 Policy")); + + clientsResource.get(clientId).remove(); + + clients = clientsResource.findByClientId("authz-client"); + + assertTrue(clients.isEmpty()); + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/client-with-authz-settings.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/client-with-authz-settings.json new file mode 100644 index 0000000000..ccc3ccc975 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/client-with-authz-settings.json @@ -0,0 +1,866 @@ +{ + "clientId": "authz-client", + "enabled": true, + "publicClient": false, + "secret": "secret", + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "redirectUris": [ + "http://localhost/authz-client/*" + ], + "webOrigins": [ + "http://localhost" + ], + "authorizationSettings": { + "allowRemoteResourceManagement": true, + "policyEnforcementMode": "PERMISSIVE", + "resources": [ + { + "name": "Default Resource", + "uri": "/*", + "type": "urn:authz-client:resources:default" + }, + { + "name": "Resource 1", + "uri": "/protected/resource/1", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 2", + "uri": "/protected/resource/2", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 3", + "uri": "/protected/resource/3", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 4", + "uri": "/protected/resource/4", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 5", + "uri": "/protected/resource/5", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 6", + "uri": "/protected/resource/6", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 7", + "uri": "/protected/resource/7", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 8", + "uri": "/protected/resource/8", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 9", + "uri": "/protected/resource/9", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 10", + "uri": "/protected/resource/10", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 11", + "uri": "/protected/resource/11", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 12", + "uri": "/protected/resource/12", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 13", + "uri": "/protected/resource/13", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 14", + "uri": "/protected/resource/14", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 15", + "uri": "/protected/resource/15", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 16", + "uri": "/protected/resource/16", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 17", + "uri": "/protected/resource/17", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 18", + "uri": "/protected/resource/18", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 19", + "uri": "/protected/resource/19", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + }, + { + "name": "Resource 20", + "uri": "/protected/resource/20", + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + } + ], + "policies": [ + { + "name": "Default Policy", + "description": "A policy that grants access only for users within this realm", + "type": "js", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n" + } + }, + { + "name": "Resource 1 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 2 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 3 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 4 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 5 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 6 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 7 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 8 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 9 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 10 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 11 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 12 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 13 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 14 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 15 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 16 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 17 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 18 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 19 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Resource 20 Policy", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]" + } + }, + { + "name": "Default Permission", + "description": "A permission that applies to the default resource type", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "defaultResourceType": "urn:authz-client:resources:default", + "applyPolicies": "[\"Default Policy\"]" + } + }, + { + "name": "Resource 1 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 1\"]", + "applyPolicies": "[\"Resource 1 Policy\"]" + } + }, + { + "name": "Resource 2 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 2\"]", + "applyPolicies": "[\"Resource 2 Policy\"]" + } + }, + { + "name": "Resource 3 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 3\"]", + "applyPolicies": "[\"Resource 3 Policy\"]" + } + }, + { + "name": "Resource 4 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 4\"]", + "applyPolicies": "[\"Resource 4 Policy\"]" + } + }, + { + "name": "Resource 5 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 5\"]", + "applyPolicies": "[\"Resource 5 Policy\"]" + } + }, + { + "name": "Resource 6 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 6\"]", + "applyPolicies": "[\"Resource 6 Policy\"]" + } + }, + { + "name": "Resource 7 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 7\"]", + "applyPolicies": "[\"Resource 7 Policy\"]" + } + }, + { + "name": "Resource 8 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 8\"]", + "applyPolicies": "[\"Resource 8 Policy\"]" + } + }, + { + "name": "Resource 9 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 9\"]", + "applyPolicies": "[\"Resource 9 Policy\"]" + } + }, + { + "name": "Resource 10 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 10\"]", + "applyPolicies": "[\"Resource 10 Policy\"]" + } + }, + { + "name": "Resource 11 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 11\"]", + "applyPolicies": "[\"Resource 11 Policy\"]" + } + }, + { + "name": "Resource 12 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 12\"]", + "applyPolicies": "[\"Resource 12 Policy\"]" + } + }, + { + "name": "Resource 13 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 13\"]", + "applyPolicies": "[\"Resource 13 Policy\"]" + } + }, + { + "name": "Resource 14 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 14\"]", + "applyPolicies": "[\"Resource 14 Policy\"]" + } + }, + { + "name": "Resource 15 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 15\"]", + "applyPolicies": "[\"Resource 15 Policy\"]" + } + }, + { + "name": "Resource 16 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 16\"]", + "applyPolicies": "[\"Resource 16 Policy\"]" + } + }, + { + "name": "Resource 17 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 17\"]", + "applyPolicies": "[\"Resource 17 Policy\"]" + } + }, + { + "name": "Resource 18 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 18\"]", + "applyPolicies": "[\"Resource 18 Policy\"]" + } + }, + { + "name": "Resource 19 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 19\"]", + "applyPolicies": "[\"Resource 19 Policy\"]" + } + }, + { + "name": "Resource 20 Permission", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Resource 20\"]", + "applyPolicies": "[\"Resource 20 Policy\"]" + } + } + ], + "scopes": [ + { + "name": "Scope B" + }, + { + "name": "Scope A" + }, + { + "name": "Scope D" + }, + { + "name": "Scope C" + }, + { + "name": "Scope E" + } + ] + } +} \ No newline at end of file