[java-idp-plugin-oidc-op-oidfed] 02/02: Refactored the federation constraints to allow modification of statements

Codeberg noreply at shibboleth.net
Thu Jan 22 17:41:51 UTC 2026


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

codeberg pushed a commit to branch dev/CACHE-REFACTOR
in repository java-idp-plugin-oidc-op-oidfed.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-oidc-op-oidfed/commit/76756ae0fa8474f852d3f9512cb7e205a740dcf9

commit 76756ae0fa8474f852d3f9512cb7e205a740dcf9
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Jan 22 19:41:20 2026 +0200

    Refactored the federation constraints to allow modification of statements
    
    - Moved constraint enforcement from trust chain cache fetcihng part into SWF actions
      - AbstractTrustChainResolutionAction serves ResolveTrustChains and ValidateProvidedTrustChain
    - The 'allowed_entity_types' may need to remove metadata for specific entity types
      - The trust chain handed to FederationPolicyConstraint.validate(..) is marked with @Live-annotation
---
 ...mbinedMetadataFromTrustChainLookupStrategy.java |  2 +-
 ...efaultProvidedTrustChainValidationStrategy.java | 11 ---
 .../DefaultTrustChainFetchingStrategy.java         | 31 ---------
 .../constraints/FederationPolicyConstraint.java    | 13 ++--
 .../FederationPolicyConstraintHelper.java          | 53 ++++++++-------
 .../impl/AbstractFederationPolicyConstraint.java   |  7 +-
 .../impl/DefaultAllowedEntityTypesConstraint.java  | 58 +++++++++++++++-
 .../impl/DefaultMaxPathLengthConstraint.java       | 16 +++--
 .../impl/DefaultNamingConstraintsConstraint.java   |  5 ++
 .../impl/AbstractTrustChainResolutionAction.java   | 78 ++++++++++++++++++++--
 .../oidfed/profile/impl/OidFederationEventIds.java |  6 ++
 .../profile/impl/ValidateProvidedTrustChain.java   |  2 +-
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  3 +-
 .../oidfed/metadata-lookup-ext-oidfed-beans.xml    |  3 +-
 .../oidfed/metadata-lookup-ext-oidfed-flow.xml     |  2 +
 .../idp/flows/oidfed/register/register-beans.xml   |  9 +--
 .../oidfed/resolve-entity/resolve-entity-beans.xml |  3 +-
 .../DefaultTrustChainFetchingStrategyTest.java     | 22 +-----
 .../profile/flow/oidfed/RegistrationFlowTest.java  | 17 +++++
 19 files changed, 223 insertions(+), 118 deletions(-)

diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultCombinedMetadataFromTrustChainLookupStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultCombinedMetadataFromTrustChainLookupStrategy.java
index 19fc945..9bc61c9 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultCombinedMetadataFromTrustChainLookupStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultCombinedMetadataFromTrustChainLookupStrategy.java
@@ -57,7 +57,7 @@ public class DefaultCombinedMetadataFromTrustChainLookupStrategy extends Abstrac
                 .map(metadata -> metadata.getAllClaims()).orElse(null);
 
         if (configurationMetadata == null || configurationMetadata.isEmpty()) {
-            log.error("Entity configuration for {} doesn't contain metadata", chain.get(0).getSubject());
+            log.debug("Entity configuration for {} doesn't contain metadata", chain.get(0).getSubject());
             return null;
         }
 
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultProvidedTrustChainValidationStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultProvidedTrustChainValidationStrategy.java
index fc38022..2580a24 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultProvidedTrustChainValidationStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultProvidedTrustChainValidationStrategy.java
@@ -27,7 +27,6 @@ import org.slf4j.Logger;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraint;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraintHelper;
 import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
@@ -114,16 +113,6 @@ public class DefaultProvidedTrustChainValidationStrategy extends AbstractIdentif
             log.debug("The trust chain did not pass the signature validation");
             return false;
         }
-        for (int i = 1; i < trustChain.size() - 1; i++) {
-            final List<EntityStatement<?>> subChain = trustChain.subList(0, i);
-            assert subChain != null;
-            if (!FederationPolicyConstraintHelper.verifyPolicyConstraints(
-                    trustChain.get(i), subChain, getFederationPolicyConstraints())) {
-                log.debug("Subordinate statement {} policy constraints validation failed",
-                        trustChain.get(i).getSubject());
-                return false;
-            }
-        }
 
         return true;
     }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategy.java
index 6fed233..14f72f6 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategy.java
@@ -37,8 +37,6 @@ import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.RemoteEnti
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.RemoteSubordinateStatementContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.RemoteTrustChainsContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.SubjectEntityStatementCriterion;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraint;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraintHelper;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.util.EntityStatementHelper;
 import net.shibboleth.oidc.metadata.cache.MetadataCache;
 import net.shibboleth.oidc.metadata.cache.MetadataCacheException;
@@ -78,9 +76,6 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
     /** Cache containing local copies of trusted trust anchor keys. */
     @NonnullAfterInit private MetadataCache<Map<String, LocalKeyContainer>> localTrustAnchorsCache;
 
-    /** Map of supported federation policy constraints. */
-    @NonnullAfterInit private Map<String, FederationPolicyConstraint> federationPolicyConstraints;
-
     /** Strategy to fetch lifetime for container with valid contents. */
     @NonnullAfterInit private Function<CriteriaSet, Duration> criteriaToValidContainerLifetimeStrategy;
 
@@ -128,27 +123,6 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
         localTrustAnchorsCache = Constraint.isNotNull(cache, "Local Trust Anchor cache cannot be null");
     }
 
-    /**
-     * Set the map of supported federation policy constraints.
-     * 
-     * @param constraints map of supported federation policy constraints.
-     */
-    public void setFederationPolicyConstraints(@Nonnull final Map<String, FederationPolicyConstraint> constraints) {
-        checkSetterPreconditions();
-        federationPolicyConstraints = Constraint.isNotNull(constraints, "Map of policy constraints cannot be null");
-    }
-
-    /**
-     * Get the map of supported federation policy constraints.
-     * 
-     * @return map of supported federation policy constraints.
-     */
-    @Nonnull public Map<String, FederationPolicyConstraint> getFederationPolicyConstraints() {
-        checkComponentActive();
-        assert federationPolicyConstraints != null;
-        return federationPolicyConstraints;
-    }
-
     /**
      * Set the strategy to fetch lifetime for container with valid contents.
      * 
@@ -190,9 +164,6 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
         if (localTrustAnchorsCache == null) {
             throw new ComponentInitializationException("Local Trust Anchor cache cannot be null");
         }
-        if (federationPolicyConstraints == null) {
-            throw new ComponentInitializationException("Map of policy constraints cannot be null");
-        }
         if (criteriaToValidContainerLifetimeStrategy == null) {
             throw new ComponentInitializationException("Criteria to valid container lifetime strategy cannot be null");
         }
@@ -324,8 +295,6 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
                         .filter(id -> !EntityStatementHelper.subjectAlreadyExists(id, chain))
                         .map(id -> fetchAuthority(entityStatement, id))
                         .filter(pair -> pair != null && pair.getFirst() != null && pair.getSecond() != null)
-                        .filter(pair -> FederationPolicyConstraintHelper.verifyPolicyConstraints(
-                                pair.getSecond(), chain, getFederationPolicyConstraints()))
                         .toList();
                 hints = !authorities.isEmpty();
                 authorities.forEach(authority -> {
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraint.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraint.java
index 5bb1f95..f8348ed 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraint.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraint.java
@@ -20,6 +20,8 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubordinateStatement;
+import net.shibboleth.shared.annotation.constraint.Live;
 
 /**
  * Interface to be implemented by the federation policy constraints.
@@ -27,11 +29,14 @@ import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
 public interface FederationPolicyConstraint {
 
     /**
-     * Validate whether the given trust chain meets given federation policy constraint value,
+     * Validate whether the given trust chain meets given federation policy constraint value. The trust chain may be
+     * modified by the constraint validators, thus it is required to be modifiable.
      * 
      * @param constraint the constraint value
-     * @param trustChain trust chain to be evaluated
-     * @return true if the trust chain is valid for this constraint, false otherwise.
+     * @param subordinateStatement subordinate statement that defined the constraint
+     * @param trustChain trust chain to be evaluated and optionally updated: it is required to be modifiable
+     * @return true if the trust chain is valid for this constraint, false otherwise
      */
-    public boolean validate(@Nullable final Object constraint, @Nonnull final List<EntityStatement<?>> trustChain);
+    public boolean validate(@Nullable final Object constraint, @Nonnull final SubordinateStatement subordinateStatement,
+            @Nonnull @Live final List<EntityStatement<?>> trustChain);
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraintHelper.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraintHelper.java
index 75aece5..3c9d8e5 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraintHelper.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/FederationPolicyConstraintHelper.java
@@ -18,12 +18,12 @@ import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.SubordinateStatementPayload;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubordinateStatement;
+import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
@@ -35,38 +35,41 @@ public class FederationPolicyConstraintHelper {
     @Nonnull private final static Logger log = LoggerFactory.getLogger(FederationPolicyConstraintHelper.class);
 
     /**
-     * Parses and verifies federation policy constraints set in the given subordinates statement against the given
-     * trust chain.
+     * Parses and verifies federation policy constraints in the given trust chain. Optionally the changed values
+     * (for instance with the 'allowed_entity_types' constraint) are enforced to the trust chain.
      * 
-     * @param subordinateStatement subordinate statement containing the constraints
-     * @param trustChain trust chain to be verified
+     * @param trustChain trust chain to be verified and optionally modified: it is required to be modifiable
      * @param federationPolicyConstraints map of the federation policy constraint implementations
      * @return true if trust chain meets the constraints. false otherwise
      */
-    public static boolean verifyPolicyConstraints(@Nullable final EntityStatement<?> subordinateStatement,
-            @Nonnull final List<EntityStatement<?>> trustChain,
+    public static boolean verifyPolicyConstraints(@Nonnull @Live final List<EntityStatement<?>> trustChain,
             @Nonnull Map<String, FederationPolicyConstraint> federationPolicyConstraints) {
-        if (subordinateStatement == null) {
+        if (trustChain.size() < 3) {
             return true;
         }
-        final Map<String, Object> constraints =
-                subordinateStatement.getParsedPayload() instanceof SubordinateStatementPayload ssp ?
-                        ssp.getConstraints() : null;
-        if (constraints == null || constraints.isEmpty()) {
-            log.trace("No constraints found for {}: {}", subordinateStatement.getSubject(), constraints);
-            return true;
-        }
-        for (final String constraint : constraints.keySet()) {
-            final FederationPolicyConstraint validator = federationPolicyConstraints.get(constraint);
-            if (validator != null) {
-                log.trace("Validating federation policy constraint {} with {}", constraint, validator);
-                if (!validator.validate(constraints.get(constraint), trustChain)) {
-                    log.warn("Subordinate statement issued by {} contained constraint {} that failed",
-                            subordinateStatement.getIssuer(), constraint);
-                    return false;
+        for (int i = trustChain.size() - 2; i > 0; i--) {
+            if (trustChain.get(i) instanceof SubordinateStatement subordinateStatement) {
+                final Map<String, Object> constraints = subordinateStatement.getParsedPayload().getConstraints();
+                if (constraints == null || constraints.isEmpty()) {
+                    log.trace("No constraints found for {}: {}", subordinateStatement.getSubject(), constraints);
+                    continue;
+                }
+                for (final String constraint : constraints.keySet()) {
+                    final FederationPolicyConstraint validator = federationPolicyConstraints.get(constraint);
+                    if (validator != null) {
+                        log.trace("Validating federation policy constraint {} with {}", constraint, validator);
+                        if (!validator.validate(constraints.get(constraint), subordinateStatement, trustChain)) {
+                            log.warn("Subordinate statement issued by {} contained constraint {} that failed",
+                                    subordinateStatement.getIssuer(), constraint);
+                            return false;
+                        }
+                    } else {
+                        log.debug("Ignoring non-recognized federation policy constraint {}", constraint);
+                    }
                 }
             } else {
-                log.debug("Ignoring non-recognized federation policy constraint {}", constraint);
+                log.error("Unexpected trust chain contents: {} is not a subordinate statement", trustChain.get(i));
+                return false;
             }
         }
         return true;
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/AbstractFederationPolicyConstraint.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/AbstractFederationPolicyConstraint.java
index 78d57b8..424c62c 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/AbstractFederationPolicyConstraint.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/AbstractFederationPolicyConstraint.java
@@ -22,6 +22,7 @@ import javax.annotation.Nullable;
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubordinateStatement;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraint;
 import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
 import net.shibboleth.shared.logic.ConstraintViolationException;
@@ -40,14 +41,14 @@ public abstract class AbstractFederationPolicyConstraint<T extends Object>
 
     /** {@inheritDoc} */
     @Override
-    public boolean validate(@Nullable final Object constraint,
+    public boolean validate(@Nullable final Object constraint, @Nonnull final SubordinateStatement subordinateStatement,
             @Nonnull final List<EntityStatement<?>> trustChain) {
         checkComponentActive();
         try {
             log.trace("Attempting to parse raw constraint value: {}", constraint);
             final T constraintData = parseConstraint(constraint);
             if (constraintData != null) {
-                return doValidate(constraintData, trustChain);
+                return doValidate(constraintData, subordinateStatement, trustChain);
             } else {
                 return true;
             }
@@ -70,9 +71,11 @@ public abstract class AbstractFederationPolicyConstraint<T extends Object>
      * Validate whether the given trust chain meets given federation policy constraint value,
      * 
      * @param constraintData the non-null constraint value
+     * @param subordinateStatement subordinate statement that contains the constraint
      * @param trustChain trust chain to be evaluated
      * @return true if the trust chain is valid for this constraint, false otherwise.
      */
     protected abstract boolean doValidate(@Nonnull final T constraintData,
+            @Nonnull final SubordinateStatement subordinateStatement,
             @Nonnull final List<EntityStatement<?>> trustChain);
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultAllowedEntityTypesConstraint.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultAllowedEntityTypesConstraint.java
index d0a5db1..8ef37f0 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultAllowedEntityTypesConstraint.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultAllowedEntityTypesConstraint.java
@@ -15,7 +15,9 @@
 package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.impl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 import javax.annotation.Nonnull;
@@ -25,8 +27,15 @@ import org.slf4j.Logger;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityConfiguration;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubordinateStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.impl.EntityConfigurationImpl;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.impl.SubordinateStatementImpl;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.claim.Metadata;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.claim.impl.MetadataImpl;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.impl.EntityConfigurationPayloadImpl;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.impl.SubordinateStatementPayloadImpl;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
@@ -79,6 +88,7 @@ public class DefaultAllowedEntityTypesConstraint extends AbstractFederationPolic
     /** {@inheritDoc} */
     @Override
     protected boolean doValidate(@Nonnull final List<String> constraintData,
+            @Nonnull final SubordinateStatement subordinateStatement,
             @Nonnull final List<EntityStatement<?>> trustChain) {
         if (constraintData.contains("federation_entity")) {
             log.warn("The value 'federation_entity' is not allowed for allowed_entity_types");
@@ -87,8 +97,12 @@ public class DefaultAllowedEntityTypesConstraint extends AbstractFederationPolic
         final List<String> allowedTypes = new ArrayList<>(constraintData);
         allowedTypes.add("federation_entity");
         log.trace("Allowed entity types: {}", allowedTypes);
-        for (final EntityStatement<?> entityStatement : trustChain) {
+        for (int i = 0; i < trustChain.size() - 1; i++) {
+            final EntityStatement<?> entityStatement = trustChain.get(i);
             assert entityStatement != null;
+            if (subordinateStatement.equals(entityStatement)) {
+                break;
+            }
             final Metadata metadata =
                     Optional.ofNullable(entityStatement.getParsedPayload().getMetadata())
                     .orElse(null);
@@ -97,12 +111,50 @@ public class DefaultAllowedEntityTypesConstraint extends AbstractFederationPolic
                     if (!allowedTypes.contains(entityType)) {
                         log.warn("The entity type {} is not allowed in entity statement {}", entityType,
                                 entityStatement.getSubject());
-                        return false;
+                        for (int j = 0; j <= i; j++) {
+                            final EntityStatement<?> replacement = removeMetadata(entityType, trustChain.get(j));
+                            if (replacement == null) {
+                                log.error("Could not remove the entity type {} from metadata for {}", entityType,
+                                        entityStatement.getSubject());
+                                return false;
+                            }
+                            trustChain.set(j, replacement);
+                        }
+                    } else {
+                        log.trace("The entity type {} is allowed for {}", entityType, entityStatement.getSubject());
                     }
-                    log.trace("The entity type {} is allowed for {}", entityType, entityStatement.getSubject());
                 }
             }
         }
         return true;
     }
+
+    /**
+     * Removes the metadata of given entity type from the given entity statement.
+     * 
+     * @param entityType entity type for metadata to be removed
+     * @param entityStatement entity statement holding the metadata
+     * @return updated entity statement, or null if the operation failed
+     */
+    @Nullable private EntityStatement<?> removeMetadata(final String entityType,
+            final EntityStatement<?> entityStatement) {
+        final Map<String, Map<String, Object>> metadataClaims =
+                new HashMap<>(entityStatement.getParsedPayload().getMetadata().getAllClaims());
+        metadataClaims.remove(entityType);
+        log.trace("Removed entity type {}", entityType);
+        final MetadataImpl metadata = new MetadataImpl(metadataClaims);
+        log.trace("Metadata contents {}", metadata);
+        if (entityStatement instanceof EntityConfiguration entityConfiguration) {
+            final EntityConfigurationPayloadImpl payload =
+                    new EntityConfigurationPayloadImpl(entityConfiguration.getParsedPayload());
+            payload.setMetadata(metadata);
+            return new EntityConfigurationImpl(entityStatement.getJwt(), payload);
+        } else if (entityStatement instanceof SubordinateStatement subordinateStatement) {
+            final SubordinateStatementPayloadImpl payload =
+                    new SubordinateStatementPayloadImpl(subordinateStatement.getParsedPayload());
+            payload.setMetadata(metadata);
+            return new SubordinateStatementImpl(entityStatement.getJwt(), payload);
+        }
+        return null;
+    }
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultMaxPathLengthConstraint.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultMaxPathLengthConstraint.java
index ea6874e..1dd7010 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultMaxPathLengthConstraint.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultMaxPathLengthConstraint.java
@@ -22,6 +22,7 @@ import javax.annotation.Nullable;
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubordinateStatement;
 import net.shibboleth.shared.logic.ConstraintViolationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -48,15 +49,16 @@ public class DefaultMaxPathLengthConstraint extends AbstractFederationPolicyCons
     /** {@inheritDoc} */
     @Override
     protected boolean doValidate(@Nonnull final Integer constraintData,
+            @Nonnull final SubordinateStatement subordinateStatement,
             @Nonnull final List<EntityStatement<?>> trustChain) {
-        final List<EntityStatement<?>> intermediates = trustChain.stream()
-                .filter(es -> !es.getSubject().equals(es.getIssuer()))
-                .toList();
-        final int length = intermediates.size();
-        log.trace("Maximum path length: {}, amount of intermediates is {}", constraintData, length);
-        if (constraintData < length) {
+        final int length = trustChain.indexOf(subordinateStatement);
+        if (length < 1) {
+            log.error("Unexpected contents in the trust chain: subordinate statement index is {}", length);
+        }
+        log.trace("Maximum path length: {}, amount of intermediates is {}", constraintData, length - 1);
+        if (constraintData < length - 1) {
             log.warn("Maximum path length is constricted to {}, amount of intermediates is {}",
-                    constraintData, length);
+                    constraintData, length - 1);
             return false;
         }
         return true;
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultNamingConstraintsConstraint.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultNamingConstraintsConstraint.java
index 0d67ba7..9cebffb 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultNamingConstraintsConstraint.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/constraints/impl/DefaultNamingConstraintsConstraint.java
@@ -31,6 +31,7 @@ import org.bouncycastle.asn1.x509.PKIXNameConstraintValidator;
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubordinateStatement;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.ConstraintViolationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -81,6 +82,7 @@ public class DefaultNamingConstraintsConstraint extends AbstractFederationPolicy
     /** {@inheritDoc} */
     @Override
     protected boolean doValidate(@Nonnull final Map<String, List<String>> constraintData,
+            @Nonnull final SubordinateStatement subordinateStatement,
             @Nonnull final List<EntityStatement<?>> trustChain) {
         final PKIXNameConstraintValidator bcValidator = new PKIXNameConstraintValidator();
 
@@ -95,6 +97,9 @@ public class DefaultNamingConstraintsConstraint extends AbstractFederationPolicy
                     new GeneralSubtree(new GeneralName(GeneralName.dNSName, item))));
 
         for (final EntityStatement<?> entityStatement : trustChain) {
+            if (subordinateStatement.equals(entityStatement)) {
+                break;
+            }
             final String host = URI.create(entityStatement.getSubject()).getHost();
             try {
                 bcValidator.checkExcluded(new GeneralName(GeneralName.dNSName, host));
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AbstractTrustChainResolutionAction.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AbstractTrustChainResolutionAction.java
index 2fa7d26..d96ac06 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AbstractTrustChainResolutionAction.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AbstractTrustChainResolutionAction.java
@@ -14,6 +14,7 @@
 
 package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -31,13 +32,19 @@ import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.slf4j.Logger;
 
 import net.minidev.json.JSONObject;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityConfiguration;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraint;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraintHelper;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.impl.EntityConfigurationImpl;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.claim.impl.MetadataImpl;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.impl.EntityConfigurationPayloadImpl;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.policy.FederationMetadataPolicyHelper;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.context.RelyingPartyTrustChainContext;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.context.VerifiedTrustChain;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
@@ -79,6 +86,9 @@ public class AbstractTrustChainResolutionAction extends AbstractProfileAction {
     /** List of claim names who are transformed from a space-separated String into a List. */
     @Nonnull private List<String> arraysAsSpaceSeparatedList;
 
+    /** Map of supported federation policy constraints. */
+    @NonnullAfterInit private Map<String, FederationPolicyConstraint> federationPolicyConstraints;
+
     /**
      * Constructor.
      */
@@ -213,6 +223,27 @@ public class AbstractTrustChainResolutionAction extends AbstractProfileAction {
         metadataValidationCondition = Constraint.isNotNull(condition, "MetadataValidationCondition cannot be null");
     }
 
+    /**
+     * Set the map of supported federation policy constraints.
+     * 
+     * @param constraints map of supported federation policy constraints.
+     */
+    public void setFederationPolicyConstraints(@Nonnull final Map<String, FederationPolicyConstraint> constraints) {
+        checkSetterPreconditions();
+        federationPolicyConstraints = Constraint.isNotNull(constraints, "Map of policy constraints cannot be null");
+    }
+
+    /**
+     * Get the map of supported federation policy constraints.
+     * 
+     * @return map of supported federation policy constraints.
+     */
+    @Nonnull public Map<String, FederationPolicyConstraint> getFederationPolicyConstraints() {
+        checkComponentActive();
+        assert federationPolicyConstraints != null;
+        return federationPolicyConstraints;
+    }
+
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -230,20 +261,37 @@ public class AbstractTrustChainResolutionAction extends AbstractProfileAction {
         if (metadataValidationCondition == null) {
             throw new ComponentInitializationException("MetadataValidationCondition cannot be null");
         }
+        if (federationPolicyConstraints == null) {
+            throw new ComponentInitializationException("Map of policy constraints cannot be null");
+        }
     }
 
     /**
      * Populates the given policy compliant trust chains with the given trust chain if its metadata is policy compliant.
      * 
-     * @param chain the trust chain to be evaluated
+     * @param candidate the trust chain to be evaluated
      * @param policyCompliantChains the list of policy-compliant trust chains to be populated
      * @return error event ID if metadata policy merging or enforcement failed, null otherwise
      */
-    @Nullable protected String populatePolicyComplaintChains(@Nonnull final List<EntityStatement<?>> chain,
-            @Nonnull List<VerifiedTrustChain> policyCompliantChains) {
-        final Map<String,Map<String,Object>> metadata = getMetadataLookupStrategy().apply(chain);
-        log.trace("{} Metadata resolved via lookup strategy: {}", getLogPrefix(), metadata);
-        if (metadata != null) {
+    @Nullable protected String populatePolicyComplaintChains(@Nonnull final List<EntityStatement<?>> candidate,
+            @Nonnull @Live List<VerifiedTrustChain> policyCompliantChains) {
+        final Map<String,Map<String,Object>> candidateMetadata = getMetadataLookupStrategy().apply(candidate);
+        log.trace("{} Metadata resolved via lookup strategy: {}", getLogPrefix(), candidateMetadata);
+        if (candidateMetadata != null) {
+            final List<EntityStatement<?>> chain = new ArrayList<>(candidate);
+            final EntityConfiguration updatedLeaf = updateEntityConfiguration(candidate.get(0), candidateMetadata);
+            if (updatedLeaf == null) {
+                log.error("Could not update the leaf entity configuration for {}", candidate.get(0).getSubject());
+                return EventIds.INVALID_MSG_CTX;
+            }
+            chain.set(0, updatedLeaf);
+            if (!FederationPolicyConstraintHelper.verifyPolicyConstraints(
+                    chain, getFederationPolicyConstraints())) {
+                return OidFederationEventIds.INVALID_TRUST_CHAIN_AGAINST_CONSTRAINTS;
+            }
+            final Map<String,Map<String,Object>> metadata =
+                    Optional.ofNullable(getMetadataLookupStrategy().apply(chain)).orElse(CollectionSupport.emptyMap());
+            log.trace("{} Constrained metadata resolved via lookup strategy: {}", getLogPrefix(), metadata);
             final Map<String,Map<String,Object>> verifiedMetadata = new HashMap<>();
             for (final String entityType : metadata.keySet()) {
                 final Map<String, MetadataPolicy> mergedPolicies;
@@ -313,4 +361,22 @@ public class AbstractTrustChainResolutionAction extends AbstractProfileAction {
                 .orElse(null);
     }
 
+    /**
+     * Updates the given entity configuration to contain given metadata.
+     * 
+     * @param entityStatement entity configuration source
+     * @param metadata metadata to be included in the updated entity configuration
+     * @return updated entity configuration or null if the source was unexpected
+     */
+    @Nullable protected EntityConfiguration updateEntityConfiguration(
+            @Nullable final EntityStatement<?> entityStatement,
+            @Nonnull final Map<String, Map<String, Object>> metadata) {
+        if (entityStatement instanceof EntityConfiguration entityConfiguration) {
+            final EntityConfigurationPayloadImpl payload =
+                    new EntityConfigurationPayloadImpl(entityConfiguration.getParsedPayload());
+            payload.setMetadata(new MetadataImpl(metadata));
+            return new EntityConfigurationImpl(entityStatement.getJwt(), payload);
+        }
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/OidFederationEventIds.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/OidFederationEventIds.java
index ec5bbbe..d8c4c01 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/OidFederationEventIds.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/OidFederationEventIds.java
@@ -69,4 +69,10 @@ public class OidFederationEventIds {
      * ID of event returned if the given metadata is invalid against policy.
      */
     @Nonnull @NotEmpty public static final String INVALID_METADATA_AGAINST_POLICY = "InvalidMetadataAgainstPolicy";
+
+    /**
+     * ID of event returned if the trust chain is invalid against constraints.
+     */
+    @Nonnull @NotEmpty public static final String INVALID_TRUST_CHAIN_AGAINST_CONSTRAINTS =
+            "InvalidTrustChainAgainstConstraints";
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java
index 2ecef8f..7afe12b 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java
@@ -115,7 +115,7 @@ public class ValidateProvidedTrustChain extends AbstractTrustChainResolutionActi
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         if (!providedTrustChainValidationStrategy.test(profileRequestContext, trustChain)) {
-            log.error("{} The trust chain validation failed", getLogPrefix());
+            log.warn("{} The trust chain validation failed", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
             return;
         }
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 46b305c..34c4020 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -333,8 +333,7 @@
                 p:criteriaToSubjectEntityIdStrategy-ref="shibboleth.oidfed.DefaultSubjectEntityIDCriteriaToIdentifierStrategy"
                 p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"
                 p:subordinateStatementCache-ref="shibboleth.oidfed.SubordinateEntityStatementMetadataCache"
-                p:localTrustAnchorsCache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache"
-                p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}">
+                p:localTrustAnchorsCache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache">
                 <property name="criteriaToValidContainerLifetimeStrategy">
                     <bean parent="shibboleth.Functions.Constant">
                         <constructor-arg>
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
index 0d25b16..7d7d06a 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
@@ -36,7 +36,8 @@
         p:metadataPolicyEnforcer-ref="#{'%{idp.oidfed.authorize.MetadataPolicyEnforcer:DefaultMetadataPolicyEnforcer}'.trim()}"
         p:preSelectedTrustChainIdsLookupStrategy="#{getObject('shibboleth.oidfed.PreSelectedTrustChainIDsLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultPreSelectedTrustChainIDsLookupStrategy')}"
         p:arraysAsSpaceSeparatedList="%{idp.oidfed.policy.arraysAsSpaceSeparatedList:scope}"
-        p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}">
+        p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}"
+        p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}">
         <property name="metadataLookupStrategy">
             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultCombinedMetadataFromTrustChainLookupStrategy" />
         </property>
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-flow.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-flow.xml
index 8c5cb3e..44c78c8 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-flow.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-flow.xml
@@ -60,12 +60,14 @@
     <end-state id="InvalidMetadataPolicy"/>
     <end-state id="InvalidMetadataAgainstPolicy"/>
     <end-state id="NoTrustChainsResolved" />
+    <end-state id="InvalidTrustChainAgainstConstraints" />
     <end-state id="HandleError"/>
 
     <global-transitions>
         <transition on="InvalidMetadataPolicy" to="InvalidMetadataPolicy" />
         <transition on="InvalidMetadataAgainstPolicy" to="InvalidMetadataAgainstPolicy" />
         <transition on="NoTrustChainsResolved" to="NoTrustChainsResolved" />
+        <transition on="InvalidTrustChainAgainstConstraints" to="InvalidTrustChainAgainstConstraints" />
         <transition on="HandleError" to="HandleError" />
     </global-transitions>
 
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
index 758ac8f..6cce525 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
@@ -43,7 +43,8 @@
         p:metadataPolicyEnforcer-ref="#{'%{idp.oidfed.register.MetadataPolicyEnforcer:DefaultMetadataPolicyEnforcer}'.trim()}"
         p:arraysAsSpaceSeparatedList="%{idp.oidfed.policy.arraysAsSpaceSeparatedList:scope}"
         p:metadataLookupStrategy-ref="DefaultCombinedMetadataFromTrustChainLookupStrategy"
-        p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}">
+        p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}"
+        p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}">
         <property name="providedTrustChainValidationStrategy">
             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultProvidedTrustChainValidationStrategy"
                 p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}">
@@ -129,7 +130,8 @@
         p:arraysAsSpaceSeparatedList="%{idp.oidfed.policy.arraysAsSpaceSeparatedList:scope}"
         p:metadataLookupStrategy-ref="DefaultCombinedMetadataFromTrustChainLookupStrategy"
         p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}"
-        p:entityConfigurationLookupStrategy-ref="ExplicitClientRegistrationRequestEntityConfigurationLookupFunction" />
+        p:entityConfigurationLookupStrategy-ref="ExplicitClientRegistrationRequestEntityConfigurationLookupFunction"
+        p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}" />
 
     <bean id="FetchThroughTrustChainMetadataCache" parent="shibboleth.oidc.CacheBuilder">
         <constructor-arg>
@@ -148,8 +150,7 @@
                 p:criteriaToSubjectEntityIdStrategy-ref="shibboleth.oidfed.DefaultSubjectEntityIDCriteriaToIdentifierStrategy"
                 p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"
                 p:subordinateStatementCache-ref="shibboleth.oidfed.SubordinateEntityStatementMetadataCache"
-                p:localTrustAnchorsCache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache"
-                p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}">
+                p:localTrustAnchorsCache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache">
                 <property name="criteriaToValidContainerLifetimeStrategy">
                     <bean parent="shibboleth.Functions.Constant">
                         <constructor-arg>
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml
index 4fbed93..2cc79b9 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml
@@ -81,7 +81,8 @@
         p:metadataPolicyEnforcer-ref="#{'%{idp.oidfed.resolve-entity.MetadataPolicyEnforcer:DefaultMetadataPolicyEnforcer}'.trim()}"
         p:preSelectedTrustChainIdsLookupStrategy="#{getObject('shibboleth.oidfed.PreSelectedTrustChainIDsLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultPreSelectedTrustChainIDsLookupStrategy')}"
         p:arraysAsSpaceSeparatedList="%{idp.oidfed.policy.arraysAsSpaceSeparatedList:scope}"
-        p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}">
+        p:metadataValidationCondition-ref="#{'%{idp.oidfed.MetadataValidationCondition:DefaultMetadataValidationCondition}'.trim()}"
+        p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}">
         <property name="metadataLookupStrategy">
             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultCombinedMetadataFromTrustChainLookupStrategy"/>
         </property>
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategyTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategyTest.java
index d4f7571..7c30d93 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategyTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remote/trustchain/DefaultTrustChainFetchingStrategyTest.java
@@ -20,7 +20,6 @@ import static org.mockito.Mockito.when;
 
 import java.time.Duration;
 import java.time.Instant;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Function;
@@ -37,7 +36,6 @@ import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.RemoteEnti
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.RemoteSubordinateStatementContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.RemoteTrustChainsContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remote.SubordinateStatementCacheIdentifier;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraint;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.payload.EntityConfigurationPayload;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.util.EntityStatementHelper;
 import net.shibboleth.oidc.metadata.cache.MetadataCache;
@@ -62,7 +60,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     Function<CriteriaSet, Duration> criteriaToInvalidContainerLifetimeStrategy;
 
     @SuppressWarnings("unchecked")
-    @BeforeMethod
     public void initMocks() {
         criteriaToSubjectEntityIdStrategy = mock(Function.class);
         entityConfigurationCache = mock(MetadataCache.class);
@@ -72,7 +69,9 @@ public class DefaultTrustChainFetchingStrategyTest {
         criteriaToInvalidContainerLifetimeStrategy = mock(Function.class);
     }
 
-    public void setup(final Map<String, FederationPolicyConstraint> federationPolicyConstraints) {
+    @BeforeMethod
+    public void setup() {
+        initMocks();
         function = new DefaultTrustChainFetchingStrategy();
         function.setCriteriaToSubjectEntityIdStrategy(criteriaToSubjectEntityIdStrategy);
         function.setEntityConfigurationCache(entityConfigurationCache);
@@ -80,7 +79,6 @@ public class DefaultTrustChainFetchingStrategyTest {
         function.setLocalTrustAnchorsCache(localTrustAnchorsCache);
         function.setCriteriaToValidContainerLifetimeStrategy(criteriaToValidContainerLifetimeStrategy);
         function.setCriteriaToInvalidContainerLifetimeStrategy(criteriaToInvalidContainerLifetimeStrategy);
-        function.setFederationPolicyConstraints(federationPolicyConstraints);
         function.setId("mockFunction");
         try {
             function.initialize();
@@ -91,13 +89,11 @@ public class DefaultTrustChainFetchingStrategyTest {
 
     @Test
     public void nullCriteria_returnsNull() {
-        setup(new HashMap<>());
         Assert.assertEquals(function.apply(null), null);
     }
 
     @Test
     public void noValidLifetimeCriteria_returnsNull() {
-        setup(new HashMap<>());
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(null);
         when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         Assert.assertEquals(function.apply(new CriteriaSet()), null);
@@ -105,7 +101,6 @@ public class DefaultTrustChainFetchingStrategyTest {
 
     @Test
     public void noInvalidLifetimeCriteria_returnsNull() {
-        setup(new HashMap<>());
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(null);
         Assert.assertEquals(function.apply(new CriteriaSet()), null);
@@ -113,7 +108,6 @@ public class DefaultTrustChainFetchingStrategyTest {
 
     @Test
     public void noEntityConfigurationResolved_returnsNull() throws MetadataCacheException {
-        setup(new HashMap<>());
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(entityConfigurationCache.get(any())).thenReturn(CollectionSupport.emptyList());
@@ -122,7 +116,6 @@ public class DefaultTrustChainFetchingStrategyTest {
 
     @Test
     public void entityConfigurationException_returnsNull() throws MetadataCacheException {
-        setup(new HashMap<>());
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(entityConfigurationCache.get(any())).thenThrow(MetadataCacheException.class);
@@ -131,7 +124,6 @@ public class DefaultTrustChainFetchingStrategyTest {
 
     @Test
     public void entityConfigurationNoHints_returnsNull() throws MetadataCacheException {
-        setup(new HashMap<>());
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         final RemoteEntityConfigurationContainer ecContainer =
@@ -142,7 +134,6 @@ public class DefaultTrustChainFetchingStrategyTest {
 
     @Test
     public void entityConfigurationOneUnresolvableHint_returnsEmptyContainer() throws MetadataCacheException {
-        setup(new HashMap<>());
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
         final RemoteEntityConfigurationContainer ecContainer =
@@ -154,7 +145,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @SuppressWarnings("unchecked")
     @Test
     public void entityConfigurationOneResolvableHint_returnsContainerWithOneChain() throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String anchor = "https://federation.local/immediate";
         when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
@@ -181,7 +171,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @Test
     public void entityConfigurationOneResolvableLocalAuthorityWithBrokenHint_returnsContainerWithOneChain()
             throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String immediate = "https://federation.local/immediate";
         final String anchor = "https://federation.local/anchor";
@@ -211,7 +200,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @Test
     public void entityConfigurationOneResolvableLocalAuthorityWithWorkingHint_returnsContainerWithTwoChains()
             throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String immediate = "https://federation.local/immediate";
         final String anchor = "https://federation.local/anchor";
@@ -247,7 +235,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @Test
     public void entityConfigurationOneResolvableHint_matchPreSelected_returnsContainerWithOneChain()
             throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String anchor = "https://federation.local/immediate";
         final PreSelectedTrustChainCriterion preSelectedCriterion =
@@ -276,7 +263,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @Test
     public void entityConfigurationOneResolvableHint_notMatchingPreSelected_returnsEmptyContainer()
             throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String anchor = "https://federation.local/immediate";
         final PreSelectedTrustChainCriterion preSelectedCriterion =
@@ -299,7 +285,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @SuppressWarnings("unchecked")
     @Test
     public void entityConfigurationTwoResolvableHints_returnsContainerWithTwoChains() throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String anchor1 = "https://federation.local/immediate1";
         final String anchor2 = "https://federation.local/immediate2";
@@ -331,7 +316,6 @@ public class DefaultTrustChainFetchingStrategyTest {
     @SuppressWarnings("unchecked")
     @Test
     public void entityConfigurationAuthorityLoop_returnsEmptyContantainer() throws MetadataCacheException {
-        setup(new HashMap<>());
         final String leaf = "https://federation.local/leaf";
         final String anchor1 = "https://federation.local/immediate1";
         final String anchor2 = "https://federation.local/immediate2";
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
index a6e1551..b3e39cc 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
@@ -315,6 +315,23 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         assertErrorCode(result, "invalid_request");
     }
 
+    @Test
+    public void testValidTrustChain_invalidMaxLengthInIntermediate() throws Exception {
+        final String clientId = uniqueClientId();
+        final String intermediateId1 = uniqueIntermediateId();
+        final String intermediateId2 = uniqueIntermediateId();
+        final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
+                subordinateStatement(intermediateId1, intermediateKey, leafKey, clientId, Collections.emptyMap(),
+                        Collections.emptyMap()) + "\", \"" +
+                subordinateStatement(intermediateId2, intermediateKey, intermediateKey, intermediateId1, Collections.emptyMap(),
+                        Map.of("max_path_length", Integer.valueOf(0))) + "\", \"" +
+                subordinateStatement(anchorId, trustedAnchorKey, intermediateKey, intermediateId2, Collections.emptyMap(),
+                        Map.of("max_path_length", Integer.valueOf(2))) + "\", \"" + trustedAnchorConfiguration() + "\"]";
+        setRequest("POST", trustChain, "application/trust-chain+json");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
     @Test
     public void testValidTrustChain_validNamingConstraintInAnchor() throws Exception {
         final String clientId = uniqueClientId();

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


More information about the commits mailing list