[java-idp-oidc] 01/02: JOIDC-222 - Support for OpenID Federation

Henri Mikkonen henri.mikkonen at iki.fi
Tue Apr 22 07:26:28 UTC 2025


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

hjmikkon pushed a commit to branch dev/JOIDC-222
in repository java-idp-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=2c23bee08035b44f9d310b71bc5095464a7ad30d

commit 2c23bee08035b44f9d310b71bc5095464a7ad30d
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Apr 22 10:24:51 2025 +0300

    JOIDC-222 - Support for OpenID Federation
    
    https://shibboleth.atlassian.net/browse/JOIDC-222
    
    Adapted into the new trust mark ID naming
    - Use 'trust_mark_id' instead of 'id' claim
    - Parse trust marks directly from the JWT claims set (not via EntityStatement)
    - Store validated trust marks into RelyingPartyTrustChainContext (in addition to identifiers)
---
 ...DefaultTrustChainTrustMarksParsingStrategy.java | 39 ++++++++++++----------
 .../impl/RelyingPartyTrustChainContext.java        | 26 +++++++++++++++
 .../op/oidfed/profile/impl/ResolveTrustMarks.java  | 15 ++++++---
 3 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainTrustMarksParsingStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainTrustMarksParsingStrategy.java
index f0add6d7..5ee66542 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainTrustMarksParsingStrategy.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainTrustMarksParsingStrategy.java
@@ -18,6 +18,7 @@ import java.text.ParseException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -28,7 +29,6 @@ import org.slf4j.Logger;
 
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
-import com.nimbusds.oauth2.sdk.id.Identifier;
 import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -62,11 +62,14 @@ public class DefaultTrustChainTrustMarksParsingStrategy
             log.trace("Inspecting entity statement {} with trust marks {}",
                     statementJwt.serialize(), statement.getClaimsSet().getTrustMarks());
 
-            if (statement.getClaimsSet().getTrustMarks() != null) {
-                final List<SignedJWT> trustMarks = statement.getClaimsSet().getTrustMarks()
+            final List<Object> rawTrustMarks = statement.getClaimsSet().getJSONArrayClaim("trust_marks");
+            if (rawTrustMarks != null && !rawTrustMarks.isEmpty()) {
+                final List<SignedJWT> trustMarks = rawTrustMarks
                     .stream()
-                    .filter(entry -> verifyTrustMark(entry.getTrustMark(), entry.getID()))
-                    .map(entry -> entry.getTrustMark())
+                    .filter(Map.class::isInstance)
+                    .map(Map.class::cast)
+                    .map(map -> parseTrustMark(map.get("trust_mark"), map.get("trust_mark_id")))
+                    .filter(Objects::nonNull)
                     .toList();
                 result.put(statement.getEntityID().getValue(), trustMarks);
             }
@@ -78,27 +81,29 @@ public class DefaultTrustChainTrustMarksParsingStrategy
     /**
      * Verifies the trust mark id and issuer claims.
      * 
-     * @param trustMark trust mark to be verified
+     * @param trustMark trust mark to be verified, expected to be parseable from string
      * @param id the id to be verified from the JWT claims set
-     * @return true if valid, false otherwise
+     * @return trust mark JWT if valid, null otherwise
      */
-    private boolean verifyTrustMark(@Nullable final SignedJWT trustMark, @Nullable final Identifier id) {
-        if (trustMark == null || id == null) {
-            return false;
+    @Nullable private SignedJWT parseTrustMark(@Nullable final Object trustMark, @Nullable final Object id) {
+        if (trustMark == null || !(trustMark instanceof String) || id == null || !(id instanceof String)) {
+            return null;
         }
         try {
-            final JWTClaimsSet trustMarkClaims = trustMark.getJWTClaimsSet();
+            final SignedJWT jwt = SignedJWT.parse((String) trustMark);
+            final JWTClaimsSet trustMarkClaims = jwt.getJWTClaimsSet();
             if (StringSupport.trimOrNull(trustMarkClaims.getIssuer()) == null) {
-                log.error("Trust Mark {} is missing mandatory issuer", trustMarkClaims.getStringClaim("id"));
-                return false;
+                log.error("Trust Mark {} is missing mandatory issuer", trustMarkClaims.getStringClaim("trust_mark_id"));
+                return null;
             }
-            if (id.getValue().equals(trustMarkClaims.getStringClaim("id"))) {
-                return true;
+            if (id.equals(trustMarkClaims.getStringClaim("trust_mark_id"))) {
+                return jwt;
             }
-            log.error("The id {} is not matching with the id-claim {}", id, trustMarkClaims.getStringClaim("id"));
+            log.error("The id {} is not matching with the trust_mark_id-claim {}", id,
+                    trustMarkClaims.getStringClaim("trust_mark_id"));
         } catch (final ParseException e) {
             log.error("Could not parse id-claim from the trust mark", e);
         }
-        return false;
+        return null;
     }
 }
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/RelyingPartyTrustChainContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/RelyingPartyTrustChainContext.java
index 37f0a031..8a6ff150 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/RelyingPartyTrustChainContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/RelyingPartyTrustChainContext.java
@@ -23,6 +23,7 @@ import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.BaseContext;
 
+import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
 
@@ -50,6 +51,9 @@ public final class RelyingPartyTrustChainContext extends BaseContext {
     /** Verified trust mark IDs for the selected trust chain. */
     @Nullable private Map<String, List<String>> verifiedTrustMarkIds;
 
+    /** Verified trust marks for the selected trust chain. */
+    @Nullable private Map<String, List<SignedJWT>> verifiedTrustMarks;
+
     /** All previously selected but rejected trust chains. */
     @Nullable private List<List<EntityStatement>> rejectedTrustChains;
 
@@ -162,6 +166,28 @@ public final class RelyingPartyTrustChainContext extends BaseContext {
         return this;
     }
 
+    /**
+     * Get the verified trust marks for the selected trust chain.
+     * 
+     * @return verified trust marks
+     */
+    @Nullable public Map<String, List<SignedJWT>> getVerifiedTrustMarks() {
+        return verifiedTrustMarks;
+    }
+
+    /**
+     * Set the verified trust marks for the selected trust chain.
+     * 
+     * @param trustmarks verified trust marks
+     * 
+     * @return this context
+     */
+    @Nonnull public RelyingPartyTrustChainContext setVerifiedTrustMarks(
+            @Nullable final Map<String, List<SignedJWT>> trustMarks) {
+        verifiedTrustMarks = trustMarks;
+        return this;
+    }
+
     /**
      * Get the previously selected but rejected trust chains for the relying party.
      * 
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ResolveTrustMarks.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ResolveTrustMarks.java
index ac8b9712..34d729fb 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ResolveTrustMarks.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ResolveTrustMarks.java
@@ -22,6 +22,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -243,7 +244,7 @@ public class ResolveTrustMarks extends AbstractProfileAction {
             return;
         }
 
-        final Map<String, List<String>> verifiedTrustMarks = new HashMap<>();
+        final Map<String, List<SignedJWT>> verifiedTrustMarks = new HashMap<>();
         for (final EntityStatement statement : selectedTrustChain) {
             final List<SignedJWT> trustMarks = chainTrustMarks.get(statement.getEntityID().getValue());
             if (trustMarks == null || trustMarks.isEmpty()) {
@@ -254,12 +255,16 @@ public class ResolveTrustMarks extends AbstractProfileAction {
                     trustMarks.stream()
                         .filter(entry -> checkTrustedIssuer(entry))
                         .filter(entry -> verifyTrustMark(entry))
-                        .map(entry -> getTrustMarkId(entry))
                         .filter(Objects::nonNull)
                         .toList());
         }
-        log.debug("{} The following trust marks are validated: {}", getLogPrefix(), verifiedTrustMarks);
-        trustChainContext.setVerifiedTrustMarkIds(verifiedTrustMarks);
+        trustChainContext.setVerifiedTrustMarks(verifiedTrustMarks);
+        final Map<String, List<String>> verifiedTrustMarkIds = verifiedTrustMarks.entrySet().stream()
+                .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue().stream()
+                        .map(list -> getTrustMarkId(list))
+                        .toList()));
+        log.debug("{} The following trust marks are validated: {}", getLogPrefix(), verifiedTrustMarkIds);
+        trustChainContext.setVerifiedTrustMarkIds(verifiedTrustMarkIds);
     }
 
     /**
@@ -351,7 +356,7 @@ public class ResolveTrustMarks extends AbstractProfileAction {
      */
     @Nullable private String getTrustMarkId(@Nullable final SignedJWT trustMark) {
         try {
-            return trustMark == null ? null : trustMark.getJWTClaimsSet().getStringClaim("id");
+            return trustMark == null ? null : trustMark.getJWTClaimsSet().getStringClaim("trust_mark_id");
         } catch (final ParseException e) {
             log.error("{} Could not parse the TrustMark JWT contents", getLogPrefix(), e);
         }

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


More information about the commits mailing list