[java-oidfed-common] branch main updated: Improve testing of metadata policies and trust marks

Codeberg noreply at shibboleth.net
Wed Sep 30 11:11:13 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/251b6ff9b0459a5327399c88d37836761bc2f870

The following commit(s) were added to refs/heads/main by this push:
     new 251b6ff  Improve testing of metadata policies and trust marks
251b6ff is described below

commit 251b6ff9b0459a5327399c88d37836761bc2f870
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Sep 30 14:10:38 2026 +0300

    Improve testing of metadata policies and trust marks
    
    - Wire the metadata policy test vectors for the resolve-entity flow
    - Included negative tests for trust marks (including delegated)
---
 .../META-INF/net.shibboleth.idp/postconfig.xml     |   6 +
 .../oidfed/flow/AbstractFederationFlowTest.java    |  24 ++-
 .../oidfed/flow/ResolveEntityFlowTest.java         |  79 ++++++++
 .../flow/TestTrustChainResolutionFlowTest.java     | 210 ++++++++++++++++++++-
 .../flow/cache/SignedKeysetMetadataCacheTest.java  |   2 +-
 5 files changed, 316 insertions(+), 5 deletions(-)

diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index d5c5b82..b2d7aac 100644
--- a/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -1190,6 +1190,12 @@
                     </key>
                     <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_metadata" c:_1="Metadata is invalid or not found for the requested entity types" c:_2="400" />
                 </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.INVALID_METADATA_POLICY"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_metadata" c:_1="Merged metadata policy is invalid for the requested entity types" c:_2="400" />
+                </entry>
                 <entry>
                     <key>
                         <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.INVALID_METADATA_AGAINST_POLICY"/>
diff --git a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/AbstractFederationFlowTest.java b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/AbstractFederationFlowTest.java
index 873ba6a..4e96698 100644
--- a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/AbstractFederationFlowTest.java
+++ b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/AbstractFederationFlowTest.java
@@ -72,7 +72,6 @@ import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.PlainJWT;
 import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.ErrorResponse;
-import com.nimbusds.oauth2.sdk.ParseException;
 import com.nimbusds.oauth2.sdk.Response;
 import com.nimbusds.oauth2.sdk.id.Issuer;
 import com.nimbusds.openid.connect.sdk.SubjectType;
@@ -327,6 +326,25 @@ public class AbstractFederationFlowTest extends AbstractFlowTest {
         return FederationJwtSupport.entityStatement(JWSAlgorithm.RS256, leafKey, builder.build()).serialize();
     }
 
+    protected String rpEntityConfiguration(final String clientId, final Map<String, Object> metadata,
+            final List<Map<String, String>> trustMarks, final List<String> crit, final JWK leafKey,
+            final String... authorityHints) throws URISyntaxException {
+        final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().issuer(clientId).subject(clientId)
+                .issueTime(Date.from(Instant.now()))
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)))
+                .claim("jwks", new JWKSet(leafKey).toJSONObject(true))
+                .claim("metadata", Map.of("openid_relying_party", new JSONObject(metadata)))
+                .claim("authority_hints", authorityHints == null || authorityHints.length == 0 ?
+                        new String[] { anchorId } : authorityHints);
+        if (trustMarks != null) {
+            builder.claim("trust_marks", trustMarks);
+        }
+        if (crit != null) {
+            builder.claim("crit", crit);
+        }
+        return FederationJwtSupport.entityStatement(JWSAlgorithm.RS256, leafKey, builder.build()).serialize();
+    }
+
     protected String rpEntityConfigurationUnmatchingKey(final String clientId,
             final OIDCClientMetadata metadata, final String... authorityHints) throws URISyntaxException {
         final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().issuer(clientId).subject(clientId)
@@ -639,7 +657,7 @@ public class AbstractFederationFlowTest extends AbstractFlowTest {
                 metadata.put("jwks", new JWKSet(rpKey.toPublicJWK()).toJSONObject());
                 mapResponse(entityConfigurationUrl(clientId),
                         mockResponse(rpEntityConfiguration(clientId,
-                                OIDCClientMetadata.parse(new JSONObject(metadata)), intermediateId)));
+                                new JSONObject(metadata), null, null, leafKey, intermediateId)));
             }
             mapResponse(entityConfigurationUrl(intermediateId), mockResponse(intermediateConfiguration(intermediateId)));
             mapResponse(entityConfigurationUrl(anchorId), mockResponse(trustedAnchorConfiguration()));
@@ -650,7 +668,7 @@ public class AbstractFederationFlowTest extends AbstractFlowTest {
                     mockResponse(rpSubordinateStatement(intermediateId, intermediateKey, leafKey, clientId,
                             Map.of("openid_relying_party", (Map<String, Object>) testVector.get("INT")),
                             intermediateId)));
-        } catch (UnsupportedOperationException | IOException | URISyntaxException | ParseException e) {
+        } catch (UnsupportedOperationException | IOException | URISyntaxException e) {
             Assert.fail("Could not initialize mock HTTP client", e);
         }
     }
diff --git a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/ResolveEntityFlowTest.java b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/ResolveEntityFlowTest.java
index 299e483..a096414 100644
--- a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/ResolveEntityFlowTest.java
+++ b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/ResolveEntityFlowTest.java
@@ -20,6 +20,7 @@ import java.net.URISyntaxException;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.RSAPrivateKey;
 import java.time.Instant;
+import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -53,7 +54,11 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
 import net.shibboleth.oidfed.messaging.impl.ResolveEntityResponse;
 import net.shibboleth.oidfed.metadata.EntityStatement;
 import net.shibboleth.oidfed.metadata.impl.SubordinateStatementImpl;
+import net.shibboleth.oidfed.metadata.payload.claim.Metadata;
+import net.shibboleth.oidfed.profile.context.RelyingPartyTrustChainContext;
+import net.shibboleth.oidfed.profile.context.VerifiedTrustChain;
 import net.shibboleth.oidfed.testing.FederationJwtSupport;
+import net.shibboleth.oidfed.testing.FederationMetadataPolicyTestingSupport;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.minidev.json.JSONObject;
 
@@ -463,6 +468,80 @@ public class ResolveEntityFlowTest extends AbstractFederationFlowTest {
         assertErrorCode(result, "invalid_client");
     }
 
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testWithMetadataPolicyTestVectors() throws Exception {
+        final List<Map<String, Object>> vectors = FederationMetadataPolicyTestingSupport.loadPolicyTestVectors();
+        for (final Map<String, Object> vector : vectors) {
+            initializeMocks();
+            initializeThreadLocals();
+            final String clientId = uniqueClientId();
+            rpConfigureMockHttpClient(clientId, vector);
+
+            request.setMethod("GET");
+            request.setQueryString("sub=" + clientId + "&trust_anchor=" + anchorId + "&entity_type=openid_relying_party");
+            final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+
+            final String ERROR_MESSAGE = "Unexpected result with test vector " + vector.get("n");
+            if (vector.get("error") instanceof String error) {
+                assertErrorCode(result, "invalid_metadata", ERROR_MESSAGE);
+                if ("invalid_policy".equals(error)) {
+                    assertErrorDescriptionContains(result, "Merged metadata policy is invalid", ERROR_MESSAGE);
+                } else {
+                    assertErrorDescriptionContains(result, "Metadata is invalid or not found for the requested entity "
+                            + "types against the fedeationn metadata policy", ERROR_MESSAGE);
+                }
+            } else {
+                if (vector.get("resolved") instanceof Map<?,?> map) {
+                    final Map<String, Object> metadata = (Map<String, Object>) vector.get("metadata");
+                    final Map<String, Object> resolved = (Map<String, Object>) map;
+
+                    final ResolveEntityResponse parsedResponse =
+                            parseSuccessResponse(result, ResolveEntityResponse.class);
+                    final SignedJWT response = parsedResponse.getJWT();
+                    Assert.assertEquals(response.getHeader().getType(), new JOSEObjectType("resolve-response+jwt"),
+                            ERROR_MESSAGE);
+                    Assert.assertEquals(response.getJWTClaimsSet().getSubject(), clientId, ERROR_MESSAGE);
+                    Assert.assertNotNull(response.getJWTClaimsSet().getClaim("metadata"), ERROR_MESSAGE);
+                    Assert.assertNull(response.getJWTClaimsSet().getClaim("authority_hints"), ERROR_MESSAGE);
+
+                    final ProfileRequestContext prc =
+                            (ProfileRequestContext)request.getAttribute(ProfileRequestContext.BINDING_KEY);
+                    assert prc != null;
+                    final VerifiedTrustChain selectedChain = prc.ensureInboundMessageContext()
+                            .ensureSubcontext(RelyingPartyTrustChainContext.class).getSelectedTrustChain();
+                    assert selectedChain != null;
+                    final Metadata enforcedMetadata = selectedChain.getMetadata();
+                    assert enforcedMetadata != null;
+                    final Map<String, Object> rpMetadata = enforcedMetadata.getOpenidRelyingPartyMetadata();
+                    assert rpMetadata != null;
+                    for (final String claim : metadata.keySet()) {
+                        final Object actual = rpMetadata.get(claim);
+                        if (resolved.get(claim) instanceof Boolean flag) {
+                            if (flag) {
+                                Assert.assertEquals(actual, flag, ERROR_MESSAGE);
+                            } else {
+                                Assert.assertTrue(actual == null || !((boolean) actual), ERROR_MESSAGE);
+                            }
+                        } else if (resolved.get(claim) instanceof Collection<?> collection) {
+                            final Collection<String> expectedStrings = collection.stream()
+                                    .map(String.class::cast).toList();
+                            final Collection<String> actualStrings = ((Collection<?>) actual).stream()
+                                    .map(String.class::cast).toList();
+                            Assert.assertTrue(expectedStrings.containsAll(actualStrings));
+                            Assert.assertTrue(actualStrings.containsAll(expectedStrings));
+                        } else {
+                            Assert.assertEquals(actual, resolved.get(claim), ERROR_MESSAGE);
+
+                        }
+                    }
+                } else {
+                    Assert.fail(ERROR_MESSAGE);
+                }
+            }
+        }
+    }
+
     protected Response parseResponse(final FlowExecutionResult result) {
         assertFlowExecutionOutcome(result.getOutcome(), END_STATE_ID);
         final ProfileRequestContext prc = retrieveProfileRequestContext(result);
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 6df45eb..e18acbb 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
@@ -34,6 +34,7 @@ import org.testng.annotations.Test;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.JWK;
 import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
@@ -99,7 +100,6 @@ public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest
         request.setMethod("GET");
         final String entityId = super.uniqueClientId();
         request.addParameter("entityID", entityId);
-        request.addParameter("includeTrustMark", "true");
 
         final String trustMark = FederationJwtSupport.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
                 entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
@@ -130,6 +130,95 @@ public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest
         assertResponseArraySize(1);
     }
 
+    @Test
+    public void testWithTrustMarkDetailsParameter_expiredTrustMark() throws Exception {
+        final String entityId = super.uniqueClientId();
+        final String trustMark = FederationJwtSupport.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().minusSeconds(300)).serialize();
+        testWithInvalidTrustMark(entityId, trustMark);
+    }
+
+    @Test
+    public void testWithTrustMarkDetailsParameter_wrongTrustMarkSignature() throws Exception {
+        final String entityId = super.uniqueClientId();
+        final String trustMark = FederationJwtSupport.trustMark(JWSAlgorithm.RS256, leafKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        testWithInvalidTrustMark(entityId, trustMark);
+    }
+
+    @Test
+    public void testWithTrustMarkDetailsParameter_untrustedTrustMarkIssuer() throws Exception {
+        final String entityId = super.uniqueClientId();
+        final String trustMark = FederationJwtSupport.trustMark(JWSAlgorithm.RS256, trustedAnchorKey, anchorId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        testWithInvalidTrustMark(entityId, trustMark);
+    }
+
+    protected void testWithInvalidTrustMark(final String entityId, final String trustMark) throws Exception {
+        request.setMethod("GET");
+        request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+
+        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(0);
+    }
+
+    @Test
+    public void testWithTrustMarkDetailsParameter_unmatchingTrustMarkType() throws Exception {
+        request.setMethod("GET");
+        final String entityId = super.uniqueClientId();
+        request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+
+        final String trustMark = FederationJwtSupport.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-wrong",
+                "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(0);
+    }
+
     @Test
     public void testWithTrustMarkDetailsParameterNullStatusNoValidationRequired() throws Exception {
         request.setMethod("GET");
@@ -303,6 +392,125 @@ public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest
         assertTrustMarkDetails(2);
     }
 
+    @Test
+    public void testWithTwoTrustMarkDetailsParameterValidStatusRemoteValidationRequired_invalidDelegationIss()
+            throws Exception {
+        final String entityId = super.uniqueClientId();
+        final JWTClaimsSet.Builder delegationBuilder = new JWTClaimsSet.Builder()
+                .issuer("https://untrusted-delegated-issuer.federation.local")
+                .subject(trustMarkIssuerId)
+                .claim("trust_mark_type", delegatedTrustMarkType)
+                .issueTime(new Date())
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)));
+        testWithInvalidDelegatedTrustMark(entityId, delegationBuilder, trustMarkIssuerKey);
+    }
+
+    @Test
+    public void testWithTwoTrustMarkDetailsParameterValidStatusRemoteValidationRequired_invalidDelegationSub()
+            throws Exception {
+        final String entityId = super.uniqueClientId();
+        final JWTClaimsSet.Builder delegationBuilder = new JWTClaimsSet.Builder()
+                .issuer(delegatedTrustMarkIssuerId)
+                .subject(entityId)
+                .claim("trust_mark_type", delegatedTrustMarkType)
+                .issueTime(new Date())
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)));
+        testWithInvalidDelegatedTrustMark(entityId, delegationBuilder, trustMarkIssuerKey);
+    }
+
+    @Test
+    public void testWithTwoTrustMarkDetailsParameterValidStatusRemoteValidationRequired_invalidDelegationExp()
+            throws Exception {
+        final String entityId = super.uniqueClientId();
+        final JWTClaimsSet.Builder delegationBuilder = new JWTClaimsSet.Builder()
+                .issuer(delegatedTrustMarkIssuerId)
+                .subject(trustMarkIssuerId)
+                .claim("trust_mark_type", delegatedTrustMarkType)
+                .issueTime(new Date())
+                .expirationTime(Date.from(Instant.now().minusSeconds(300)));
+        testWithInvalidDelegatedTrustMark(entityId, delegationBuilder, trustMarkIssuerKey);
+    }
+
+    @Test
+    public void testWithTwoTrustMarkDetailsParameterValidStatusRemoteValidationRequired_invalidDelegationType()
+            throws Exception {
+        final String entityId = super.uniqueClientId();
+        final JWTClaimsSet.Builder delegationBuilder = new JWTClaimsSet.Builder()
+                .issuer(delegatedTrustMarkIssuerId)
+                .subject(trustMarkIssuerId)
+                .claim("trust_mark_type", "https://trust-mark-example.federation.local/unmatching-delegated")
+                .issueTime(new Date())
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)));
+        testWithInvalidDelegatedTrustMark(entityId, delegationBuilder, trustMarkIssuerKey);
+    }
+
+    @Test
+    public void testWithTwoTrustMarkDetailsParameterValidStatusRemoteValidationRequired_invalidDelegationSignature()
+            throws Exception {
+        final String entityId = super.uniqueClientId();
+        final JWTClaimsSet.Builder delegationBuilder = new JWTClaimsSet.Builder()
+                .issuer(delegatedTrustMarkIssuerId)
+                .subject(trustMarkIssuerId)
+                .claim("trust_mark_type", delegatedTrustMarkType)
+                .issueTime(new Date())
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)));
+        testWithInvalidDelegatedTrustMark(entityId, delegationBuilder, trustedAnchorKey);
+    }
+
+    protected void testWithInvalidDelegatedTrustMark(final String entityId,
+            final JWTClaimsSet.Builder delegationBuilder, final JWK signingKey) throws Exception {
+        request.setMethod("GET");
+        request.addParameter("entityID", entityId);
+        request.addParameter("includeTrustMark", "true");
+        request.addParameter("remoteTrustMarkValidation", "true");
+
+        final String trustMark = FederationJwtSupport.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 JWTClaimsSet.Builder trustMarkBuilder = new JWTClaimsSet.Builder()
+                .subject(entityId)
+                .issuer(trustMarkIssuerId)
+                .claim("trust_mark_type", delegatedTrustMarkType)
+                .claim("delegation", FederationJwtSupport.trustMarkDelegation(
+                        JWSAlgorithm.RS256, TestFederationCredentials.delegatedTrustMarkOwnerKey(),
+                        delegationBuilder.build()).serialize())
+                .issueTime(new Date())
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)));
+        final String trustMark2 = FederationJwtSupport.trustMark(
+                JWSAlgorithm.RS256, signingKey, trustMarkBuilder.build()).serialize();
+
+        final String rpEntityConfiguration = rpEntityConfiguration(entityId, metadata, List.of(
+                Map.of("trust_mark_type", "https://example.org/email-allowing-trust-mark",
+                        "trust_mark", trustMark),
+                Map.of("trust_mark_type", delegatedTrustMarkType,
+                        "trust_mark", trustMark2)), 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)));
+            mapResponses(trustMarkStatusEndpoint,
+                    mockResponse(200, "application/trust-mark-status-response+jwt",
+                            trustMarkStatusResponse(trustMarkIssuerId, trustMark, "active", trustMarkIssuerKey)),
+                    mockResponse(200, "application/trust-mark-status-response+jwt",
+                            trustMarkStatusResponse(trustMarkIssuerId, trustMark2, "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);
+        assertTrustMarkDetails(1);
+    }
+
     protected void assertResponseArraySize(final int expected) {
         final ObjectMapper objectMapper = new ObjectMapper();
         try {
diff --git a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/cache/SignedKeysetMetadataCacheTest.java b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/cache/SignedKeysetMetadataCacheTest.java
index 624ccdf..f75c980 100644
--- a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/cache/SignedKeysetMetadataCacheTest.java
+++ b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/cache/SignedKeysetMetadataCacheTest.java
@@ -197,7 +197,7 @@ public class SignedKeysetMetadataCacheTest extends AbstractFederationFlowTest {
         metadata.setCustomField("signed_jwks_uri", signedJwksUri);
         final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().issuer(entityId).subject(entityId)
                 .issueTime(Date.from(Instant.now()))
-                .expirationTime(Date.from(Instant.now().minusSeconds(300)))
+                .expirationTime(Date.from(Instant.now().plusSeconds(300)))
                 .claim("keys", new JWKSet(rpKey).toJSONObject(true).get("keys"));
         final String signedKeyset = FederationJwtSupport.signedJwt(
                 JWSAlgorithm.RS256, rpKey, "jwk-set+jwt", builder.build()).serialize();

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


More information about the commits mailing list