[java-idp-plugin-oidc-op-oidfed] 03/03: Verify trust_marks syntax (including trust_mark_type match) as claims validator
Codeberg
noreply at shibboleth.net
Fri Jan 30 11:57:13 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/6fc88fc65fc49b7188f25e2c16f75f9fdc29b686
commit 6fc88fc65fc49b7188f25e2c16f75f9fdc29b686
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Jan 30 13:56:32 2026 +0200
Verify trust_marks syntax (including trust_mark_type match) as claims validator
- the validator is wired to entity configurations, explicit registration requests and resolve entity responses
---
.../jwt/claims/impl/TrustMarksClaimsValidator.java | 109 +++++++++++++++++++++
.../META-INF/net.shibboleth.idp/postconfig.xml | 3 +
2 files changed, 112 insertions(+)
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/security/jwt/claims/impl/TrustMarksClaimsValidator.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/security/jwt/claims/impl/TrustMarksClaimsValidator.java
new file mode 100644
index 0000000..70e9dff
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/security/jwt/claims/impl/TrustMarksClaimsValidator.java
@@ -0,0 +1,109 @@
+/*
+ * 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.idp.plugin.oidc.op.oidfed.security.jwt.claims.impl;
+
+import java.text.ParseException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.oidc.jwt.claims.AbstractClaimsValidator;
+import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
+import net.shibboleth.oidc.jwt.claims.JWTValidationException;
+import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+
+/**
+ * A {@link ClaimsValidator} for validating the syntax of the optional trust_marks claim. Each item ie the array must
+ * contain a match between the trust_mark_type claim and the corresponding claim inside the trust_mark JWT payload.
+ */
+ at ThreadSafeAfterInit
+public class TrustMarksClaimsValidator extends AbstractClaimsValidator {
+
+ /** {@inheritDoc} */
+ protected void doValidate(@Nonnull final JWTClaimsSet claims,
+ @Nonnull final ProfileRequestContext context) throws JWTValidationException {
+ try {
+ final List<Object> trustMarks = claims.getListClaim("trust_marks");
+ if (trustMarks != null) {
+ for (final Object raw : trustMarks) {
+ if (raw instanceof Map<?, ?> map) {
+ final Map<String, String> trustMark = map.keySet().stream()
+ .filter(String.class::isInstance)
+ .map(String.class::cast)
+ .filter(key -> map.get(key) instanceof String)
+ .collect(Collectors.toMap(key -> key, key -> (String) map.get(key)));
+ if (trustMark.isEmpty()) {
+ throw new JWTValidationException("Unexpected contents for trust_marks array item: "
+ + "Could not parse a map of Strings");
+ }
+ validateContent(trustMark);
+ } else {
+ throw new JWTValidationException("Unexpected contents for trust_marks array item: "
+ + "Could not parse a map of strings");
+ }
+ }
+ }
+ } catch (final ParseException e) {
+ throw new JWTValidationException("Unexpected contents for trust_marks: could not parse an array", e);
+ }
+ }
+
+ /**
+ * Verifies that the given trust mark item meets the syntax requirements: the trust_mark content must be a signed
+ * JWT with a matching value for the trust_mark_type claim.
+ *
+ * @param trustMark trust mark JSON object as a map
+ * @throws JWTValidationException if the syntax validation fails
+ */
+ protected void validateContent(@Nonnull final Map<String, String> trustMark) throws JWTValidationException {
+ final String trustMarkType = trustMark.get("trust_mark_type");
+ if (trustMarkType == null) {
+ throw new JWTValidationException("Unexpected contents for trust_marks array item: "
+ + "trust_mark_type is null");
+ }
+ final SignedJWT trustMarkJwt = Optional.ofNullable(trustMark.get("trust_mark"))
+ .map(value -> {
+ try {
+ return SignedJWT.parse(value);
+ } catch (final ParseException e) {
+ return null;
+ }
+ })
+ .orElse(null);
+ if (trustMarkJwt == null) {
+ throw new JWTValidationException("Unexpected contents for trust_marks array item: "
+ + "trust_mark cannot be parsed into JWT");
+ }
+ try {
+ final String trustMarkTypeJwt = trustMarkJwt.getJWTClaimsSet().getStringClaim("trust_mark_type");
+ if (!trustMarkType.equals(trustMarkTypeJwt)) {
+ throw new JWTValidationException("Unexpected contents for trust_marks array item: "
+ + "trust_mark_type " + trustMarkType + " does not match the JWT claim " + trustMarkTypeJwt);
+ }
+ } catch (final ParseException e) {
+ throw new JWTValidationException("Unexpected contents for trust_marks array item: "
+ + "Could not parse trust_mark_type from JWT for trust_mark_type " + trustMarkType, e);
+ }
+
+ }
+}
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 af61e8f..74722fa 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
@@ -171,6 +171,7 @@
p:prohibitedClaims="aud" />
<bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.security.jwt.claims.impl.CritClaimsValidator"
p:recognizedClaims="%{idp.oidfed.cache.entityConfiguration.critClaims:%{idp.oidfed.cache.default.critClaims:}}" />
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.security.jwt.claims.impl.TrustMarksClaimsValidator" />
</util:list>
</property>
</bean>
@@ -453,6 +454,7 @@
p:requiredClaims="metadata" />
<bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
p:requiredClaims="trust_chain" />
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.security.jwt.claims.impl.TrustMarksClaimsValidator" />
</util:list>
</property>
</bean>
@@ -1101,6 +1103,7 @@
p:recognizedClaims="%{idp.oidfed.cache.explicitRegistration.critClaims:%{idp.oidfed.cache.default.critClaims:}}" />
<bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
p:requiredClaims="authority_hints" />
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.security.jwt.claims.impl.TrustMarksClaimsValidator" />
</util:list>
</property>
</bean>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list