[java-oidfed-common] branch main updated: Support a chain of header validator bipredicates instead of a single one
Codeberg
noreply at shibboleth.net
Thu Oct 1 08:38:10 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/41cc8b40844333ce107c7aa6e9587d3a8404a347
The following commit(s) were added to refs/heads/main by this push:
new 41cc8b4 Support a chain of header validator bipredicates instead of a single one
41cc8b4 is described below
commit 41cc8b40844333ce107c7aa6e9587d3a8404a347
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Oct 1 11:37:22 2026 +0300
Support a chain of header validator bipredicates instead of a single one
- Also provide a validation condition implementation, useful for provided statements or chains
---
.../META-INF/net.shibboleth.idp/postconfig.xml | 36 +++++----
...tEntityStatementContentValidationCondition.java | 27 ++++---
.../DefaultTypeHeaderValidationCondition.java | 85 ++++++++++++++++++++++
3 files changed, 121 insertions(+), 27 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 6dedfd0..87638a2 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
@@ -116,9 +116,11 @@
<bean class="net.shibboleth.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
p:claimsValidator-ref="%{idp.oidfed.cache.entityConfiguration.claimsValidator:shibboleth.oidfed.DefaultEntityConfigurationClaimsValidator}"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier">
- <property name="headerValidator">
- <bean class="net.shibboleth.oidfed.metadata.cache.DefaultTrustChainHeaderValidationCondition"
- p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper" />
+ <property name="headerValidators">
+ <util:list value-type="java.util.function.BiPredicate">
+ <bean class="net.shibboleth.oidfed.metadata.cache.DefaultTrustChainHeaderValidationCondition"
+ p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper" />
+ </util:list>
</property>
<property name="containerIdValidationStrategy">
<bean parent="shibboleth.BiConditions.Expression" c:expression="#input1?.getEntityId()?.equals(#input2?.getParsedPayload()?.getSubject())"/>
@@ -223,9 +225,11 @@
<bean class="net.shibboleth.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
p:claimsValidator-ref="%{idp.oidfed.cache.subordinateStatement.claimsValidator:shibboleth.oidfed.DefaultSubordinateStatementClaimsValidator}"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier">
- <property name="headerValidator">
- <bean class="net.shibboleth.oidfed.metadata.cache.DefaultTrustChainHeaderValidationCondition"
- p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper" />
+ <property name="headerValidators">
+ <util:list value-type="java.util.function.BiPredicate">
+ <bean class="net.shibboleth.oidfed.metadata.cache.DefaultTrustChainHeaderValidationCondition"
+ p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper" />
+ </util:list>
</property>
<property name="containerIdValidationStrategy">
<bean parent="shibboleth.BiConditions.Expression" c:expression="#input1?.getEntityId()?.equals(#input2?.getParsedPayload()?.getSubject())"/>
@@ -454,8 +458,8 @@
<bean class="net.shibboleth.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
p:claimsValidator-ref="%{idp.oidfed.cache.resolveEntity.claimsValidator:shibboleth.oidfed.DefaultResolveEntityResponseClaimsValidator}"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier">
- <property name="headerValidator">
- <bean parent="shibboleth.BiConditions.Expression" c:expression="true"/>
+ <property name="headerValidators">
+ <util:list value-type="java.util.function.BiPredicate"/>
</property>
<property name="containerIdValidationStrategy">
<bean parent="shibboleth.BiConditions.Expression" c:expression="#input1?.getEntityId()?.equals(#input2?.getParsedPayload()?.getSubject())"/>
@@ -632,8 +636,8 @@
<bean class="net.shibboleth.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
p:claimsValidator-ref="%{idp.oidfed.cache.trustMarkStatus.claimsValidator:shibboleth.oidfed.DefaultTrustMarkStatusClaimsValidator}"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier">
- <property name="headerValidator">
- <bean parent="shibboleth.BiConditions.Expression" c:expression="true"/>
+ <property name="headerValidators">
+ <util:list value-type="java.util.function.BiPredicate"/>
</property>
<property name="containerIdValidationStrategy">
<bean parent="shibboleth.BiConditions.Expression" c:expression="#input1?.getEntityId()?.equals(#input2?.getParsedPayload()?.getIssuer())"/>
@@ -752,8 +756,8 @@
<bean class="net.shibboleth.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
p:claimsValidator-ref="%{idp.oidfed.cache.trustMark.claimsValidator:shibboleth.oidfed.DefaultTrustMarkClaimsValidator}"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier">
- <property name="headerValidator">
- <bean parent="shibboleth.BiConditions.Expression" c:expression="true"/>
+ <property name="headerValidators">
+ <util:list value-type="java.util.function.BiPredicate"/>
</property>
<property name="containerIdValidationStrategy">
<bean parent="shibboleth.BiConditions.Expression" c:expression="#input1?.getEntityId()?.equals(#input2?.getParsedPayload()?.getSubject())"/>
@@ -884,9 +888,11 @@
<bean class="net.shibboleth.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
p:claimsValidator-ref="%{idp.oidfed.cache.signedKeyset.claimsValidator:shibboleth.oidfed.DefaultSignedKeysetClaimsValidator}"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier">
- <property name="headerValidator">
- <bean class="net.shibboleth.oidfed.metadata.cache.DefaultTrustChainHeaderValidationCondition"
- p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper" />
+ <property name="headerValidators">
+ <util:list value-type="java.util.function.BiPredicate">
+ <bean class="net.shibboleth.oidfed.metadata.cache.DefaultTrustChainHeaderValidationCondition"
+ p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper" />
+ </util:list>
</property>
<property name="containerIdValidationStrategy">
<bean parent="shibboleth.BiConditions.Expression" c:expression="#input1?.getEntityId()?.equals(#input2?.getParsedPayload()?.getSubject())"/>
diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java
index e02d188..156c0b8 100644
--- a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java
@@ -15,6 +15,7 @@
package net.shibboleth.oidfed.metadata.cache;
import java.text.ParseException;
+import java.util.List;
import java.util.Optional;
import java.util.function.BiPredicate;
@@ -60,8 +61,8 @@ public class DefaultEntityStatementContentValidationCondition
/** The claims validator to use for validating the entity statement claims. */
@NonnullAfterInit private ClaimsValidator claimsValidator;
- /** The header validator to use for validating the entity statement header. */
- @NonnullAfterInit private BiPredicate<SignedJWT, ProfileRequestContext> headerValidator;
+ /** The header validators to use for validating the entity statement header. */
+ @NonnullAfterInit private List<BiPredicate<SignedJWT, ProfileRequestContext>> headerValidators;
/** Supplier for the Current HTTP request, if available. */
@NonnullAfterInit private NonnullSupplier<HttpServletRequest> httpServletRequestSupplier;
@@ -82,13 +83,13 @@ public class DefaultEntityStatementContentValidationCondition
}
/**
- * Set the header validator to use for validating the entity statement header.
+ * Set the header validators to use for validating the entity statement header.
*
- * @param validator header validator
+ * @param validators header validators
*/
- public void setHeaderValidator(@Nonnull final BiPredicate<SignedJWT, ProfileRequestContext> validator) {
+ public void setHeaderValidators(@Nonnull final List<BiPredicate<SignedJWT, ProfileRequestContext>> validators) {
checkSetterPreconditions();
- headerValidator = Constraint.isNotNull(validator, "Header validator cannot be null");
+ headerValidators = Constraint.isNotNull(validators, "Header validators cannot be null");
}
/**
@@ -121,8 +122,8 @@ public class DefaultEntityStatementContentValidationCondition
if (claimsValidator == null) {
throw new ComponentInitializationException("Claims validator cannot be null");
}
- if (headerValidator == null) {
- throw new ComponentInitializationException("Header validator cannot be null");
+ if (headerValidators == null) {
+ throw new ComponentInitializationException("Header validators cannot be null");
}
if (httpServletRequestSupplier == null) {
throw new ComponentInitializationException("Http servlet request supplier cannot be null");
@@ -145,7 +146,7 @@ public class DefaultEntityStatementContentValidationCondition
final var wrapper = responseContainer.getStatement();
assert wrapper != null;
if (!containerIdValidationStrategy.test(responseContainer, wrapper)) {
- log.warn("Container ID validation failed with the requested ID {}", responseContainer.getEntityId());
+ log.warn("Container ID validation failed with the requested ID {}", responseContainer.getEntityId());
return false;
}
final ProfileRequestContext profileRequestContext =
@@ -162,9 +163,11 @@ public class DefaultEntityStatementContentValidationCondition
}
//TODO: make validator interface to commons?
- if (!headerValidator.test(wrapper.getJwt(), nonNullProfileRequestContext)) {
- log.warn("Header validation failed for entity statement {}", responseContainer.getEntityId());
- return false;
+ for (final BiPredicate<SignedJWT, ProfileRequestContext> headerValidator : headerValidators) {
+ if (!headerValidator.test(wrapper.getJwt(), nonNullProfileRequestContext)) {
+ log.warn("Header validation failed for entity statement {}", responseContainer.getEntityId());
+ return false;
+ }
}
try {
diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultTypeHeaderValidationCondition.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultTypeHeaderValidationCondition.java
new file mode 100644
index 0000000..ceaf211
--- /dev/null
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/DefaultTypeHeaderValidationCondition.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidfed.metadata.cache;
+
+import java.util.Optional;
+import java.util.function.BiPredicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Default validator that validates the type header for given entity statement {@link SignedJWT}.
+ */
+public class DefaultTypeHeaderValidationCondition extends AbstractIdentifiableInitializableComponent
+ implements BiPredicate<SignedJWT, ProfileRequestContext> {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(DefaultTypeHeaderValidationCondition.class);
+
+ /** The required value for the type header. */
+ @NonnullAfterInit private String requiredTypeHeader;
+
+ /**
+ * Set the required value for the type header.
+ *
+ * @param type header value
+ */
+ public void setRequiredTypeHeader(@Nonnull @NotEmpty final String type) {
+ checkSetterPreconditions();
+ requiredTypeHeader = Constraint.isNotEmpty(type, "Required type header value cannot be empty");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ if (requiredTypeHeader == null) {
+ throw new ComponentInitializationException("Required type header value cannot be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean test(@Nullable final SignedJWT signedJwt,
+ @Nullable final ProfileRequestContext profileRequestContext) {
+ checkComponentActive();
+ if (signedJwt == null || signedJwt.getHeader() == null) {
+ log.error("Invalid input: signed JWT or its header cannot be null");
+ return false;
+ }
+ final String actualHeader = Optional.ofNullable(signedJwt.getHeader().getType())
+ .map(header -> header.getType())
+ .orElse(null);
+ if (!requiredTypeHeader.equals(actualHeader)) {
+ log.warn("The type header {} is not expected {}", actualHeader, requiredTypeHeader);
+ return false;
+ }
+ return true;
+ }
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list