KEYCLOAK-13066 Include resourceType in ScopePermissionRepresentation
This commit is contained in:
parent
82d3251ab4
commit
666832d1be
5 changed files with 199 additions and 33 deletions
|
@ -79,19 +79,14 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory<Reso
|
|||
|
||||
private void updateResourceType(Policy policy, ResourcePermissionRepresentation representation) {
|
||||
if (representation != null) {
|
||||
//TODO: remove this check once we migrate to new API
|
||||
if (ResourcePermissionRepresentation.class.equals(representation.getClass())) {
|
||||
ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation);
|
||||
Map<String, String> config = new HashMap(policy.getConfig());
|
||||
|
||||
config.compute("defaultResourceType", (key, value) -> {
|
||||
String resourceType = resourcePermission.getResourceType();
|
||||
return resourceType != null ? resourcePermission.getResourceType() : null;
|
||||
String resourceType = representation.getResourceType();
|
||||
return resourceType != null ? representation.getResourceType() : null;
|
||||
});
|
||||
|
||||
policy.setConfig(config);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
|
@ -59,7 +62,32 @@ public class ScopePolicyProviderFactory implements PolicyProviderFactory<ScopePe
|
|||
|
||||
@Override
|
||||
public ScopePermissionRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
|
||||
return new ScopePermissionRepresentation();
|
||||
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||
representation.setResourceType(policy.getConfig().get("defaultResourceType"));
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, ScopePermissionRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateResourceType(policy, representation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, ScopePermissionRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateResourceType(policy, representation);
|
||||
}
|
||||
|
||||
private void updateResourceType(Policy policy, ScopePermissionRepresentation representation) {
|
||||
if (representation != null) {
|
||||
Map<String, String> config = new HashMap(policy.getConfig());
|
||||
|
||||
config.compute("defaultResourceType", (key, value) -> {
|
||||
String resourceType = representation.getResourceType();
|
||||
return resourceType != null ? representation.getResourceType() : null;
|
||||
});
|
||||
|
||||
policy.setConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,8 +21,18 @@ package org.keycloak.representations.idm.authorization;
|
|||
*/
|
||||
public class ScopePermissionRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
private String resourceType;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "scope";
|
||||
}
|
||||
|
||||
public void setResourceType(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,7 @@
|
|||
|
||||
package org.keycloak.authorization.jpa.entities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
|
@ -59,7 +56,7 @@ import org.keycloak.representations.idm.authorization.Logic;
|
|||
@NamedQuery(name="findPolicyIdByResource", query="select p from PolicyEntity p inner join p.resources r inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
|
||||
@NamedQuery(name="findPolicyIdByScope", query="select pe from PolicyEntity pe inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id))"),
|
||||
@NamedQuery(name="findPolicyIdByResourceScope", query="select pe from PolicyEntity pe inner join pe.resources r inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds) and p.id = pe.id)) and exists (select p.id from ResourceEntity r inner join r.policies p where r.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and r.id in (:resourceId)))"),
|
||||
@NamedQuery(name="findPolicyIdByNullResourceScope", query="select pe from PolicyEntity pe inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and s.id in (:scopeIds))) and pe.resources is empty"),
|
||||
@NamedQuery(name="findPolicyIdByNullResourceScope", query="select pe from PolicyEntity pe left join fetch pe.config c inner join pe.scopes s inner join fetch pe.associatedPolicies a where pe.resourceServer.id = :serverId and exists (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.id = pe.id and p.type = 'scope' and s.id in (:scopeIds))) and pe.resources is empty and not exists (select pec from pe.config pec where KEY(pec) = 'defaultResourceType')"),
|
||||
@NamedQuery(name="findPolicyIdByType", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"),
|
||||
@NamedQuery(name="findPolicyIdByResourceType", query="select p from PolicyEntity p inner join p.config c inner join fetch p.associatedPolicies a where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"),
|
||||
@NamedQuery(name="findPolicyIdByDependentPolices", query="select p.id from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)"),
|
||||
|
|
|
@ -780,7 +780,7 @@ public class EntitlementAPITest extends AbstractAuthzTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testObtainAllEntitlementsForResource() throws Exception {
|
||||
public void testObtainAllEntitlementsForResourceWithResourcePermission() throws Exception {
|
||||
ClientResource client = getClient(getRealm(), RESOURCE_SERVER_TEST);
|
||||
AuthorizationResource authorization = client.authorization();
|
||||
|
||||
|
@ -849,6 +849,11 @@ public class EntitlementAPITest extends AbstractAuthzTest {
|
|||
|
||||
request.addPermission(resource.getId(), "scope:view", "scope:update", "scope:delete");
|
||||
|
||||
response = authzClient.authorization(accessToken).authorize(request);
|
||||
assertNotNull(response.getToken());
|
||||
permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
|
||||
assertEquals(1, permissions.size());
|
||||
|
||||
for (Permission grantedPermission : permissions) {
|
||||
assertEquals(resource.getId(), grantedPermission.getResourceId());
|
||||
assertEquals(2, grantedPermission.getScopes().size());
|
||||
|
@ -856,6 +861,87 @@ public class EntitlementAPITest extends AbstractAuthzTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObtainAllEntitlementsForResourceWithScopePermission() throws Exception {
|
||||
ClientResource client = getClient(getRealm(), RESOURCE_SERVER_TEST);
|
||||
AuthorizationResource authorization = client.authorization();
|
||||
|
||||
JSPolicyRepresentation policy = new JSPolicyRepresentation();
|
||||
|
||||
policy.setName(KeycloakModelUtils.generateId());
|
||||
policy.setCode("$evaluation.grant();");
|
||||
|
||||
authorization.policies().js().create(policy).close();
|
||||
|
||||
ResourceRepresentation resourceWithoutType = new ResourceRepresentation();
|
||||
|
||||
resourceWithoutType.setName(KeycloakModelUtils.generateId());
|
||||
resourceWithoutType.addScope("scope:view", "scope:update", "scope:delete");
|
||||
|
||||
try (Response response = authorization.resources().create(resourceWithoutType)) {
|
||||
resourceWithoutType = response.readEntity(ResourceRepresentation.class);
|
||||
}
|
||||
|
||||
ResourceRepresentation resourceWithType = new ResourceRepresentation();
|
||||
|
||||
resourceWithType.setName(KeycloakModelUtils.generateId());
|
||||
resourceWithType.setType("type-one");
|
||||
resourceWithType.addScope("scope:view", "scope:update", "scope:delete");
|
||||
|
||||
try (Response response = authorization.resources().create(resourceWithType)) {
|
||||
resourceWithType = response.readEntity(ResourceRepresentation.class);
|
||||
}
|
||||
|
||||
ScopePermissionRepresentation permission = new ScopePermissionRepresentation();
|
||||
|
||||
permission.setName(KeycloakModelUtils.generateId());
|
||||
permission.addResource(resourceWithoutType.getId());
|
||||
permission.addScope("scope:view");
|
||||
permission.addPolicy(policy.getName());
|
||||
|
||||
authorization.permissions().scope().create(permission).close();
|
||||
|
||||
permission = new ScopePermissionRepresentation();
|
||||
|
||||
permission.setName(KeycloakModelUtils.generateId());
|
||||
permission.setResourceType("type-one");
|
||||
permission.addScope("scope:update");
|
||||
permission.addPolicy(policy.getName());
|
||||
|
||||
authorization.permissions().scope().create(permission).close();
|
||||
|
||||
String accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).doGrantAccessTokenRequest("secret", "kolo", "password").getAccessToken();
|
||||
AuthzClient authzClient = getAuthzClient(AUTHZ_CLIENT_CONFIG);
|
||||
|
||||
AuthorizationRequest request = new AuthorizationRequest();
|
||||
request.addPermission(resourceWithoutType.getId(), "scope:view", "scope:update", "scope:delete");
|
||||
|
||||
AuthorizationResponse response = authzClient.authorization(accessToken).authorize(request);
|
||||
assertNotNull(response.getToken());
|
||||
Collection<Permission> permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
|
||||
assertEquals(1, permissions.size());
|
||||
|
||||
for (Permission grantedPermission : permissions) {
|
||||
assertEquals(resourceWithoutType.getId(), grantedPermission.getResourceId());
|
||||
assertEquals(1, grantedPermission.getScopes().size());
|
||||
assertTrue(grantedPermission.getScopes().containsAll(Arrays.asList("scope:view")));
|
||||
}
|
||||
|
||||
request = new AuthorizationRequest();
|
||||
request.addPermission(resourceWithType.getId(), "scope:view", "scope:update", "scope:delete");
|
||||
|
||||
response = authzClient.authorization(accessToken).authorize(request);
|
||||
assertNotNull(response.getToken());
|
||||
permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
|
||||
assertEquals(1, permissions.size());
|
||||
|
||||
for (Permission grantedPermission : permissions) {
|
||||
assertEquals(resourceWithType.getId(), grantedPermission.getResourceId());
|
||||
assertEquals(1, grantedPermission.getScopes().size());
|
||||
assertTrue(grantedPermission.getScopes().containsAll(Arrays.asList("scope:update")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerDecisionStrategy() throws Exception {
|
||||
ClientResource client = getClient(getRealm(), RESOURCE_SERVER_TEST);
|
||||
|
@ -1040,29 +1126,59 @@ public class EntitlementAPITest extends AbstractAuthzTest {
|
|||
authorization.resources().create(resource).close();
|
||||
}
|
||||
|
||||
ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ResourceRepresentation resource = new ResourceRepresentation();
|
||||
|
||||
permission.setName(KeycloakModelUtils.generateId());
|
||||
permission.setResourceType("type-one");
|
||||
permission.addPolicy(policy.getName());
|
||||
resource.setType("type-four");
|
||||
resource.setName(KeycloakModelUtils.generateId());
|
||||
resource.addScope("scope:view", "scope:update");
|
||||
|
||||
authorization.permissions().resource().create(permission).close();
|
||||
authorization.resources().create(resource).close();
|
||||
}
|
||||
|
||||
permission = new ResourcePermissionRepresentation();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ResourceRepresentation resource = new ResourceRepresentation();
|
||||
|
||||
permission.setName(KeycloakModelUtils.generateId());
|
||||
permission.setResourceType("type-two");
|
||||
permission.addPolicy(policy.getName());
|
||||
resource.setType("type-five");
|
||||
resource.setName(KeycloakModelUtils.generateId());
|
||||
resource.addScope("scope:view");
|
||||
|
||||
authorization.permissions().resource().create(permission).close();
|
||||
authorization.resources().create(resource).close();
|
||||
}
|
||||
|
||||
permission = new ResourcePermissionRepresentation();
|
||||
|
||||
permission.setName(KeycloakModelUtils.generateId());
|
||||
permission.setResourceType("type-three");
|
||||
permission.addPolicy(policy.getName());
|
||||
ResourcePermissionRepresentation resourcePermission = new ResourcePermissionRepresentation();
|
||||
|
||||
authorization.permissions().resource().create(permission).close();
|
||||
resourcePermission.setName(KeycloakModelUtils.generateId());
|
||||
resourcePermission.setResourceType("type-one");
|
||||
resourcePermission.addPolicy(policy.getName());
|
||||
|
||||
authorization.permissions().resource().create(resourcePermission).close();
|
||||
|
||||
resourcePermission = new ResourcePermissionRepresentation();
|
||||
|
||||
resourcePermission.setName(KeycloakModelUtils.generateId());
|
||||
resourcePermission.setResourceType("type-two");
|
||||
resourcePermission.addPolicy(policy.getName());
|
||||
|
||||
authorization.permissions().resource().create(resourcePermission).close();
|
||||
|
||||
resourcePermission = new ResourcePermissionRepresentation();
|
||||
|
||||
resourcePermission.setName(KeycloakModelUtils.generateId());
|
||||
resourcePermission.setResourceType("type-three");
|
||||
resourcePermission.addPolicy(policy.getName());
|
||||
|
||||
authorization.permissions().resource().create(resourcePermission).close();
|
||||
|
||||
ScopePermissionRepresentation scopePersmission = new ScopePermissionRepresentation();
|
||||
|
||||
scopePersmission.setName(KeycloakModelUtils.generateId());
|
||||
scopePersmission.setResourceType("type-four");
|
||||
scopePersmission.addScope("scope:view");
|
||||
scopePersmission.addPolicy(policy.getName());
|
||||
|
||||
authorization.permissions().scope().create(scopePersmission).close();
|
||||
|
||||
String accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).doGrantAccessTokenRequest("secret", "kolo", "password").getAccessToken();
|
||||
AuthzClient authzClient = getAuthzClient(AUTHZ_CLIENT_CONFIG);
|
||||
|
@ -1081,6 +1197,26 @@ public class EntitlementAPITest extends AbstractAuthzTest {
|
|||
permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
|
||||
assertEquals(10, permissions.size());
|
||||
|
||||
request = new AuthorizationRequest();
|
||||
request.addPermission("resource-type:type-four", "scope:view");
|
||||
response = authzClient.authorization(accessToken).authorize(request);
|
||||
assertNotNull(response.getToken());
|
||||
permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
|
||||
assertEquals(10, permissions.size());
|
||||
for (Permission grantedPermission : permissions) {
|
||||
assertEquals(1, grantedPermission.getScopes().size());
|
||||
assertTrue(grantedPermission.getScopes().containsAll(Arrays.asList("scope:view")));
|
||||
}
|
||||
|
||||
request = new AuthorizationRequest();
|
||||
request.addPermission("resource-type:type-five", "scope:view");
|
||||
try {
|
||||
authzClient.authorization(accessToken).authorize(request);
|
||||
fail("no type-five resources can be granted since scope permission for scope:view only applies to type-four");
|
||||
} catch (RuntimeException expected) {
|
||||
assertEquals(403, HttpResponseException.class.cast(expected.getCause()).getStatusCode());
|
||||
assertTrue(HttpResponseException.class.cast(expected.getCause()).toString().contains("access_denied"));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ResourceRepresentation resource = new ResourceRepresentation();
|
||||
|
|
Loading…
Reference in a new issue