From 9857a04895da92f4166db874e26cb539618396a2 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Thu, 29 Oct 2020 22:28:14 +0100 Subject: [PATCH] KEYCLOAK-16107 Enable ScriptBasedOIDCProtocolMapper to return JSON objects directly We now allow to return JSON objects directly from a ScriptBasedOIDCProtocolMapper, by adding support to turn objects that implement the java.util.Map into JsonNodes. Previously returning JSON objects directly caused an exception during runtime. --- .../oidc/mappers/OIDCAttributeMapperHelper.java | 12 ++++++++++-- .../testsuite/oauth/OIDCProtocolMappersTest.java | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java index 0e7a5933e9..0813f8171f 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java @@ -159,11 +159,19 @@ public class OIDCAttributeMapperHelper { } private static JsonNode getJsonNode(Object attributeValue) { - if (attributeValue instanceof JsonNode) return (JsonNode) attributeValue; + if (attributeValue instanceof JsonNode){ + return (JsonNode) attributeValue; + } + if (attributeValue instanceof Map) { + try { + return JsonSerialization.createObjectNode(attributeValue); + } catch (Exception ignore) { + } + } if (attributeValue instanceof String) { try { return JsonSerialization.readValue(attributeValue.toString(), JsonNode.class); - } catch (Exception ex) { + } catch (Exception ignore) { } } return null; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java index e1f3141d07..1f6ef01c9d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java @@ -141,6 +141,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest { app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper1","computed-via-script", "computed-via-script", "String", true, true, "'hello_' + user.username", false)).close(); app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper2","multiValued-via-script", "multiValued-via-script", "String", true, true, "new java.util.ArrayList(['A','B'])", true)).close(); + app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3","computed-json-via-script", "computed-json-via-script", "JSON", true, true, "var x = {'int':42, 'bool': true, 'string': 'test'}; x", false)).close(); Response response = app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3", "syntax-error-script", "syntax-error-script", "String", true, true, "func_tion foo(){ return 'fail';} foo()", false)); assertThat(response.getStatusInfo().getFamily(), is(Response.Status.Family.CLIENT_ERROR)); @@ -152,6 +153,12 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest { assertEquals("hello_test-user@localhost", accessToken.getOtherClaims().get("computed-via-script")); assertEquals(Arrays.asList("A","B"), accessToken.getOtherClaims().get("multiValued-via-script")); + Object o = accessToken.getOtherClaims().get("computed-json-via-script"); + assertTrue("Computed json object should be a map", o instanceof Map); + Map map = (Map)o; + assertEquals(map.get("int"), 42); + assertEquals(map.get("bool"), true); + assertEquals(map.get("string"), "test"); } }