keycloak-aplcache

Merge pull request #3500 from pedroigor/KEYCLOAK-3554-new [KEYCLOAK-3554]

11/14/2016 6:10:37 PM

Details

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 c2e654e..1261a41 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
@@ -31,10 +31,7 @@ import org.keycloak.authorization.store.ScopeStore;
 import org.keycloak.authorization.store.StoreFactory;
 import org.keycloak.common.enums.SslRequired;
 import org.keycloak.common.util.Base64;
-import org.keycloak.common.util.CertificateUtils;
-import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.MultivaluedHashMap;
-import org.keycloak.common.util.PemUtils;
 import org.keycloak.common.util.UriUtils;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.credential.CredentialModel;
@@ -105,11 +102,7 @@ import org.keycloak.storage.federated.UserFederatedStorageProvider;
 import org.keycloak.util.JsonSerialization;
 
 import java.io.IOException;
-import java.security.KeyPair;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -1866,7 +1859,18 @@ public class RepresentationToModel {
             toModel(resourceRepresentation, resourceServer, authorization);
         });
 
-        rep.getPolicies().forEach(policyRepresentation -> {
+        importPolicies(authorization, resourceServer, rep.getPolicies(), null);
+    }
+
+    private static Policy importPolicies(AuthorizationProvider authorization, ResourceServer resourceServer, List<PolicyRepresentation> policiesToImport, String parentPolicyName) {
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        KeycloakSession session = authorization.getKeycloakSession();
+        RealmModel realm = authorization.getRealm();
+        for (PolicyRepresentation policyRepresentation : policiesToImport) {
+            if (parentPolicyName != null && !parentPolicyName.equals(policyRepresentation.getName())) {
+                continue;
+            }
+
             Map<String, String> config = policyRepresentation.getConfig();
 
             String roles = config.get("roles");
@@ -1900,6 +1904,16 @@ public class RepresentationToModel {
                         }
 
                         if (role == null) {
+                            role = realm.getRoleById(roleName);
+
+                            if (role == null) {
+                                String finalRoleName1 = roleName;
+                                role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName1)).filter(roleModel -> roleModel != null)
+                                        .findFirst().orElse(null);
+                            }
+                        }
+
+                        if (role == null) {
                             throw new RuntimeException("Error while importing configuration. Role [" + roleName + "] could not be found.");
                         }
 
@@ -1916,7 +1930,19 @@ public class RepresentationToModel {
             if (users != null && !users.isEmpty()) {
                 try {
                     List<String> usersMap = JsonSerialization.readValue(users, List.class);
-                    config.put("users", JsonSerialization.writeValueAsString(usersMap.stream().map(userName -> session.users().getUserByUsername(userName, realm).getId()).collect(Collectors.toList())));
+                    config.put("users", JsonSerialization.writeValueAsString(usersMap.stream().map(userId -> {
+                        UserModel user = session.users().getUserByUsername(userId, realm);
+
+                        if (user == null) {
+                            user = session.users().getUserById(userId, realm);
+                        }
+
+                        if (user == null) {
+                            throw new RuntimeException("Error while importing configuration. User [" + userId + "] could not be found.");
+                        }
+
+                        return user.getId();
+                    }).collect(Collectors.toList())));
                 } catch (Exception e) {
                     throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
                 }
@@ -1926,11 +1952,16 @@ public class RepresentationToModel {
 
             if (scopes != null && !scopes.isEmpty()) {
                 try {
+                    ScopeStore scopeStore = storeFactory.getScopeStore();
                     List<String> scopesMap = JsonSerialization.readValue(scopes, List.class);
                     config.put("scopes", JsonSerialization.writeValueAsString(scopesMap.stream().map(scopeName -> {
                         Scope newScope = scopeStore.findByName(scopeName, resourceServer.getId());
 
                         if (newScope == null) {
+                            newScope = scopeStore.findById(scopeName);
+                        }
+
+                        if (newScope == null) {
                             throw new RuntimeException("Scope with name [" + scopeName + "] not defined.");
                         }
 
@@ -1947,8 +1978,21 @@ public class RepresentationToModel {
                 ResourceStore resourceStore = storeFactory.getResourceStore();
                 try {
                     List<String> resources = JsonSerialization.readValue(policyResources, List.class);
-                    config.put("resources", JsonSerialization.writeValueAsString(resources.stream().map(resourceName -> {
-                        return resourceStore.findByName(resourceName, resourceServer.getId()).getId();
+                    config.put("resources", JsonSerialization.writeValueAsString(resources.stream().map(new Function<String, String>() {
+                        @Override
+                        public String apply(String resourceName) {
+                            Resource resource = resourceStore.findByName(resourceName, resourceServer.getId());
+
+                            if (resource == null) {
+                                resource = resourceStore.findById(resourceName);
+                            }
+
+                            if (resource == null) {
+                                throw new RuntimeException("Resource with name [" + resourceName + "] not defined.");
+                            }
+
+                            return resource.getId();
+                        }
                     }).collect(Collectors.toList())));
                 } catch (Exception e) {
                     throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
@@ -1965,7 +2009,14 @@ public class RepresentationToModel {
                         Policy policy = policyStore.findByName(policyName, resourceServer.getId());
 
                         if (policy == null) {
-                            throw new RuntimeException("Policy with name [" + policyName + "] not defined.");
+                            policy = policyStore.findById(policyName);
+                        }
+
+                        if (policy == null) {
+                            policy = importPolicies(authorization, resourceServer, policiesToImport, policyName);
+                            if (policy == null) {
+                                throw new RuntimeException("Policy with name [" + policyName + "] not defined.");
+                            }
                         }
 
                         return policy.getId();
@@ -1975,8 +2026,14 @@ public class RepresentationToModel {
                 }
             }
 
-            toModel(policyRepresentation, resourceServer, authorization);
-        });
+            if (parentPolicyName == null) {
+                toModel(policyRepresentation, resourceServer, authorization);
+            } else if (parentPolicyName.equals(policyRepresentation.getName())) {
+                return toModel(policyRepresentation, resourceServer, authorization);
+            }
+        }
+
+        return null;
     }
 
     public static Policy toModel(PolicyRepresentation policy, ResourceServer resourceServer, AuthorizationProvider authorization) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
new file mode 100644
index 0000000..2922a3e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.testsuite.admin.client.authorization;
+
+import static com.sun.corba.se.impl.oa.poa.Policies.defaultPolicies;
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
+
+    @Test
+    public void testImportUnorderedSettings() throws Exception {
+        ClientResource clientResource = getClientResource();
+
+        enableAuthorizationServices();
+
+        ResourceServerRepresentation toImport = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/import-authorization-unordered-settings.json"), ResourceServerRepresentation.class);
+
+        realmsResouce().realm(getRealmId()).roles().create(new RoleRepresentation("user", null, false));
+        clientResource.roles().create(new RoleRepresentation("manage-albums", null, false));
+
+        AuthorizationResource authorizationResource = clientResource.authorization();
+
+        authorizationResource.importSettings(toImport);
+
+        assertEquals(13, authorizationResource.policies().policies().size());
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
new file mode 100644
index 0000000..4b30031
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
@@ -0,0 +1,183 @@
+{
+  "allowRemoteResourceManagement": true,
+  "policyEnforcementMode": "ENFORCING",
+  "resources": [
+    {
+      "name": "User Profile Resource",
+      "uri": "/profile",
+      "type": "http://photoz.com/profile",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:profile:view"
+        }
+      ]
+    },
+    {
+      "name": "Album Resource",
+      "uri": "/album/*",
+      "type": "http://photoz.com/album",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:album:view"
+        },
+        {
+          "name": "urn:photoz.com:scopes:album:delete"
+        },
+        {
+          "name": "urn:photoz.com:scopes:album:create"
+        }
+      ]
+    },
+    {
+      "name": "Admin Resources",
+      "uri": "/admin/*",
+      "type": "http://photoz.com/admin",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:album:admin:manage"
+        }
+      ]
+    }
+  ],
+  "policies": [
+    {
+      "name": "View User Permission",
+      "description": "Defines who is allowed to view an user profile",
+      "type": "scope",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only From @keycloak.org or Admin\"]",
+        "scopes": "[\"urn:photoz.com:scopes:profile:view\"]"
+      }
+    },
+    {
+      "name": "Only Owner Policy",
+      "description": "Defines that only the resource owner is allowed to do something",
+      "type": "drools",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "mavenArtifactVersion": "${project.version}",
+        "mavenArtifactId": "photoz-authz-policy",
+        "sessionName": "MainOwnerSession",
+        "mavenArtifactGroupId": "org.keycloak",
+        "moduleName": "PhotozAuthzOwnerPolicy",
+        "scannerPeriod": "1",
+        "scannerPeriodUnit": "Hours"
+      }
+    },
+    {
+      "name": "Any User Policy",
+      "description": "Defines that only users from well known clients are allowed to access",
+      "type": "role",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "roles": "[{\"id\":\"user\"},{\"id\":\"manage-albums\",\"required\":true}]"
+      }
+    },
+    {
+      "name": "Only From a Specific Client Address",
+      "description": "Defines that only clients from a specific address can do something",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "code": "var contextAttributes = $evaluation.getContext().getAttributes();\n\nif (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Administration Policy",
+      "description": "Defines that only administrators from a specific network address can do something.",
+      "type": "aggregate",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only From a Specific Client Address\",\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Only Owner and Administrators Policy",
+      "description": "Defines that only the resource owner and administrators can do something",
+      "type": "aggregate",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "applyPolicies": "[\"Administration Policy\",\"Only Owner Policy\"]"
+      }
+    },
+    {
+      "name": "Album Resource Permission",
+      "description": "General policies that apply to all album resources.",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "defaultResourceType": "http://photoz.com/album",
+        "default": "true",
+        "applyPolicies": "[\"Any User Policy\",\"Administration Policy\"]"
+      }
+    },
+    {
+      "name": "Admin Resource Permission",
+      "description": "General policy for any administrative resource.",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "defaultResourceType": "http://photoz.com/admin",
+        "default": "true",
+        "applyPolicies": "[\"Administration Policy\"]"
+      }
+    },
+    {
+      "name": "Delete Album Permission",
+      "description": "A policy that only allows the owner to delete his albums.",
+      "type": "scope",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only Owner and Administrators Policy\"]",
+        "scopes": "[\"urn:photoz.com:scopes:album:delete\"]"
+      }
+    },
+    {
+      "name": "Any Admin Policy",
+      "description": "Defines that adminsitrators can do something",
+      "type": "role",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "roles": "[{\"id\":\"admin\",\"required\":true}]"
+      }
+    },
+    {
+      "name": "Only From @keycloak.org or Admin",
+      "description": "Defines that only users from @keycloak.org",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRole('admin') || email.endsWith('@keycloak.org')) {\n    $evaluation.grant();\n}"
+      }
+    }
+  ],
+  "scopes": [
+    {
+      "name": "urn:photoz.com:scopes:profile:view"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:view"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:create"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:delete"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:admin:manage"
+    }
+  ]
+}
\ No newline at end of file