From 2b88388ff9a5c59bb688be1afb446ec525d084a5 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Wed, 20 Mar 2024 12:21:49 -0300 Subject: [PATCH] Do not grant scopes not granted for resources owned the resource server itself Closes #25057 Signed-off-by: Pedro Igor --- .../AuthorizationTokenService.java | 8 ++- .../testsuite/authz/EntitlementAPITest.java | 61 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java index 96ecf9e19fb4..baa8ce87420b 100644 --- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java +++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java @@ -32,6 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; +import java.util.function.Predicate; import java.util.stream.Collectors; import jakarta.ws.rs.HttpMethod; @@ -656,7 +657,12 @@ private void resolveResourcePermission(KeycloakAuthorizationRequest request, ResourcePermission resourcePermission = addPermission(request, resourceServer, authorization, permissionsToEvaluate, limit, requestedScopesModel, grantedResource); - + if (resourcePermission != null) { + Collection permissionScopes = resourcePermission.getScopes(); + if (permissionScopes != null) { + permissionScopes.retainAll(scopes); + } + } // the permission is explicitly granted by the owner, mark this permission as granted so that we don't run the evaluation engine on it resourcePermission.setGranted(true); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java index f03e213fa869..cdd36b7064db 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java @@ -35,7 +35,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.stream.Collectors; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClients; @@ -2415,6 +2417,65 @@ public void testPermissionOrder() throws Exception { .getScopes().contains("entity:read"))); } + @Test + public void testSameResultRegardlessOPermissionParameterValue() throws Exception { + ClientResource client = getClient(getRealm(), RESOURCE_SERVER_TEST); + AuthorizationResource authorization = client.authorization(); + ResourceRepresentation resource = new ResourceRepresentation(); + + resource.setName(KeycloakModelUtils.generateId()); + resource.addScope("scope1", "scope2"); + resource.setOwnerManagedAccess(true); + + try (Response response = authorization.resources().create(resource)) { + resource = response.readEntity(ResourceRepresentation.class); + } + + UserPolicyRepresentation policy = new UserPolicyRepresentation(); + + policy.setName(KeycloakModelUtils.generateId()); + policy.addUser("marta"); + + authorization.policies().user().create(policy).close(); + + ScopePermissionRepresentation representation = new ScopePermissionRepresentation(); + + representation.setName(KeycloakModelUtils.generateId()); + representation.addScope("scope1"); + representation.addPolicy(policy.getName()); + + authorization.permissions().scope().create(representation).close(); + + AuthzClient authzClient = getAuthzClient(AUTHZ_CLIENT_CONFIG); + PermissionTicketRepresentation ticket = new PermissionTicketRepresentation(); + + ticket.setResource(resource.getId()); + ticket.setRequesterName("marta"); + ticket.setGranted(true); + ticket.setScopeName("scope1"); + + authzClient.protection().permission().create(ticket); + + AuthorizationRequest request = new AuthorizationRequest(); + request.addPermission(resource.getId()); + AuthorizationResponse response = authzClient.authorization("marta", "password").authorize(request); + AccessToken rpt = toAccessToken(response.getToken()); + ResourceRepresentation finalResource = resource; + List permissions = rpt.getAuthorization().getPermissions().stream().filter(permission -> permission.getResourceId().equals(finalResource.getId())).collect(Collectors.toList()); + assertEquals(1, permissions.size()); + assertEquals(1, permissions.get(0).getScopes().size()); + assertEquals("scope1", permissions.get(0).getScopes().iterator().next()); + + request = new AuthorizationRequest(); + request.addPermission(resource.getName()); + response = authzClient.authorization("marta", "password").authorize(request); + rpt = toAccessToken(response.getToken()); + permissions = rpt.getAuthorization().getPermissions().stream().filter(permission -> permission.getResourceId().equals(finalResource.getId())).collect(Collectors.toList()); + assertEquals(1, permissions.size()); + assertEquals(1, permissions.get(0).getScopes().size()); + assertEquals("scope1", permissions.get(0).getScopes().iterator().next()); + } + private void testRptRequestWithResourceName(String configFile) { Metadata metadata = new Metadata();