[java-oidc-common] branch main updated: JCOMOIDC-166 - Decoding of list valued claims fails

Codeberg noreply at shibboleth.net
Tue Aug 25 12:59:46 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch main
in repository java-oidc-common.

View the commit online:
https://codeberg.org/Shibboleth/java-oidc-common/commit/d26e3acd09b58c56102d1c09a18ece4722e80884

The following commit(s) were added to refs/heads/main by this push:
     new d26e3acd JCOMOIDC-166 - Decoding of list valued claims fails
d26e3acd is described below

commit d26e3acd09b58c56102d1c09a18ece4722e80884
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Tue Aug 25 13:59:36 2026 +0100

    JCOMOIDC-166 - Decoding of list valued claims fails
    
     - Added List to the supported types to decode
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-166
---
 .../impl/OIDCScopedStringAttributeTranscoder.java  | 14 +++--
 .../impl/OIDCStringAttributeTranscoder.java        | 21 +++++--
 .../OIDCScopedStringAttributeTranscoderTest.java   | 33 +++++++++++
 .../impl/OIDCStringAttributeTranscoderTest.java    | 67 ++++++++++++++++++++++
 4 files changed, 127 insertions(+), 8 deletions(-)

diff --git a/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoder.java b/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoder.java
index 18c6aad5..ecc30853 100644
--- a/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoder.java
+++ b/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoder.java
@@ -106,8 +106,7 @@ public class OIDCScopedStringAttributeTranscoder extends AbstractOIDCAttributeTr
             @Nullable final ProfileRequestContext profileRequestContext, @Nonnull final Object input,
             @Nonnull final TranscodingRule rule) throws AttributeDecodingException {
         
-        if (input instanceof String) {
-            final String stringValue = (String)input;
+        if (input instanceof final String stringValue) {
             final String scopeDelimiter = rule.getOrDefault(PROP_SCOPE_DELIMITER, String.class, "@");
             assert scopeDelimiter != null;
             final int offset = stringValue.indexOf(scopeDelimiter);
@@ -119,9 +118,8 @@ public class OIDCScopedStringAttributeTranscoder extends AbstractOIDCAttributeTr
             assert scope != null;
             return CollectionSupport.listOf(ScopedStringAttributeValue.valueOf(stringValue.substring(0, offset), 
                     scope));
-        } else if (input instanceof JSONArray) {
+        } else if (input instanceof final JSONArray array) {
             // Deal with array recursively
-            final JSONArray array = (JSONArray)input;
             final List<IdPAttributeValue> arrayValuesDecoded = new ArrayList<>();
             for (final Object element : array) {
                 assert element != null;
@@ -129,6 +127,14 @@ public class OIDCScopedStringAttributeTranscoder extends AbstractOIDCAttributeTr
             }
             return arrayValuesDecoded;
             
+        } else if (input instanceof final List list){
+        	 // Deal with array recursively
+            final List<IdPAttributeValue> arrayValuesDecoded = new ArrayList<>();
+            for (final Object element : list) {
+                assert element != null;
+                arrayValuesDecoded.addAll(decodeValues(profileRequestContext, element, rule));
+            }
+            return arrayValuesDecoded;
         } else {
             log.trace("Could not convert values of type {} for the claim '{}' to a scoped string attribute using "
                     + "transcoding rule '{} -> {}'",
diff --git a/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoder.java b/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoder.java
index 8b34380c..4a1f7ac7 100644
--- a/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoder.java
+++ b/oidc-common-attribute-impl/src/main/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoder.java
@@ -195,15 +195,13 @@ public class OIDCStringAttributeTranscoder extends AbstractOIDCAttributeTranscod
             return CollectionSupport.listOf(StringAttributeValue.valueOf(Double.toString((Double)input)));            
         } else if (input instanceof Boolean && boolAsString) {           
             return CollectionSupport.listOf(StringAttributeValue.valueOf(Boolean.toString((Boolean)input)));            
-        } else if (input instanceof JSONArray) {
+        } else if (input instanceof final JSONArray array) {
             final Boolean arrayAsString = rule.getOrDefault(PROP_ARRAY_AS_STRING, Boolean.class, false);
             assert arrayAsString != null;
             if (arrayAsString) {
                 // Serialize JSON Array to JSON string
                 return CollectionSupport.listOf(StringAttributeValue.valueOf(((JSONArray)input).toJSONString()));
             } else {
-                // Deal with array recursively
-                final JSONArray array = (JSONArray) input;
                 final List<IdPAttributeValue> arrayValuesDecoded = new ArrayList<>();
                 for (final Object element : array) {
                     assert element != null;
@@ -212,7 +210,7 @@ public class OIDCStringAttributeTranscoder extends AbstractOIDCAttributeTranscod
                 return arrayValuesDecoded;  
             }
             
-        } if (input instanceof JSONObject && asObject) {
+        } else if (input instanceof JSONObject && asObject) {
             // Serialize JSONObject to a JSON string.
             return CollectionSupport.listOf(StringAttributeValue.valueOf(((JSONObject)input).toJSONString()));
             
@@ -228,6 +226,21 @@ public class OIDCStringAttributeTranscoder extends AbstractOIDCAttributeTranscod
             
             return CollectionSupport.listOf(StringAttributeValue.valueOf(
                     new JSONObject(mapWithStringKeys).toJSONString()));
+            
+        } else if(input instanceof final List inputList) { 
+        	final Boolean arrayAsString = rule.getOrDefault(PROP_ARRAY_AS_STRING, Boolean.class, false);
+            assert arrayAsString != null;
+            if (arrayAsString) {
+                // Serialize JSON Array to JSON string, use same method as if JSONArray for consistent output
+                return CollectionSupport.listOf(StringAttributeValue.valueOf(JSONArray.toJSONString(inputList)));
+            } else {
+                final List<IdPAttributeValue> arrayValuesDecoded = new ArrayList<>();
+                for (final Object element : inputList) {
+                    assert element != null;
+                    arrayValuesDecoded.addAll(decodeValues(profileRequestContext, element, rule));
+                }
+                return arrayValuesDecoded;  
+            }
         } else {
             log.trace("Could not convert values of type {} for the claim '{}' to a string attribute using "
                     + "transcoding rule '{} -> {}'",
diff --git a/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoderTest.java b/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoderTest.java
index a790ffe1..11cde387 100644
--- a/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoderTest.java
+++ b/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCScopedStringAttributeTranscoderTest.java
@@ -363,6 +363,39 @@ public class OIDCScopedStringAttributeTranscoderTest {
         Assert.assertEquals(((ScopedStringAttributeValue)decodedAttribute.getValues().get(1)).getValue(), STRING_2);
     }
     
+    // See JCOMOIDC-166
+    @Test
+    public void testDecodingStringArray_UsingArrayList() 
+    			throws ComponentInitializationException, AttributeDecodingException {
+        
+        registry.setTranscoderRegistry(CollectionSupport.singletonList(new TranscodingRule(ruleset)));
+        registry.setApplicationContext(new MockApplicationContext());        
+        registry.initialize();        
+       
+        // Map from oidc claim.name 'bar' to shib attribute id 'foo'. 
+        final JSONObject inputAttribute = new JSONObject();
+        final List<String> values = new ArrayList<>();
+        values.add(STRING_1+ DELIMITER + SCOPE_1);
+        values.add(STRING_2+ DELIMITER + SCOPE_2);            
+        inputAttribute.put(ATTR_NAME, values);
+
+        final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute);
+        Assert.assertEquals(rulesets.size(), 1);
+        final TranscodingRule tr = rulesets.iterator().next();
+        assert tr != null;
+
+        final IdPAttribute decodedAttribute = TranscoderSupport.<JSONObject>getTranscoder(tr)
+                .decode(null, inputAttribute, tr);
+
+        assert decodedAttribute != null;
+        Assert.assertEquals(decodedAttribute.getId(), ATTR_ID);
+        Assert.assertEquals(decodedAttribute.getValues().size(), 2);
+        Assert.assertEquals(((ScopedStringAttributeValue)decodedAttribute.getValues().get(0)).getScope(), SCOPE_1);
+        Assert.assertEquals(((ScopedStringAttributeValue)decodedAttribute.getValues().get(0)).getValue(), STRING_1);
+        Assert.assertEquals(((ScopedStringAttributeValue)decodedAttribute.getValues().get(1)).getScope(), SCOPE_2);
+        Assert.assertEquals(((ScopedStringAttributeValue)decodedAttribute.getValues().get(1)).getValue(), STRING_2);
+    }
+    
     @Test
     public void testDecodingComplexArray() throws ComponentInitializationException, AttributeDecodingException {
         
diff --git a/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoderTest.java b/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoderTest.java
index 6049e12f..52aecf67 100644
--- a/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoderTest.java
+++ b/oidc-common-attribute-impl/src/test/java/net/shibboleth/oidc/attribute/transcoding/impl/OIDCStringAttributeTranscoderTest.java
@@ -380,6 +380,73 @@ public class OIDCStringAttributeTranscoderTest {
         Assert.assertEquals(decodedAttribute.getValues().get(1).getNativeValue(), "Second");
     }
     
+    // See JCOMOIDC-166
+    @Test
+    public void testDecodingStringArray_UsingArrayList() 
+    		throws ComponentInitializationException, AttributeDecodingException {
+        
+        assert ruleset != null;
+        registry.setTranscoderRegistry(CollectionSupport.singletonList(new TranscodingRule(ruleset)));
+        registry.setApplicationContext(new MockApplicationContext());        
+        registry.initialize();
+       
+        // Map from oidc claim.name 'bar' to shib attribute id 'foo'. 
+        final JSONObject inputAttribute = new JSONObject();  
+        final List<String> values = new ArrayList<>();
+        values.add("https://refeds.org/assurance");
+        values.add("https://refeds.org/assurance/IAP/low");            
+        inputAttribute.put(ATTR_NAME, values);
+
+        final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute);
+        Assert.assertEquals(rulesets.size(), 1);
+        final TranscodingRule tr = rulesets.iterator().next();
+        assert tr != null;
+
+        final IdPAttribute decodedAttribute = TranscoderSupport.<JSONObject>getTranscoder(tr)
+                .decode(null, inputAttribute, tr);
+
+        assert decodedAttribute != null;
+        Assert.assertEquals(decodedAttribute.getId(), ATTR_ID);
+        Assert.assertEquals(decodedAttribute.getValues().size(), 2);
+        Assert.assertEquals(decodedAttribute.getValues().get(0).getNativeValue(), "https://refeds.org/assurance");
+        Assert.assertEquals(decodedAttribute.getValues().get(1).getNativeValue(), 
+        		"https://refeds.org/assurance/IAP/low");
+    }
+    
+    // See JCOMOIDC-166
+    @Test
+    public void testDecodingStringArrayAsJSONString_UsingArrayList() 
+    		throws ComponentInitializationException, AttributeDecodingException {
+    	
+    	ruleset.put(OIDCStringAttributeTranscoder.PROP_ARRAY_AS_STRING, true);
+        
+        assert ruleset != null;
+        registry.setTranscoderRegistry(CollectionSupport.singletonList(new TranscodingRule(ruleset)));
+        registry.setApplicationContext(new MockApplicationContext());        
+        registry.initialize();
+       
+        // Map from oidc claim.name 'bar' to shib attribute id 'foo'. 
+        final JSONObject inputAttribute = new JSONObject();  
+        final List<String> values = new ArrayList<>();
+        values.add("https://refeds.org/assurance");
+        values.add("https://refeds.org/assurance/IAP/low");            
+        inputAttribute.put(ATTR_NAME, values);
+
+        final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute);
+        Assert.assertEquals(rulesets.size(), 1);
+        final TranscodingRule tr = rulesets.iterator().next();
+        assert tr != null;
+
+        final IdPAttribute decodedAttribute = TranscoderSupport.<JSONObject>getTranscoder(tr)
+                .decode(null, inputAttribute, tr);
+
+        assert decodedAttribute != null;
+        Assert.assertEquals(decodedAttribute.getId(), ATTR_ID);
+        Assert.assertEquals(decodedAttribute.getValues().size(), 1);
+        Assert.assertEquals(decodedAttribute.getValues().get(0).getNativeValue(), 
+        		"[\"https:\\/\\/refeds.org\\/assurance\",\"https:\\/\\/refeds.org\\/assurance\\/IAP\\/low\"]");
+    }
+    
     @Test
     public void testDecodingStringArrayAsString() throws ComponentInitializationException, AttributeDecodingException {
         

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list