keycloak-uncached

[KEYCLOAK-5148] - Create authorization settings when creating

7/5/2017 6:19:00 PM

Details

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 599ad70..7a505ab 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();
@@ -96,9 +96,12 @@ public class JPAResourceStore implements ResourceStore {
 
         List<String> result = query.getResultList();
         List<Resource> 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;
     }
 
@@ -112,9 +115,12 @@ public class JPAResourceStore implements ResourceStore {
 
         List<String> result = query.getResultList();
         List<Resource> 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;
     }
 
@@ -126,9 +132,12 @@ public class JPAResourceStore implements ResourceStore {
 
         List<String> result = query.getResultList();
         List<Resource> 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;
     }
 
@@ -165,9 +174,12 @@ public class JPAResourceStore implements ResourceStore {
 
         List<String> result = query.getResultList();
         List<Resource> 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;
     }
 
@@ -181,9 +193,12 @@ public class JPAResourceStore implements ResourceStore {
 
         List<String> result = query.getResultList();
         List<Resource> 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;
     }
 
@@ -213,9 +228,12 @@ public class JPAResourceStore implements ResourceStore {
 
         List<String> result = query.getResultList();
         List<Resource> 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 535634b..3d4f163 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 e52da9a..9c7a291 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 <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -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 decb4da..c0ea7df 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 0000000..73e1961
--- /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 <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+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<ClientRepresentation> 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 0000000..ccc3ccc
--- /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