From c8970c95d539c47df9ee62f1d9b66d4ef5b9e61e Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Tue, 9 Apr 2019 10:56:10 -0300 Subject: [PATCH] [KEYCLOAK-10015] - CIP not properly resolving objects from JSON request body --- .../authorization/util/JsonUtils.java | 17 ++++++- .../ClaimInformationPointProviderTest.java | 45 ++++++++++++++++++- .../enforcer-config-claims-provider.json | 17 +++++++ 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/util/JsonUtils.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/util/JsonUtils.java index 36c6d9b1f9..631f2ad6a0 100644 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/util/JsonUtils.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/util/JsonUtils.java @@ -16,11 +16,13 @@ */ package org.keycloak.adapters.authorization.util; +import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.fasterxml.jackson.databind.JsonNode; +import org.keycloak.util.JsonSerialization; /** * @author Pedro Igor @@ -38,14 +40,25 @@ public class JsonUtils { Iterator iterator = jsonNode.iterator(); while (iterator.hasNext()) { - String value = iterator.next().textValue(); + JsonNode node = iterator.next(); + String value; + + if (node.isObject()) { + try { + value = JsonSerialization.writeValueAsString(node); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + value = node.asText(); + } if (value != null) { values.add(value); } } } else { - String value = jsonNode.textValue(); + String value = jsonNode.asText(); if (value != null) { values.add(value); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ClaimInformationPointProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ClaimInformationPointProviderTest.java index e3f05c1390..50d2a03690 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ClaimInformationPointProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ClaimInformationPointProviderTest.java @@ -44,6 +44,7 @@ import io.undertow.server.handlers.form.FormParserFactory; import org.apache.http.impl.client.HttpClients; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.KeycloakDeployment; @@ -197,7 +198,7 @@ public class ClaimInformationPointProviderTest extends AbstractKeycloakTest { headers.put("Content-Type", Arrays.asList("application/json")); ObjectMapper mapper = JsonSerialization.mapper; - JsonParser parser = mapper.getFactory().createParser("{\"a\": {\"b\": {\"c\": \"c-value\"}}, \"d\": [\"d-value1\", \"d-value2\"]}"); + JsonParser parser = mapper.getFactory().createParser("{\"a\": {\"b\": {\"c\": \"c-value\"}}, \"d\": [\"d-value1\", \"d-value2\"], \"e\": {\"number\": 123}}"); TreeNode treeNode = mapper.readTree(parser); HttpFacade httpFacade = createHttpFacade(headers, new ByteArrayInputStream(treeNode.toString().getBytes())); @@ -205,6 +206,48 @@ public class ClaimInformationPointProviderTest extends AbstractKeycloakTest { assertEquals("c-value", claims.get("claim-from-json-body-object").get(0)); assertEquals("d-value2", claims.get("claim-from-json-body-array").get(0)); + assertEquals("123", claims.get("claim-from-json-body-number").get(0)); + } + + @Test + public void testBodyJsonObjectClaim() throws Exception { + Map> headers = new HashMap<>(); + + headers.put("Content-Type", Arrays.asList("application/json")); + + ObjectMapper mapper = JsonSerialization.mapper; + JsonParser parser = mapper.getFactory().createParser("{\"Individual\" : {\n" + + "\n" + + " \"Name\": \"John\",\n" + + "\n" + + " \"Lastname\": \"Doe\",\n" + + "\n" + + " \"individualRoles\" : [ {\n" + + "\n" + + " \"roleSpec\": 2342,\n" + + "\n" + + " \"roleId\": 4234},\n" + + "\n" + + "{\n" + + "\n" + + " \"roleSpec\": 4223,\n" + + "\n" + + " \"roleId\": 523\n" + + "\n" + + " }\n" + + "\n" + + " ]\n" + + "\n" + + "}}"); + TreeNode treeNode = mapper.readTree(parser); + HttpFacade httpFacade = createHttpFacade(headers, new ByteArrayInputStream(treeNode.toString().getBytes())); + + Map> claims = getClaimInformationProviderForPath("/claims-from-body-json-object", "claims").resolve(httpFacade); + + assertEquals(1, claims.size()); + assertEquals(2, claims.get("individualRoles").size()); + assertEquals("{\"roleSpec\":2342,\"roleId\":4234}", claims.get("individualRoles").get(0)); + assertEquals("{\"roleSpec\":4223,\"roleId\":523}", claims.get("individualRoles").get(1)); } @Test diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-claims-provider.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-claims-provider.json index 9da5dae147..eaeaaa4d9c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-claims-provider.json +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/enforcer-config-claims-provider.json @@ -32,6 +32,7 @@ "claim-from-secure": "{request.secure}", "claim-from-json-body-object": "{request.body['/a/b/c']}", "claim-from-json-body-array": "{request.body['/d/1']}", + "claim-from-json-body-number": "{request.body['/e/number']}", "claim-from-body": "{request.body}", "claim-from-static-value": "static value", "claim-from-multiple-static-value": ["static", "value"], @@ -39,6 +40,22 @@ } } }, + { + "path": "/claims-from-body-json-object", + "methods": [ + { + "method": "POST", + "scopes": [ + "create" + ] + } + ], + "claim-information-point": { + "claims": { + "individualRoles": "{request.body['/Individual/individualRoles']}" + } + } + }, { "path": "/http-post-claim-provider", "claim-information-point": {