[java-idp-plugin-vci] branch main updated: Parse credential information in bit more friendly manner for attributes
Codeberg
noreply at shibboleth.net
Tue Sep 22 11:36:31 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-idp-plugin-vci.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/f8df3fc90a7f10d2699f86cb730e352234a4c2a6
The following commit(s) were added to refs/heads/main by this push:
new f8df3fc Parse credential information in bit more friendly manner for attributes
f8df3fc is described below
commit f8df3fc90a7f10d2699f86cb730e352234a4c2a6
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Tue Sep 22 14:36:17 2026 +0300
Parse credential information in bit more friendly manner for attributes
---
README.md | 9 ++---
.../impl/CredentialOfferRequestedClaim.java | 12 +++++++
.../impl/CredentialOfferRequestedCredential.java | 38 ++++++++++++++++++++--
.../CredentialOfferRequestedCredentialTest.java | 21 ++++++++++++
4 files changed, 74 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index cc82be6..0473977 100644
--- a/README.md
+++ b/README.md
@@ -745,8 +745,9 @@ code flow:
</details>
-The *value* of the attribute is the serialized claim list. You define it as a
-`ScriptedAttribute` so that it may read the real attributes of the user:
+The *value* of the attribute is the claims as an array of `{"path": [...], "value": ...}`, the
+same array the Credential Offer API takes. You define it as a `ScriptedAttribute` so that it may
+read the real attributes of the user:
<details>
<summary>Example snippet of conf/attribute-resolver.xml</summary>
@@ -759,14 +760,14 @@ The *value* of the attribute is the serialized claim list. You define it as a
<InputAttributeDefinition ref="sn" />
<InputAttributeDefinition ref="eduPersonAffiliation" />
<Script><![CDATA[
- var credential = '{"requestedCredential":['
+ var credential = '['
+ '{"path":["diploma"],"value":"Scrum Master"},'
+ '{"path":["mail"],"value":"' + mail.getValues().get(0) + '"},'
+ '{"path":["eppn"],"value":"' + eduPersonPrincipalName.getValues().get(0) + '"},'
+ '{"path":["givenName"],"value":"' + givenName.getValues().get(0) + '"},'
+ '{"path":["familyName"],"value":"' + sn.getValues().get(0) + '"},'
+ '{"path":["affiliation"],"value":"' + eduPersonAffiliation.getValues().get(0) + '"}'
- + ']}';
+ + ']';
GeantIncubatorDiploma.addValue(credential);
]]></Script>
<AttributeEncoder xsi:type="oidc:OIDCString" name="GeantIncubatorDiploma_SDJWT" />
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedClaim.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedClaim.java
index 683e13d..2611ef2 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedClaim.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedClaim.java
@@ -82,6 +82,18 @@ public final class CredentialOfferRequestedClaim {
return value;
}
+ /**
+ * Build a requested claim of a path and a value.
+ *
+ * @param path Path of the claim
+ * @param value Value of the claim
+ * @return CredentialOfferRequestedClaim instance
+ */
+ public static CredentialOfferRequestedClaim of(@Nonnull @NotEmpty final List<String> path,
+ @Nonnull final Object value) {
+ return new CredentialOfferRequestedClaim(path, value);
+ }
+
/**
* Parse CredentialOfferRequestedClaim instance from Map.
*
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredential.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredential.java
index 76999e6..7251e5f 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredential.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredential.java
@@ -19,6 +19,7 @@ package org.geant.shibboleth.plugin.openidvci.messaging.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Map;
import javax.annotation.Nonnull;
@@ -33,6 +34,9 @@ import com.nimbusds.oauth2.sdk.ParseException;
*/
public class CredentialOfferRequestedCredential {
+ /** Key of the requested claims. */
+ private static final String REQUESTED_CREDENTIAL_KEY = "requestedCredential";
+
/** Requested credentials. */
private final List<CredentialOfferRequestedClaim> requestedCredential;
@@ -83,8 +87,11 @@ public class CredentialOfferRequestedCredential {
*/
public static CredentialOfferRequestedCredential parse(@Nonnull final String request)
throws ParseException, JsonMappingException, JsonProcessingException {
- return new ObjectMapper().readValue(request, CredentialOfferRequestedCredential.class);
-
+ final Object parsed = new ObjectMapper().readValue(request, Object.class);
+ if (parsed instanceof Map<?, ?> content && content.containsKey(REQUESTED_CREDENTIAL_KEY)) {
+ return parse(content.get(REQUESTED_CREDENTIAL_KEY));
+ }
+ return parse(parsed);
}
/**
@@ -103,7 +110,34 @@ public class CredentialOfferRequestedCredential {
}
return new CredentialOfferRequestedCredential(requestedCredential);
}
+ if (object instanceof Map<?, ?> claims) {
+ collectClaims(claims, new ArrayList<>(), requestedCredential);
+ if (requestedCredential.isEmpty()) {
+ throw new ParseException("Invalid credential offer requested credential: No claims");
+ }
+ return new CredentialOfferRequestedCredential(requestedCredential);
+ }
throw new ParseException("Invalid credential offer requested credential: Parsing failed for "
+ (object != null ? object.toString() : "null"));
}
+
+ /**
+ * Collect the claims of a claims object, a nested object naming the path of the claims below it.
+ *
+ * @param claims claims object to read
+ * @param path path of the claims object
+ * @param collected claims collected so far
+ */
+ private static void collectClaims(@Nonnull final Map<?, ?> claims, @Nonnull final List<String> path,
+ @Nonnull final List<CredentialOfferRequestedClaim> collected) {
+ for (final Map.Entry<?, ?> claim : claims.entrySet()) {
+ final List<String> claimPath = new ArrayList<>(path);
+ claimPath.add(String.valueOf(claim.getKey()));
+ if (claim.getValue() instanceof Map<?, ?> nested) {
+ collectClaims(nested, claimPath, collected);
+ } else if (claim.getValue() != null) {
+ collected.add(CredentialOfferRequestedClaim.of(claimPath, claim.getValue()));
+ }
+ }
+ }
}
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredentialTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredentialTest.java
index ed61dbf..ae84c79 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredentialTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestedCredentialTest.java
@@ -51,6 +51,27 @@ public class CredentialOfferRequestedCredentialTest {
Assert.assertEquals(requestedCredential.getRequestedCredential().get(0).getValue(), "stringValue");
}
+ @Test
+ public void claimsObject() throws JsonProcessingException, ParseException {
+ requestedCredential = CredentialOfferRequestedCredential.parse("{\"diploma\":\"Scrum Master\","
+ + "\"mail\":\"incubatorUser at example.org\",\"address\":{\"city\":\"Helsinki\"}}");
+ Assert.assertEquals(requestedCredential.getRequestedCredential().size(), 3);
+ final CredentialOfferRequestedClaim nested = requestedCredential.getRequestedCredential().stream()
+ .filter(claim -> claim.getPath().size() == 2).findFirst().orElse(null);
+ Assert.assertNotNull(nested);
+ Assert.assertEquals(nested.getPath(), Arrays.asList("address", "city"));
+ Assert.assertEquals(nested.getValue(), "Helsinki");
+ }
+
+ @Test
+ public void claimsArray() throws JsonProcessingException, ParseException {
+ requestedCredential = CredentialOfferRequestedCredential
+ .parse("[{\"path\":[\"mail\"],\"value\":\"incubatorUser at example.org\"}]");
+ Assert.assertEquals(requestedCredential.getRequestedCredential().size(), 1);
+ Assert.assertEquals(requestedCredential.getRequestedCredential().get(0).getValue(),
+ "incubatorUser at example.org");
+ }
+
@Test
public void exampleString() throws JsonProcessingException, ParseException {
CredentialOfferRequestedCredential.parse(
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list