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 96ecf9e19f..baa8ce8742 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.Set; 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 @@ public class AuthorizationTokenService { 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 f03e213fa8..cdd36b7064 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.HashSet; 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 class EntitlementAPITest extends AbstractAuthzTest { .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();