[java-oidfed-common] 03/03: Update trust mark details output for the test-resolution admin flow

Codeberg noreply at shibboleth.net
Thu Jun 4 14:13:08 UTC 2026


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

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

View the commit online:
https://codeberg.org/Shibboleth/java-oidfed-common/commit/0647a5b12abbc925668ae960edd27919bd43ed7f

commit 0647a5b12abbc925668ae960edd27919bd43ed7f
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Jun 4 17:12:36 2026 +0300

    Update trust mark details output for the test-resolution admin flow
    
    - If includeTrustMark flag is set, the output contains iss/sub/iat/exp/type details in addition to the raw JWT
    - Also improved flow testincludeTrustMark
---
 .../test-trust-chain-resolution-beans.xml          |   3 +-
 .../admin/oidfed/test-trust-chain-resolution.vm    |   9 +-
 .../flow/TestTrustChainResolutionFlowTest.java     | 134 ++++++++++++++++++++-
 3 files changed, 139 insertions(+), 7 deletions(-)

diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml
index 7a3d6ac..69f5ebe 100644
--- a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml
@@ -61,7 +61,8 @@
         p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine"
         p:delegationTrustEngine-ref="shibboleth.oidfed.DefaultDelegatedTrustMarkTrustEngine">
         <property name="trustChainTrustMarksParsingStrategy">
-            <bean class="net.shibboleth.oidfed.profile.navigate.DefaultTrustChainTrustMarksParsingStrategy"/>
+            <bean class="net.shibboleth.oidfed.profile.navigate.DefaultTrustChainTrustMarksParsingStrategy"
+                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper"/>
         </property>
         <property name="trustedTrustMarkIssuersLookupStrategy">
             <bean class="net.shibboleth.oidfed.profile.navigate.DefaultTrustChainTrustedTrustMarkIssuersLookupStrategy"/>
diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm
index 0d8017d..30a7949 100644
--- a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm
@@ -55,7 +55,14 @@
         ]#if($includeTrustMark),
         "trust_mark_details" : [
 #foreach ($trustMark in $trustMarks.get($index - 1))
-            "$trustMark.serialize()"#if( $foreach.hasNext ),#end
+            {
+                "trust_mark_type": "$trustMark.getParsedPayload().getTrustMarkType()",
+                "issuer": "$trustMark.getIssuer()",
+                "subject" : "$trustMark.getParsedPayload().getSubject()",
+                "issuedAt" : "$trustMark.getParsedPayload().getIssuedAt()",
+                "expiresAt" : "$trustMark.getParsedPayload().getExpiration()",
+                "rawJwt" : "$trustMark.getJwt().serialize()"
+            }#if( $foreach.hasNext ),#end
 #end
         ]#end
     }#if( $foreach.hasNext ),#end
diff --git a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java
index 0a750e6..eccc979 100644
--- a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java
+++ b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java
@@ -91,16 +91,122 @@ public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest
         assertResponseArraySize(0);
     }
 
-    /**
-     * Test the flow without any parameters.
-     * 
-     * @throws Exception if an error occurs
-     */
     @Test
     public void testWithOnlyEntityIDParameter() throws Exception {
         request.setMethod("GET");
         final String entityId = super.uniqueClientId();
         request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setRedirectionURI(new URI(redirectUri));
+        metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+
+        final String rpEntityConfiguration = rpEntityConfiguration(entityId, metadata, List.of(Map.of(
+                "trust_mark_type", "https://example.org/email-allowing-trust-mark",
+                "trust_mark", trustMark)), leafKey);
+        rpConfigureMockHttpClient(entityId, rpEntityConfiguration);
+        try {
+            mapResponse(entityConfigurationUrl(trustMarkIssuerId),
+                    mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
+                    mockResponse(subordinateStatement(trustMarkIssuerId,
+                            Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
+            mapResponse(trustMarkStatusEndpoint, mockResponse(200, "application/trust-mark-status-response+jwt",
+                    trustMarkStatusResponse(trustMarkIssuerId, trustMark, "active", trustMarkIssuerKey)));
+        } catch (UnsupportedOperationException | IOException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+
+        final FlowExecutionOutcome outcome = result.getOutcome();
+        assertEquals(outcome.getId(), "ResponseView");
+        assertResponseArraySize(1);
+    }
+
+    @Test
+    public void testWithTrustMarkDetailsParameterNullStatusNoValidationRequired() throws Exception {
+        request.setMethod("GET");
+        final String entityId = super.uniqueClientId();
+        request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setRedirectionURI(new URI(redirectUri));
+        metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+
+        final String rpEntityConfiguration = rpEntityConfiguration(entityId, metadata, List.of(Map.of(
+                "trust_mark_type", "https://example.org/email-allowing-trust-mark",
+                "trust_mark", trustMark)), leafKey);
+        rpConfigureMockHttpClient(entityId, rpEntityConfiguration);
+        try {
+            mapResponse(entityConfigurationUrl(trustMarkIssuerId),
+                    mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
+                    mockResponse(subordinateStatement(trustMarkIssuerId,
+                            Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
+        } catch (UnsupportedOperationException | IOException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+
+        final FlowExecutionOutcome outcome = result.getOutcome();
+        assertEquals(outcome.getId(), "ResponseView");
+        assertResponseArraySize(1);
+        assertTrustMarkDetails(1);
+    }
+
+    @Test
+    public void testWithTrustMarkDetailsParameterInvalidStatusRemoteValidationRequired() throws Exception {
+        request.setMethod("GET");
+        final String entityId = super.uniqueClientId();
+        request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+        request.addParameter("remoteTrustMarkValidation", "true");
+
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setRedirectionURI(new URI(redirectUri));
+        metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+
+        final String rpEntityConfiguration = rpEntityConfiguration(entityId, metadata, List.of(Map.of(
+                "trust_mark_type", "https://example.org/email-allowing-trust-mark",
+                "trust_mark", trustMark)), leafKey);
+        rpConfigureMockHttpClient(entityId, rpEntityConfiguration);
+        try {
+            mapResponse(entityConfigurationUrl(trustMarkIssuerId),
+                    mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
+                    mockResponse(subordinateStatement(trustMarkIssuerId,
+                            Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
+            mapResponse(trustMarkStatusEndpoint, mockResponse(200, "application/trust-mark-status-response+jwt",
+                    trustMarkStatusResponse(trustMarkIssuerId, trustMark, "invalid", trustMarkIssuerKey)));
+        } catch (UnsupportedOperationException | IOException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+
+        final FlowExecutionOutcome outcome = result.getOutcome();
+        assertEquals(outcome.getId(), "ResponseView");
+        assertResponseArraySize(1);
+        assertTrustMarkDetails(0);
+    }
+
+    @Test
+    public void testWithTrustMarkDetailsParameterValidStatusRemoteValidationRequired() throws Exception {
+        request.setMethod("GET");
+        final String entityId = super.uniqueClientId();
+        request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+        request.addParameter("remoteTrustMarkValidation", "true");
 
         final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
                 entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
@@ -129,6 +235,7 @@ public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest
         final FlowExecutionOutcome outcome = result.getOutcome();
         assertEquals(outcome.getId(), "ResponseView");
         assertResponseArraySize(1);
+        assertTrustMarkDetails(1);
     }
 
     protected void assertResponseArraySize(final int expected) {
@@ -139,4 +246,21 @@ public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest
             Assert.fail("Could not deserialize response", e);
         }
     }
+
+    protected void assertTrustMarkDetails(final int expected) {
+        final ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            final List<?> rootArray = objectMapper.readValue(response.getContentAsString(), List.class);
+            if (rootArray.get(0) instanceof Map<?,?> map) {
+                if (map.get("trust_mark_details") instanceof List<?> details) {
+                    Assert.assertEquals(details.size(), expected);
+                    return;
+                }
+            }
+        } catch (JsonProcessingException | UnsupportedEncodingException e) {
+            Assert.fail("Could not deserialize response", e);
+        }
+        Assert.fail("Unexpected trust_mark_details");
+    }
+
 }

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


More information about the commits mailing list