diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java index b6ffd740785..eb18ea405ea 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java @@ -11,6 +11,7 @@ import org.keycloak.authorization.policy.provider.PolicyProviderAdminService; import org.keycloak.authorization.policy.provider.PolicyProviderFactory; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation; /** @@ -37,28 +38,32 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory { @Override public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) { - return new PolicyProviderAdminService() { + return new PolicyProviderAdminService() { @Override - public void onCreate(Policy policy, ResourcePermissionRepresentation representation) { + public void onCreate(Policy policy, AbstractPolicyRepresentation representation) { updateResourceType(policy, representation); } @Override - public void onUpdate(Policy policy, ResourcePermissionRepresentation representation) { + public void onUpdate(Policy policy, AbstractPolicyRepresentation representation) { updateResourceType(policy, representation); } - private void updateResourceType(Policy policy, ResourcePermissionRepresentation representation) { - //TODO: remove this check once we migrate to new API + private void updateResourceType(Policy policy, AbstractPolicyRepresentation representation) { if (representation != null) { - Map config = policy.getConfig(); + //TODO: remove this check once we migrate to new API + if (ResourcePermissionRepresentation.class.equals(representation.getClass())) { + ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation); + Map config = policy.getConfig(); - config.compute("defaultResourceType", (key, value) -> { - String resourceType = representation.getResourceType(); - return resourceType != null ? representation.getResourceType() : null; - }); + config.compute("defaultResourceType", (key, value) -> { + String resourceType = resourcePermission.getResourceType(); + return resourceType != null ? resourcePermission.getResourceType() : null; + }); - policy.setConfig(config); + policy.setConfig(config); + + } } } @@ -68,7 +73,7 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory { } @Override - public Class getRepresentationType() { + public Class getRepresentationType() { return ResourcePermissionRepresentation.class; } diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java index 1c28a5fa83b..d85a73e5141 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java @@ -35,22 +35,7 @@ public class ScopePolicyProviderFactory implements PolicyProviderFactory { @Override public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) { - return new PolicyProviderAdminService() { - @Override - public void onCreate(Policy policy, ScopePermissionRepresentation representation) { - - } - - @Override - public void onUpdate(Policy policy, ScopePermissionRepresentation representation) { - - } - - @Override - public void onRemove(Policy policy) { - - } - + return new PolicyProviderAdminService() { @Override public Class getRepresentationType() { return ScopePermissionRepresentation.class; diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java index ccd5ee17620..c4e5c99ebd9 100644 --- a/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java @@ -88,7 +88,7 @@ public class AbstractPolicyRepresentation { return policies; } - public void addPolicies(String... id) { + public void addPolicy(String... id) { if (this.policies == null) { this.policies = new HashSet<>(); } diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PermissionsResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PermissionsResource.java index 6c160807132..679137bda97 100644 --- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PermissionsResource.java +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PermissionsResource.java @@ -25,4 +25,7 @@ public interface PermissionsResource { @Path("resource") ResourcePermissionsResource resource(); + + @Path("scope") + ScopePermissionsResource scope(); } diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ScopePermissionResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ScopePermissionResource.java new file mode 100644 index 00000000000..199e412ecb5 --- /dev/null +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ScopePermissionResource.java @@ -0,0 +1,75 @@ +/* + * 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.admin.client.resource; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.jboss.resteasy.annotations.cache.NoCache; +import org.keycloak.representations.idm.authorization.PolicyRepresentation; +import org.keycloak.representations.idm.authorization.ResourceRepresentation; +import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation; +import org.keycloak.representations.idm.authorization.ScopeRepresentation; + +/** + * @author Pedro Igor + */ +public interface ScopePermissionResource { + + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + ScopePermissionRepresentation toRepresentation(); + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + void update(ScopePermissionRepresentation representation); + + @DELETE + void remove(); + + @Path("/associatedPolicies") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + List associatedPolicies(); + + @Path("/dependentPolicies") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + List dependentPolicies(); + + @Path("/resources") + @GET + @Produces("application/json") + @NoCache + List resources(); + + @Path("/scopes") + @GET + @Produces("application/json") + @NoCache + List scopes(); +} diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ScopePermissionsResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ScopePermissionsResource.java new file mode 100644 index 00000000000..c92b132f10e --- /dev/null +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ScopePermissionsResource.java @@ -0,0 +1,41 @@ +/* + * 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.admin.client.resource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation; + +/** + * @author Pedro Igor + */ +public interface ScopePermissionsResource { + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + Response create(ScopePermissionRepresentation representation); + + @Path("{id}") + ScopePermissionResource findById(@PathParam("id") String id); +} diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java index ec7b6c9d440..fe6c8a759d3 100644 --- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java +++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java @@ -26,13 +26,19 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati */ public interface PolicyProviderAdminService { - void onCreate(Policy policy, R representation); + default void onCreate(Policy policy, R representation) { - void onUpdate(Policy policy, R representation); + } - void onRemove(Policy policy); + default void onUpdate(Policy policy, R representation) { - default AbstractPolicyRepresentation toRepresentation(Policy policy) { + } + + default void onRemove(Policy policy) { + + } + + default R toRepresentation(Policy policy) { return null; } 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 766e2755783..39d7380cc52 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 @@ -17,6 +17,18 @@ package org.keycloak.models.utils; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + import org.jboss.logging.Logger; import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProviderFactory; @@ -25,7 +37,6 @@ import org.keycloak.authorization.model.Resource; import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.Scope; import org.keycloak.authorization.policy.provider.PolicyProvider; -import org.keycloak.authorization.policy.provider.PolicyProviderAdminService; import org.keycloak.authorization.store.PolicyStore; import org.keycloak.authorization.store.ResourceServerStore; import org.keycloak.authorization.store.ResourceStore; @@ -105,18 +116,6 @@ import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.federated.UserFederatedStorageProvider; import org.keycloak.util.JsonSerialization; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - public class RepresentationToModel { private static Logger logger = Logger.getLogger(RepresentationToModel.class); @@ -2118,224 +2117,94 @@ public class RepresentationToModel { } PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore(); - Policy existing; + Policy model; if (representation.getId() != null) { - existing = policyStore.findById(representation.getId(), resourceServer.getId()); + model = policyStore.findById(representation.getId(), resourceServer.getId()); } else { - existing = policyStore.findByName(representation.getName(), resourceServer.getId()); + model = policyStore.findByName(representation.getName(), resourceServer.getId()); } - if (existing != null) { - existing.setName(representation.getName()); - existing.setDescription(representation.getDescription()); - existing.setDecisionStrategy(representation.getDecisionStrategy()); - existing.setLogic(representation.getLogic()); - - updatePolicy(existing, representation, authorization); - - return existing; + if (model != null) { + model.setName(representation.getName()); + model.setDescription(representation.getDescription()); + model.setDecisionStrategy(representation.getDecisionStrategy()); + model.setLogic(representation.getLogic()); + } else { + model = policyStore.create(representation.getName(), type, resourceServer); + model.setDescription(representation.getDescription()); + model.setDecisionStrategy(representation.getDecisionStrategy()); + model.setLogic(representation.getLogic()); } - Policy model = policyStore.create(representation.getName(), type, resourceServer); - - model.setDescription(representation.getDescription()); - model.setDecisionStrategy(representation.getDecisionStrategy()); - model.setLogic(representation.getLogic()); - - updatePolicy(model, representation, authorization); + updateResources(representation.getResources(), model, authorization); + updateScopes(representation.getScopes(), model, authorization); + updateAssociatedPolicies(representation.getPolicies(), model, authorization); representation.setId(model.getId()); return model; } - private static void updatePolicy(Policy policy, AbstractPolicyRepresentation representation, AuthorizationProvider authorization) { - ResourceServer resourceServer = policy.getResourceServer(); - StoreFactory storeFactory = authorization.getStoreFactory(); - Set newResources = representation.getResources(); - - if (newResources != null && !newResources.isEmpty()) { - Set associatedResources = policy.getResources(); - String newResourceId = newResources.iterator().next(); - - if (newResourceId != null) { - Resource newResource = storeFactory.getResourceStore().findById(newResourceId, resourceServer.getId()); - - if (newResource == null) { - throw new RuntimeException("Resource with id [" + newResourceId + "] does not exist"); - } - - if (!associatedResources.isEmpty()) { - Resource associatedResource = associatedResources.iterator().next(); - - if (!associatedResource.getId().equals(newResource.getId())) { - policy.removeResource(associatedResource); - } - } - - policy.addResource(newResource); - } else { - for (Resource resource : new ArrayList<>(associatedResources)) { - policy.removeResource(resource); - } - } - } else { - for (Resource associatedResource : new HashSet(policy.getResources())) { - policy.removeResource(associatedResource); - } - } - - PolicyStore policyStore = storeFactory.getPolicyStore(); - Set policies = representation.getPolicies(); - - for (String policyId : policies) { - boolean hasPolicy = false; - - for (Policy policyModel : new HashSet(policy.getAssociatedPolicies())) { - if (policyModel.getId().equals(policyId) || policyModel.getName().equals(policyId)) { - hasPolicy = true; - } - } - - - if (!hasPolicy) { - Policy associatedPolicy = policyStore.findById(policyId, resourceServer.getId()); - - if (associatedPolicy == null) { - associatedPolicy = policyStore.findByName(policyId, resourceServer.getId()); - } - - policy.addAssociatedPolicy(associatedPolicy); - } - } - - for (Policy policyModel : new HashSet(policy.getAssociatedPolicies())) { - boolean hasPolicy = false; - - for (String policyId : policies) { - if (policyModel.getId().equals(policyId) || policyModel.getName().equals(policyId)) { - hasPolicy = true; - } - } - if (!hasPolicy) { - policy.removeAssociatedPolicy(policyModel); - ; - } - } - - Set newScopes = representation.getScopes(); - - if (newScopes != null && !newScopes.isEmpty()) { - for (String scopeId : newScopes) { - boolean hasScope = false; - - for (Scope scopeModel : new HashSet(policy.getScopes())) { - if (scopeModel.getId().equals(scopeId)) { - hasScope = true; - } - } - if (!hasScope) { - Scope scope = storeFactory.getScopeStore().findById(scopeId, resourceServer.getId()); - - if (scope == null) { - storeFactory.getScopeStore().findByName(scopeId, resourceServer.getId()); - } - - policy.addScope(scope); - } - } - - for (Scope scopeModel : new HashSet(policy.getScopes())) { - boolean hasScope = false; - - for (String scopeId : newScopes) { - if (scopeModel.getId().equals(scopeId)) { - hasScope = true; - } - } - if (!hasScope) { - policy.removeScope(scopeModel); - } - } - } else { - for (Scope associatedScope : new HashSet(policy.getScopes())) { - policy.removeScope(associatedScope); - } - } - } - public static Policy toModel(PolicyRepresentation policy, ResourceServer resourceServer, AuthorizationProvider authorization) { - String type = policy.getType(); - PolicyProvider provider = authorization.getProvider(type); + Policy model = toModel(AbstractPolicyRepresentation.class.cast(policy), resourceServer, authorization); - if (provider == null) { - //TODO: temporary, remove this check on future versions as drools type is now deprecated - if ("drools".equalsIgnoreCase(type)) { - type = "rules"; - } - if (authorization.getProvider(type) == null) { - throw new RuntimeException("Unknown policy type [" + type + "]. Could not find a provider for this type."); - } - } + String resources = policy.getConfig().get("resources"); - PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore(); - Policy existing; - - if (policy.getId() != null) { - existing = policyStore.findById(policy.getId(), resourceServer.getId()); - } else { - existing = policyStore.findByName(policy.getName(), resourceServer.getId()); - } - - if (existing != null) { - existing.setName(policy.getName()); - existing.setDescription(policy.getDescription()); - existing.setConfig(policy.getConfig()); - existing.setDecisionStrategy(policy.getDecisionStrategy()); - existing.setLogic(policy.getLogic()); - - updateResources(existing, authorization); - updateAssociatedPolicies(existing, resourceServer, authorization); - updateScopes(existing, authorization); - - return existing; - } - - Policy model = policyStore.create(policy.getName(), type, resourceServer); - - model.setDescription(policy.getDescription()); - model.setDecisionStrategy(policy.getDecisionStrategy()); - model.setLogic(policy.getLogic()); - model.setConfig(policy.getConfig()); - - updateResources(model, authorization); - updateAssociatedPolicies(model, resourceServer, authorization); - updateScopes(model, authorization); - - policy.setId(model.getId()); - - return model; - } - - private static void updateScopes(Policy policy, AuthorizationProvider authorization) { - String scopes = policy.getConfig().get("scopes"); - if (scopes != null) { - String[] scopeIds; + if (resources != null) { + Set resourceIds; try { - scopeIds = JsonSerialization.readValue(scopes, String[].class); + resourceIds = JsonSerialization.readValue(resources, Set.class); } catch (IOException e) { throw new RuntimeException(e); } + updateResources(resourceIds, model, authorization); + } + + String scopes = policy.getConfig().get("scopes"); + + if (scopes != null) { + Set scopeIds; + + try { + scopeIds = JsonSerialization.readValue(scopes, Set.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + + updateScopes(scopeIds, model, authorization); + } + + String policies = policy.getConfig().get("applyPolicies"); + + if (policies != null) { + Set policyIds; + + try { + policyIds = JsonSerialization.readValue(policies, Set.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + + updateAssociatedPolicies(policyIds, model, authorization); + } + + model.setConfig(policy.getConfig()); + + return model; + } + + private static void updateScopes(Set scopeIds, Policy policy, AuthorizationProvider authorization) { + if (scopeIds != null) { StoreFactory storeFactory = authorization.getStoreFactory(); for (String scopeId : scopeIds) { boolean hasScope = false; for (Scope scopeModel : new HashSet(policy.getScopes())) { - if (scopeModel.getId().equals(scopeId)) { + if (scopeModel.getId().equals(scopeId) || scopeModel.getName().equals(scopeId)) { hasScope = true; } } @@ -2344,7 +2213,10 @@ public class RepresentationToModel { Scope scope = storeFactory.getScopeStore().findById(scopeId, resourceServer.getId()); if (scope == null) { - storeFactory.getScopeStore().findByName(scopeId, resourceServer.getId()); + scope = storeFactory.getScopeStore().findByName(scopeId, resourceServer.getId()); + if (scope == null) { + throw new RuntimeException("Scope with id or name [" + scopeId + "] does not exist"); + } } policy.addScope(scope); @@ -2355,7 +2227,7 @@ public class RepresentationToModel { boolean hasScope = false; for (String scopeId : scopeIds) { - if (scopeModel.getId().equals(scopeId)) { + if (scopeModel.getId().equals(scopeId) || scopeModel.getName().equals(scopeId)) { hasScope = true; } } @@ -2368,18 +2240,10 @@ public class RepresentationToModel { } } - private static void updateAssociatedPolicies(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization) { - String policies = policy.getConfig().get("applyPolicies"); - - if (policies != null) { - String[] policyIds; - - try { - policyIds = JsonSerialization.readValue(policies, String[].class); - } catch (IOException e) { - throw new RuntimeException(e); - } + private static void updateAssociatedPolicies(Set policyIds, Policy policy, AuthorizationProvider authorization) { + ResourceServer resourceServer = policy.getResourceServer(); + if (policyIds != null) { StoreFactory storeFactory = authorization.getStoreFactory(); PolicyStore policyStore = storeFactory.getPolicyStore(); @@ -2392,12 +2256,14 @@ public class RepresentationToModel { } } - if (!hasPolicy) { Policy associatedPolicy = policyStore.findById(policyId, resourceServer.getId()); if (associatedPolicy == null) { associatedPolicy = policyStore.findByName(policyId, resourceServer.getId()); + if (associatedPolicy == null) { + throw new RuntimeException("Policy with id or name [" + policyId + "] does not exist"); + } } policy.addAssociatedPolicy(associatedPolicy); @@ -2422,23 +2288,14 @@ public class RepresentationToModel { } } - private static void updateResources(Policy policy, AuthorizationProvider authorization) { - String resources = policy.getConfig().get("resources"); - if (resources != null) { - String[] resourceIds; - - try { - resourceIds = JsonSerialization.readValue(resources, String[].class); - } catch (IOException e) { - throw new RuntimeException(e); - } - + private static void updateResources(Set resourceIds, Policy policy, AuthorizationProvider authorization) { + if (resourceIds != null) { StoreFactory storeFactory = authorization.getStoreFactory(); for (String resourceId : resourceIds) { boolean hasResource = false; for (Resource resourceModel : new HashSet(policy.getResources())) { - if (resourceModel.getId().equals(resourceId)) { + if (resourceModel.getId().equals(resourceId) || resourceModel.getName().equals(resourceId)) { hasResource = true; } } @@ -2446,7 +2303,10 @@ public class RepresentationToModel { Resource resource = storeFactory.getResourceStore().findById(resourceId, policy.getResourceServer().getId()); if (resource == null) { - throw new RuntimeException("Resource [" + resourceId + "] not found."); + resource = storeFactory.getResourceStore().findByName(resourceId, policy.getResourceServer().getId()); + if (resource == null) { + throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist"); + } } policy.addResource(resource); @@ -2457,7 +2317,7 @@ public class RepresentationToModel { boolean hasResource = false; for (String resourceId : resourceIds) { - if (resourceModel.getId().equals(resourceId)) { + if (resourceModel.getId().equals(resourceId) || resourceModel.getName().equals(resourceId)) { hasResource = true; } } 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 faafe11875a..fe45dfab0e8 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyResourceService.java @@ -16,8 +16,6 @@ */ package org.keycloak.authorization.admin; -import static org.keycloak.models.utils.RepresentationToModel.toModel; - import java.io.IOException; import java.util.List; import java.util.stream.Collectors; @@ -40,6 +38,8 @@ import org.keycloak.authorization.policy.provider.PolicyProviderFactory; import org.keycloak.authorization.store.PolicyStore; import org.keycloak.authorization.store.StoreFactory; import org.keycloak.models.utils.ModelToRepresentation; +import org.keycloak.models.utils.RepresentationToModel; +import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation; @@ -70,37 +70,31 @@ public class PolicyResourceService { public Response update(String payload) { this.auth.requireManage(); + AbstractPolicyRepresentation representation = doCreateRepresentation(payload); + if (policy == null) { return Response.status(Status.NOT_FOUND).build(); } - doUpdate(policy, payload); - - return Response.status(Status.CREATED).build(); - } - - protected void doUpdate(Policy policy, String payload) { - PolicyRepresentation representation; - - try { - representation = JsonSerialization.readValue(payload, PolicyRepresentation.class); - } catch (IOException cause) { - throw new RuntimeException("Failed to deserialize representation", cause); - } - representation.setId(policy.getId()); - policy = toModel(representation, resourceServer, authorization); + Policy updated = toModel(representation); - PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType()); + PolicyProviderAdminService resource = getPolicyProviderAdminResource(updated.getType()); if (resource != null) { try { - resource.onUpdate(policy, null); + resource.onUpdate(updated, representation); } catch (Exception e) { throw new RuntimeException(e); } } + + return Response.status(Status.CREATED).build(); + } + + protected Policy toModel(AbstractPolicyRepresentation representation) { + return RepresentationToModel.toModel(PolicyRepresentation.class.cast(representation), resourceServer, authorization); } @DELETE @@ -241,6 +235,18 @@ public class PolicyResourceService { }).collect(Collectors.toList())).build(); } + protected AbstractPolicyRepresentation doCreateRepresentation(String payload) { + PolicyRepresentation representation; + + try { + representation = JsonSerialization.readValue(payload, PolicyRepresentation.class); + } catch (IOException cause) { + throw new RuntimeException("Failed to deserialize representation", cause); + } + + return representation; + } + protected PolicyProviderAdminService getPolicyProviderAdminResource(String policyType) { PolicyProviderFactory providerFactory = authorization.getProviderFactory(policyType); @@ -250,4 +256,8 @@ public class PolicyResourceService { return null; } + + protected Policy getPolicy() { + return policy; + } } diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java index dc1040019b1..026d7fba891 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyTypeResourceService.java @@ -16,14 +16,13 @@ */ package org.keycloak.authorization.admin; -import static org.keycloak.models.utils.RepresentationToModel.toModel; - import java.io.IOException; import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.policy.provider.PolicyProviderAdminService; +import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; import org.keycloak.services.resources.admin.RealmAuth; import org.keycloak.util.JsonSerialization; @@ -38,22 +37,9 @@ public class PolicyTypeResourceService extends PolicyResourceService { } @Override - protected void doUpdate(Policy policy, String payload) { - String type = policy.getType(); - PolicyProviderAdminService provider = getPolicyProviderAdminResource(type); - AbstractPolicyRepresentation representation = toRepresentation(type, payload, provider); - - policy = toModel(representation, policy.getResourceServer(), authorization); - - try { - provider.onUpdate(policy, representation); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private AbstractPolicyRepresentation toRepresentation(String type, String payload, PolicyProviderAdminService provider) { - Class representationType = provider.getRepresentationType(); + protected AbstractPolicyRepresentation doCreateRepresentation(String payload) { + String type = getPolicy().getType(); + Class representationType = getPolicyProviderAdminResource(type).getRepresentationType(); if (representationType == null) { throw new RuntimeException("Policy provider for type [" + type + "] returned a null representation type."); @@ -66,22 +52,29 @@ public class PolicyTypeResourceService extends PolicyResourceService { } catch (IOException e) { throw new RuntimeException("Failed to deserialize JSON using policy provider for type [" + type + "].", e); } + + representation.setType(type); + return representation; } + @Override + protected Policy toModel(AbstractPolicyRepresentation representation) { + return RepresentationToModel.toModel(representation, resourceServer, authorization); + } + @Override protected Object toRepresentation(Policy policy) { PolicyProviderAdminService provider = getPolicyProviderAdminResource(policy.getType()); - return toRepresentation(policy, provider.toRepresentation(policy)); - } + AbstractPolicyRepresentation representation = provider.toRepresentation(policy); - private AbstractPolicyRepresentation toRepresentation(Policy policy, AbstractPolicyRepresentation representation) { representation.setId(policy.getId()); representation.setName(policy.getName()); representation.setDescription(policy.getDescription()); representation.setType(policy.getType()); representation.setDecisionStrategy(policy.getDecisionStrategy()); representation.setLogic(policy.getLogic()); + return representation; } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractPermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractPermissionManagementTest.java new file mode 100644 index 00000000000..7dc58438402 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractPermissionManagementTest.java @@ -0,0 +1,170 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import org.junit.Before; +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.admin.client.resource.ClientsResource; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.authorization.client.AuthzClient; +import org.keycloak.authorization.client.Configuration; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation; +import org.keycloak.representations.idm.authorization.PolicyRepresentation; +import org.keycloak.representations.idm.authorization.ResourceRepresentation; +import org.keycloak.representations.idm.authorization.ScopeRepresentation; +import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.util.AdminClientUtil; +import org.keycloak.testsuite.util.ClientBuilder; +import org.keycloak.testsuite.util.RealmBuilder; +import org.keycloak.testsuite.util.UserBuilder; +import org.keycloak.util.JsonSerialization; + +/** + * @author Pedro Igor + */ +public abstract class AbstractPermissionManagementTest extends AbstractKeycloakTest { + @Override + public void addTestRealms(List testRealms) { + testRealms.add(RealmBuilder.create().name("authz-test") + .user(UserBuilder.create().username("marta").password("password")) + .user(UserBuilder.create().username("kolo").password("password")) + .client(ClientBuilder.create().clientId("resource-server-test") + .secret("secret") + .authorizationServicesEnabled(true) + .redirectUris("http://localhost/resource-server-test") + .defaultRoles("uma_protection") + .directAccessGrants()) + .build()); + } + + @Before + public void configureAuthorization() throws Exception { + createResourcesAndScopes(); + RealmResource realm = getRealm(); + createPolicies(realm, getClient(realm)); + } + + protected void assertRepresentation(AbstractPolicyRepresentation expected, AbstractPolicyRepresentation actual, + Supplier> resources, + Supplier> scopes, + Supplier> policies) { + assertNotNull(actual); + assertNotNull(actual.getId()); + + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getDescription(), actual.getDescription()); + assertEquals(expected.getDecisionStrategy(), actual.getDecisionStrategy()); + assertEquals(expected.getLogic(), actual.getLogic()); + assertNull(actual.getResources()); + assertNull(actual.getPolicies()); + assertNull(actual.getScopes()); + + assertEquals(expected.getPolicies().size(), policies.get().stream().map(representation1 -> representation1.getName()).filter(policyName -> expected.getPolicies().contains(policyName)).count()); + + if (expected.getResources() != null) { + assertEquals(expected.getResources().size(), resources.get().stream().map(representation1 -> representation1.getName()).filter(resourceName -> expected.getResources().contains(resourceName)).count()); + } else { + assertTrue(resources.get().isEmpty()); + } + + if (expected.getScopes() != null) { + assertEquals(expected.getScopes().size(), scopes.get().stream().map(representation1 -> representation1.getName()).filter(scopeName -> expected.getScopes().contains(scopeName)).count()); + } else { + assertTrue(scopes.get().isEmpty()); + } + + expected.setId(actual.getId()); + } + + private void createResourcesAndScopes() throws IOException { + Set scopes = new HashSet<>(); + + scopes.add(new ScopeRepresentation("read")); + scopes.add(new ScopeRepresentation("write")); + scopes.add(new ScopeRepresentation("execute")); + + List resources = new ArrayList<>(); + + resources.add(new ResourceRepresentation("Resource A", scopes)); + resources.add(new ResourceRepresentation("Resource B", scopes)); + resources.add(new ResourceRepresentation("Resource C", scopes)); + + resources.forEach(resource -> getClient().authorization().resources().create(resource)); + } + + private void createPolicies(RealmResource realm, ClientResource client) throws IOException { + createUserPolicy("Only Marta Policy", realm, client, "marta"); + createUserPolicy("Only Kolo Policy", realm, client, "kolo"); + } + + private void createUserPolicy(String name, RealmResource realm, ClientResource client, String username) throws IOException { + String userId = realm.users().search(username).stream().map(representation -> representation.getId()).findFirst().orElseThrow(() -> new RuntimeException("Expected user [userId]")); + + PolicyRepresentation representation = new PolicyRepresentation(); + + representation.setName(name); + representation.setType("user"); + + Map config = new HashMap<>(); + + config.put("users", JsonSerialization.writeValueAsString(new String[]{userId})); + + representation.setConfig(config); + + client.authorization().policies().create(representation); + } + + protected ClientResource getClient() { + return getClient(getRealm()); + } + + protected ClientResource getClient(RealmResource realm) { + ClientsResource clients = realm.clients(); + return clients.findByClientId("resource-server-test").stream().map(representation -> clients.get(representation.getId())).findFirst().orElseThrow(() -> new RuntimeException("Expected client [resource-server-test]")); + } + + protected RealmResource getRealm() { + try { + return AdminClientUtil.createAdminClient().realm("authz-test"); + } catch (Exception cause) { + throw new RuntimeException("Failed to create admin client", cause); + } + } + + private AuthzClient getAuthzClient() { + try { + return AuthzClient.create(JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/default-keycloak.json"), Configuration.class)); + } catch (IOException cause) { + throw new RuntimeException("Failed to create authz client", cause); + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java index b1572da723c..1deed221a00 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourcePermissionManagementTest.java @@ -17,93 +17,44 @@ package org.keycloak.testsuite.admin.client.authorization; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.IntFunction; -import java.util.stream.Collectors; +import java.util.Collections; import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Response; -import org.junit.Before; import org.junit.Test; import org.keycloak.admin.client.resource.AuthorizationResource; -import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.admin.client.resource.ClientsResource; -import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.ResourcePermissionResource; import org.keycloak.admin.client.resource.ResourcePermissionsResource; -import org.keycloak.authorization.client.AuthzClient; -import org.keycloak.authorization.client.Configuration; -import org.keycloak.authorization.client.representation.ResourceRepresentation; -import org.keycloak.authorization.client.representation.ScopeRepresentation; -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.PolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation; -import org.keycloak.testsuite.AbstractKeycloakTest; -import org.keycloak.testsuite.util.AdminClientUtil; -import org.keycloak.testsuite.util.ClientBuilder; -import org.keycloak.testsuite.util.RealmBuilder; -import org.keycloak.testsuite.util.UserBuilder; -import org.keycloak.util.JsonSerialization; /** * @author Pedro Igor */ -public class ResourcePermissionManagementTest extends AbstractKeycloakTest { - - @Override - public void addTestRealms(List testRealms) { - testRealms.add(RealmBuilder.create().name("authz-test") - .user(UserBuilder.create().username("marta").password("password")) - .user(UserBuilder.create().username("kolo").password("password")) - .client(ClientBuilder.create().clientId("resource-server-test") - .secret("secret") - .authorizationServicesEnabled(true) - .redirectUris("http://localhost/resource-server-test") - .defaultRoles("uma_protection") - .directAccessGrants()) - .build()); - } - - @Before - public void configureAuthorization() throws Exception { - createResourcesAndScopes(); - RealmResource realm = getRealm(); - createPolicies(realm, getClient(realm)); - } +public class ResourcePermissionManagementTest extends AbstractPermissionManagementTest { @Test public void testCreateResourcePermission() { - AuthorizationResource authorization = getClient(getRealm()).authorization(); + AuthorizationResource authorization = getClient().authorization(); ResourcePermissionRepresentation representation = new ResourcePermissionRepresentation(); representation.setName("Resource A Permission"); representation.setDescription("description"); representation.setDecisionStrategy(DecisionStrategy.CONSENSUS); representation.setLogic(Logic.NEGATIVE); - representation.addResource(getResourceId("Resource A", authorization)); - representation.addPolicies(getPolicyIds(Arrays.asList("Only Marta Policy", "Only Kolo Policy"), authorization).stream().toArray((IntFunction) value -> new String[value])); + representation.addResource("Resource A"); + representation.addPolicy("Only Marta Policy", "Only Kolo Policy"); assertCreated(authorization, representation); } @Test public void testCreateResourceType() { - AuthorizationResource authorization = getClient(getRealm()).authorization(); + AuthorizationResource authorization = getClient().authorization(); ResourcePermissionRepresentation representation = new ResourcePermissionRepresentation(); representation.setName("Resource A Type Permission"); @@ -111,19 +62,56 @@ public class ResourcePermissionManagementTest extends AbstractKeycloakTest { representation.setDecisionStrategy(DecisionStrategy.CONSENSUS); representation.setLogic(Logic.NEGATIVE); representation.setResourceType("test-resource"); - representation.addPolicies(getPolicyIds(Arrays.asList("Only Marta Policy"), authorization).stream().toArray((IntFunction) value -> new String[value])); + representation.addPolicy("Only Marta Policy"); assertCreated(authorization, representation); } + @Test + public void testUpdate() { + AuthorizationResource authorization = getClient().authorization(); + ResourcePermissionRepresentation representation = new ResourcePermissionRepresentation(); + + representation.setName("Update Test Resource Permission"); + representation.setDescription("description"); + representation.setDecisionStrategy(DecisionStrategy.CONSENSUS); + representation.setLogic(Logic.NEGATIVE); + representation.addResource("Resource A"); + representation.addPolicy("Only Marta Policy", "Only Kolo Policy"); + + assertCreated(authorization, representation); + + representation.setName("changed"); + representation.setDescription("changed"); + representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE); + representation.setLogic(Logic.POSITIVE); + representation.getResources().remove("Resource A"); + representation.addResource("Resource B"); + representation.getPolicies().remove("Only Marta Policy"); + + ResourcePermissionsResource permissions = authorization.permissions().resource(); + ResourcePermissionResource permission = permissions.findById(representation.getId()); + + permission.update(representation); + + assertRepresentation(representation, permission); + + representation.getResources().clear(); + representation.setResourceType("changed"); + + permission.update(representation); + + assertRepresentation(representation, permission); + } + @Test public void testDelete() { - AuthorizationResource authorization = getClient(getRealm()).authorization(); + AuthorizationResource authorization = getClient().authorization(); ResourcePermissionRepresentation representation = new ResourcePermissionRepresentation(); representation.setName("Test Delete Permission"); representation.setResourceType("test-resource"); - representation.addPolicies(getPolicyIds(Arrays.asList("Only Marta Policy"), authorization).stream().toArray((IntFunction) value -> new String[value])); + representation.addPolicy("Only Marta Policy"); ResourcePermissionsResource permissions = authorization.permissions().resource(); Response response = permissions.create(representation); @@ -143,12 +131,12 @@ public class ResourcePermissionManagementTest extends AbstractKeycloakTest { @Test public void failCreateWithSameName() { - AuthorizationResource authorization = getClient(getRealm()).authorization(); + AuthorizationResource authorization = getClient().authorization(); ResourcePermissionRepresentation permission1 = new ResourcePermissionRepresentation(); permission1.setName("Conflicting Name Permission"); permission1.setResourceType("test-resource"); - permission1.addPolicies(getPolicyIds(Arrays.asList("Only Marta Policy"), authorization).stream().toArray((IntFunction) value -> new String[value])); + permission1.addPolicy("Only Marta Policy"); ResourcePermissionsResource permissions = authorization.permissions().resource(); @@ -167,97 +155,11 @@ public class ResourcePermissionManagementTest extends AbstractKeycloakTest { ResourcePermissionsResource permissions = authorization.permissions().resource(); Response response = permissions.create(representation); ResourcePermissionRepresentation created = response.readEntity(ResourcePermissionRepresentation.class); - - assertNotNull(created); - assertNotNull(created.getId()); - ResourcePermissionResource permission = permissions.findById(created.getId()); - ResourcePermissionRepresentation found = permission.toRepresentation(); - - assertNotNull(found); - assertEquals(created.getId(), found.getId()); - assertEquals(created.getName(), found.getName()); - assertEquals(created.getDescription(), found.getDescription()); - assertEquals(created.getDecisionStrategy(), found.getDecisionStrategy()); - assertEquals(created.getLogic(), found.getLogic()); - assertEquals(created.getResourceType(), found.getResourceType()); - assertNull(found.getResources()); - assertNull(found.getPolicies()); - - assertEquals(representation.getPolicies().size(), permission.associatedPolicies().stream().map(representation1 -> representation1.getId()).filter(policyId -> representation.getPolicies().contains(policyId)).count()); - - if (representation.getResources() != null) { - assertEquals(representation.getResources().size(), permission.resources().stream().map(representation1 -> representation1.getId()).filter(resourceId -> representation.getResources().contains(resourceId)).count()); - } else { - assertTrue(permission.resources().isEmpty()); - } + assertRepresentation(representation, permission); } - private void createResourcesAndScopes() throws IOException { - AuthzClient authzClient = getAuthzClient(); - Set scopes = new HashSet<>(); - - scopes.add(new ScopeRepresentation("read")); - scopes.add(new ScopeRepresentation("write")); - scopes.add(new ScopeRepresentation("execute")); - - List resources = new ArrayList<>(); - - resources.add(new ResourceRepresentation("Resource A", scopes)); - resources.add(new ResourceRepresentation("Resource B", scopes)); - resources.add(new ResourceRepresentation("Resource C", scopes)); - - resources.forEach(resource -> authzClient.protection().resource().create(resource)); - } - - private void createPolicies(RealmResource realm, ClientResource client) throws IOException { - createUserPolicy("Only Marta Policy", realm, client, "marta"); - createUserPolicy("Only Kolo Policy", realm, client, "kolo"); - } - - private void createUserPolicy(String name, RealmResource realm, ClientResource client, String username) throws IOException { - String userId = realm.users().search(username).stream().map(representation -> representation.getId()).findFirst().orElseThrow(() -> new RuntimeException("Expected user [userId]")); - - PolicyRepresentation representation = new PolicyRepresentation(); - - representation.setName(name); - representation.setType("user"); - - Map config = new HashMap<>(); - - config.put("users", JsonSerialization.writeValueAsString(new String[] {userId})); - - representation.setConfig(config); - - client.authorization().policies().create(representation); - } - - private ClientResource getClient(RealmResource realm) { - ClientsResource clients = realm.clients(); - return clients.findByClientId("resource-server-test").stream().map(representation -> clients.get(representation.getId())).findFirst().orElseThrow(() -> new RuntimeException("Expected client [resource-server-test]")); - } - - private RealmResource getRealm() { - try { - return AdminClientUtil.createAdminClient().realm("authz-test"); - } catch (Exception cause) { - throw new RuntimeException("Failed to create admin client", cause); - } - } - - private String getResourceId(String resourceName, AuthorizationResource authorization) { - return authorization.resources().findByName(resourceName).stream().map(representation -> representation.getId()).findFirst().orElseThrow(() -> new RuntimeException("Expected user [userId]")); - } - - private List getPolicyIds(List policies, AuthorizationResource authorization) { - return policies.stream().map(policyName -> authorization.policies().findByName(policyName).getId()).collect(Collectors.toList()); - } - - private AuthzClient getAuthzClient() { - try { - return AuthzClient.create(JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/default-keycloak.json"), Configuration.class)); - } catch (IOException cause) { - throw new RuntimeException("Failed to create authz client", cause); - } + private void assertRepresentation(ResourcePermissionRepresentation representation, ResourcePermissionResource permission) { + assertRepresentation(representation, permission.toRepresentation(), () -> permission.resources(), () -> Collections.emptyList(), () -> permission.associatedPolicies()); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java new file mode 100644 index 00000000000..8759a0a9f2a --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopePermissionManagementTest.java @@ -0,0 +1,161 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.Collections; + +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.Response; + +import org.junit.Test; +import org.keycloak.admin.client.resource.AuthorizationResource; +import org.keycloak.admin.client.resource.ScopePermissionResource; +import org.keycloak.admin.client.resource.ScopePermissionsResource; +import org.keycloak.representations.idm.authorization.DecisionStrategy; +import org.keycloak.representations.idm.authorization.Logic; +import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation; + +/** + * @author Pedro Igor + */ +public class ScopePermissionManagementTest extends AbstractPermissionManagementTest { + + @Test + public void testCreateResourceScopePermission() { + AuthorizationResource authorization = getClient().authorization(); + ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); + + representation.setName("Resource A Scope Permission"); + representation.setDescription("description"); + representation.setDecisionStrategy(DecisionStrategy.CONSENSUS); + representation.setLogic(Logic.NEGATIVE); + representation.addResource("Resource A"); + representation.addScopes("read", "execute"); + representation.addPolicy("Only Marta Policy", "Only Kolo Policy"); + + assertCreated(authorization, representation); + } + + @Test + public void testCreateScopePermission() { + AuthorizationResource authorization = getClient().authorization(); + ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); + + representation.setName("Read Permission"); + representation.setDescription("description"); + representation.setDecisionStrategy(DecisionStrategy.CONSENSUS); + representation.setLogic(Logic.NEGATIVE); + representation.addScopes("read", "write"); + representation.addPolicy("Only Marta Policy"); + + assertCreated(authorization, representation); + } + + @Test + public void testUpdate() { + AuthorizationResource authorization = getClient().authorization(); + ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); + + representation.setName("Update Test Scope Permission"); + representation.setDescription("description"); + representation.setDecisionStrategy(DecisionStrategy.CONSENSUS); + representation.setLogic(Logic.NEGATIVE); + representation.addResource("Resource A"); + representation.addScopes("read", "execute"); + representation.addPolicy("Only Marta Policy", "Only Kolo Policy"); + + assertCreated(authorization, representation); + + representation.setName("changed"); + representation.setDescription("changed"); + representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE); + representation.setLogic(Logic.POSITIVE); + representation.getResources().remove("Resource A"); + representation.addResource("Resource B"); + representation.getScopes().remove("execute"); + representation.getPolicies().remove("Only Marta Policy"); + + ScopePermissionsResource permissions = authorization.permissions().scope(); + ScopePermissionResource permission = permissions.findById(representation.getId()); + + permission.update(representation); + + assertRepresentation(representation, permission); + } + + @Test + public void testDelete() { + AuthorizationResource authorization = getClient().authorization(); + ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); + + representation.setName("Test Delete Permission"); + representation.addScopes("execute"); + representation.addPolicy("Only Marta Policy"); + + assertCreated(authorization, representation); + + ScopePermissionsResource permissions = authorization.permissions().scope(); + + permissions.findById(representation.getId()).remove(); + + ScopePermissionResource removed = permissions.findById(representation.getId()); + + try { + removed.toRepresentation(); + fail("Permission not removed"); + } catch (NotFoundException ignore) { + + } + } + + @Test + public void failCreateWithSameName() { + AuthorizationResource authorization = getClient().authorization(); + ScopePermissionRepresentation permission1 = new ScopePermissionRepresentation(); + + permission1.setName("Conflicting Name Permission"); + permission1.addScopes("read"); + permission1.addPolicy("Only Marta Policy"); + + ScopePermissionsResource permissions = authorization.permissions().scope(); + + permissions.create(permission1); + + ScopePermissionRepresentation permission2 = new ScopePermissionRepresentation(); + + permission2.setName(permission1.getName()); + + Response response = permissions.create(permission2); + + assertEquals(Response.Status.CONFLICT.getStatusCode(), response.getStatus()); + } + + private void assertCreated(AuthorizationResource authorization, ScopePermissionRepresentation representation) { + ScopePermissionsResource permissions = authorization.permissions().scope(); + Response response = permissions.create(representation); + ScopePermissionRepresentation created = response.readEntity(ScopePermissionRepresentation.class); + ScopePermissionResource permission = permissions.findById(created.getId()); + assertRepresentation(representation, permission); + } + + private void assertRepresentation(ScopePermissionRepresentation representation, ScopePermissionResource permission) { + assertRepresentation(representation, permission.toRepresentation(), () -> permission.resources(), () -> permission.scopes(), () -> permission.associatedPolicies()); + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java index 1b0b50bb1db..576a472fc6b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java @@ -29,7 +29,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; @@ -48,6 +47,8 @@ import org.keycloak.representations.AccessToken; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.authorization.Permission; import org.keycloak.representations.idm.authorization.PolicyRepresentation; +import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation; +import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.util.AdminClientUtil; import org.keycloak.testsuite.util.ClientBuilder; @@ -193,61 +194,29 @@ public class ConflictingScopePermissionTest extends AbstractKeycloakTest { } private void createResourcePermission(String name, String resourceName, List policies, ClientResource client) throws IOException { - AuthorizationResource authorization = client.authorization(); - String resourceId = getResourceId(resourceName, authorization); - List policyIds = getPolicyIds(policies, authorization); - - PolicyRepresentation representation = new PolicyRepresentation(); + ResourcePermissionRepresentation representation = new ResourcePermissionRepresentation(); representation.setName(name); - representation.setType("resource"); + representation.addResource(resourceName); + representation.addPolicy(policies.toArray(new String[policies.size()])); - Map config = new HashMap<>(); - - config.put("resources", JsonSerialization.writeValueAsString(new String[] {resourceId})); - config.put("applyPolicies", JsonSerialization.writeValueAsString(policyIds)); - - representation.setConfig(config); - - authorization.policies().create(representation); - } - - private String getResourceId(String resourceName, AuthorizationResource authorization) { - return authorization.resources().findByName(resourceName).stream().map(representation -> representation.getId()).findFirst().orElseThrow(() -> new RuntimeException("Expected user [userId]")); + client.authorization().permissions().resource().create(representation); } private void createScopePermission(String name, String resourceName, List scopes, List policies, ClientResource client) throws IOException { AuthorizationResource authorization = client.authorization(); - String resourceId = null; - - if (resourceName != null) { - resourceId = getResourceId(resourceName, authorization); - } - - List scopeIds = scopes.stream().map(scopeName -> authorization.scopes().findByName(scopeName).getId()).collect(Collectors.toList()); - List policyIds = getPolicyIds(policies, authorization); - - PolicyRepresentation representation = new PolicyRepresentation(); + ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); representation.setName(name); - representation.setType("resource"); - Map config = new HashMap<>(); - - if (resourceId != null) { - config.put("resources", JsonSerialization.writeValueAsString(new String[]{resourceId})); + if (resourceName != null) { + representation.addResource(resourceName); } - config.put("scopes", JsonSerialization.writeValueAsString(scopeIds)); - config.put("applyPolicies", JsonSerialization.writeValueAsString(policyIds)); + representation.addScopes(scopes.toArray(new String[scopes.size()])); + representation.addPolicy(scopes.toArray(new String[policies.size()])); - representation.setConfig(config); - - authorization.policies().create(representation); - } - - private List getPolicyIds(List policies, AuthorizationResource authorization) { - return policies.stream().map(policyName -> authorization.policies().findByName(policyName).getId()).collect(Collectors.toList()); + authorization.permissions().scope().create(representation); } private AuthzClient getAuthzClient() {