keycloak-uncached

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/AuthorizationRequest.java b/core/src/main/java/org/keycloak/representations/idm/authorization/AuthorizationRequest.java
index 6682075..90cba85 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/AuthorizationRequest.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/AuthorizationRequest.java
@@ -151,7 +151,7 @@ public class AuthorizationRequest {
         ResourcePermission permission = null;
 
         for (ResourcePermission resourcePermission : permissions.getResources()) {
-            if (resourcePermission.getResourceId().equals(resourceId)) {
+            if (resourcePermission.getResourceId() != null && resourcePermission.getResourceId().equals(resourceId)) {
                 permission = resourcePermission;
                 break;
             }
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 751197b..97e6727 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -29,6 +29,7 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -354,17 +355,21 @@ public class AuthorizationTokenService {
                 }
             }
 
-            if (existingResources.isEmpty() && (requestedScopes == null || requestedScopes.isEmpty())) {
-                throw new CorsErrorResponseException(cors, "invalid_resource", "Resource with id [" + requestedResource.getResourceId() + "] does not exist.", Status.FORBIDDEN);
-            }
-
             String clientAdditionalScopes = request.getScope();
 
             if (clientAdditionalScopes != null) {
                 requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
             }
 
-            List<Scope> requestedScopesModel = requestedScopes.stream().map(s -> scopeStore.findByName(s, resourceServer.getId())).collect(Collectors.toList());
+            List<Scope> requestedScopesModel = requestedScopes.stream().map(s -> scopeStore.findByName(s, resourceServer.getId())).filter(Objects::nonNull).collect(Collectors.toList());
+
+            if (requestedResource.getResourceId() != null && !"".equals(requestedResource.getResourceId().trim()) && existingResources.isEmpty()) {
+                throw new CorsErrorResponseException(cors, "invalid_resource", "Resource with id [" + requestedResource.getResourceId() + "] does not exist.", Status.BAD_REQUEST);
+            }
+
+            if ((requestedResource.getScopes() != null && !requestedResource.getScopes().isEmpty()) && requestedScopesModel.isEmpty()) {
+                throw new CorsErrorResponseException(cors, "invalid_scope", "One of the given scopes " + requestedResource.getScopes() + " are invalid", Status.BAD_REQUEST);
+            }
 
             if (!existingResources.isEmpty()) {
                 for (Resource resource : existingResources) {
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 9325550..562555a 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
@@ -21,12 +21,15 @@ import static org.junit.Assert.assertFalse;
 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.Set;
 import java.util.function.Supplier;
 
 import org.junit.Before;
@@ -439,7 +442,7 @@ public class EntitlementAPITest extends AbstractAuthzTest {
 
         authorization.resources().resource(resource.getId()).update(resource);
 
-        // the addition of a new scope invalidates the permission previously grante to the resource
+        // the addition of a new scope invalidates the permission previously granted to the resource
         assertFalse(hasPermission("kolo", "password", resource.getId()));
 
         accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).doGrantAccessTokenRequest("secret", "kolo", "password").getAccessToken();
@@ -471,6 +474,7 @@ public class EntitlementAPITest extends AbstractAuthzTest {
         authorization.resources().resource(resource.getId()).update(resource);
 
         assertTrue(hasPermission("kolo", "password", resource.getId()));
+        assertTrue(hasPermission("kolo", "password", resource.getId(), "Scope A"));
         assertFalse(hasPermission("kolo", "password", resource.getId(), "Scope B"));
 
         resource.setScopes(new HashSet<>());
@@ -479,6 +483,7 @@ public class EntitlementAPITest extends AbstractAuthzTest {
 
         assertTrue(hasPermission("kolo", "password", resource.getId()));
         assertFalse(hasPermission("kolo", "password", resource.getId(), "Scope A"));
+        assertFalse(hasPermission("kolo", "password", resource.getId(), "Scope B"));
     }
 
     @Test
@@ -514,9 +519,146 @@ public class EntitlementAPITest extends AbstractAuthzTest {
 
         request.addPermission("Sensortest", "sensors:view");
 
+        try {
+            authzClient.authorization(accessToken).authorize(request);
+            fail("resource is invalid");
+        } catch (RuntimeException expected) {
+            assertEquals(400, HttpResponseException.class.cast(expected.getCause()).getStatusCode());
+            assertTrue(HttpResponseException.class.cast(expected.getCause()).toString().contains("invalid_resource"));
+        }
+    }
+
+    @Test
+    public void testObtainAllEntitlementsInvalidScope() 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 resource = new ResourceRepresentation();
+
+        resource.setName(KeycloakModelUtils.generateId());
+        resource.addScope("sensors:view", "sensors:update", "sensors:delete");
+
+        resource = authorization.resources().create(resource).readEntity(ResourceRepresentation.class);
+
+        ScopePermissionRepresentation permission = new ScopePermissionRepresentation();
+
+        permission.setName(KeycloakModelUtils.generateId());
+        permission.addScope("sensors:view");
+        permission.addPolicy(policy.getName());
+
+        authorization.permissions().scope().create(permission);
+
+        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(resource.getId(), "sensors:view_invalid");
+
+        try {
+            authzClient.authorization(accessToken).authorize(request);
+            fail("scope is invalid");
+        } catch (RuntimeException expected) {
+            assertEquals(400, HttpResponseException.class.cast(expected.getCause()).getStatusCode());
+            assertTrue(HttpResponseException.class.cast(expected.getCause()).toString().contains("invalid_scope"));
+        }
+
+        request = new AuthorizationRequest();
+
+        request.addPermission(null, "sensors:view_invalid");
+
+        try {
+            authzClient.authorization(accessToken).authorize(request);
+            fail("scope is invalid");
+        } catch (RuntimeException expected) {
+            assertEquals(400, HttpResponseException.class.cast(expected.getCause()).getStatusCode());
+            assertTrue(HttpResponseException.class.cast(expected.getCause()).toString().contains("invalid_scope"));
+        }
+    }
+
+    @Test
+    public void testObtainAllEntitlementsForScope() 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();
+
+        Set<String> resourceIds = new HashSet<>();
+        ResourceRepresentation resource = new ResourceRepresentation();
+
+        resource.setName(KeycloakModelUtils.generateId());
+        resource.addScope("sensors:view", "sensors:update", "sensors:delete");
+
+        resourceIds.add(authorization.resources().create(resource).readEntity(ResourceRepresentation.class).getId());
+
+        resource = new ResourceRepresentation();
+
+        resource.setName(KeycloakModelUtils.generateId());
+        resource.addScope("sensors:view", "sensors:update", "sensors:delete");
+
+        resourceIds.add(authorization.resources().create(resource).readEntity(ResourceRepresentation.class).getId());
+
+        ScopePermissionRepresentation permission = new ScopePermissionRepresentation();
+
+        permission.setName(KeycloakModelUtils.generateId());
+        permission.addScope("sensors:view", "sensors:update");
+        permission.addPolicy(policy.getName());
+
+        authorization.permissions().scope().create(permission);
+
+        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(null, "sensors:view");
+
         AuthorizationResponse response = authzClient.authorization(accessToken).authorize(request);
+        assertNotNull(response.getToken());
+        List<Permission> permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
+        assertEquals(2, permissions.size());
+
+        for (Permission grantedPermission : permissions) {
+            assertTrue(resourceIds.containsAll(Arrays.asList(grantedPermission.getResourceId())));
+            assertEquals(1, grantedPermission.getScopes().size());
+            assertTrue(grantedPermission.getScopes().containsAll(Arrays.asList("sensors:view")));
+        }
+
+        request.addPermission(null, "sensors:view", "sensors:update");
 
-        assertNotNull(response);
+        response = authzClient.authorization(accessToken).authorize(request);
+        assertNotNull(response.getToken());
+        permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
+        assertEquals(2, permissions.size());
+
+        for (Permission grantedPermission : permissions) {
+            assertTrue(resourceIds.containsAll(Arrays.asList(grantedPermission.getResourceId())));
+            assertEquals(2, grantedPermission.getScopes().size());
+            assertTrue(grantedPermission.getScopes().containsAll(Arrays.asList("sensors:view", "sensors:update")));
+        }
+
+        request.addPermission(null, "sensors:view", "sensors:update", "sensors:delete");
+
+        response = authzClient.authorization(accessToken).authorize(request);
+        assertNotNull(response.getToken());
+        permissions = toAccessToken(response.getToken()).getAuthorization().getPermissions();
+        assertEquals(2, permissions.size());
+
+        for (Permission grantedPermission : permissions) {
+            assertTrue(resourceIds.containsAll(Arrays.asList(grantedPermission.getResourceId())));
+            assertEquals(2, grantedPermission.getScopes().size());
+            assertTrue(grantedPermission.getScopes().containsAll(Arrays.asList("sensors:view", "sensors:update")));
+        }
     }
 
     private void testRptRequestWithResourceName(String configFile) {