[java-oidc-common] branch main updated: JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons

Henri Mikkonen henri.mikkonen at iki.fi
Fri Jan 27 15:27:00 UTC 2023


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

hjmikkon pushed a commit to branch main
in repository java-oidc-common.

View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=a07f33a6a226a6d52a4ce2d230bf1833ea8d5995

The following commit(s) were added to refs/heads/main by this push:
     new a07f33a  JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons
a07f33a is described below

commit a07f33a6a226a6d52a4ce2d230bf1833ea8d5995
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Jan 27 17:25:54 2023 +0200

    JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-41
    
    Extended signature signing and validation to honor algorithm set in the client metadata.
---
 .../impl/ClientInformationJWTTrustEngine.java      | 134 ++++++++++
 ...ormationSignatureSigningParametersResolver.java | 128 +++++++++
 .../impl/ClientInformationJWTTrustEngineTest.java  | 286 +++++++++++++++++++++
 .../impl/ExplicitKeySignedJWTTrustEngineTest.java  |  12 +-
 4 files changed, 554 insertions(+), 6 deletions(-)

diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ClientInformationJWTTrustEngine.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ClientInformationJWTTrustEngine.java
new file mode 100644
index 0000000..49037e9
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ClientInformationJWTTrustEngine.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.oidc.security.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.SecurityException;
+import org.opensaml.security.credential.CredentialResolver;
+import org.opensaml.security.trust.TrustedCredentialTrustEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.JOSEObject;
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
+import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
+import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ * An implementation of {@link org.opensaml.xmlsec.signature.support.SignatureTrustEngine} which evaluates the validity
+ * and trustworthiness of JWT signatures.
+ * 
+ * <p>
+ * This extends {@link ExplicitKeySignedJWTTrustEngine} by adding a configurable lookup strategy for the signature
+ * algorithm that must be used in the incoming token. Also a default value can be set if the function returns no
+ * value. If neither function is returning value nor the default value is set, then any signature accepted by the
+ * parent class is accepted.
+ * </p>
+ */
+public class ClientInformationJWTTrustEngine extends ExplicitKeySignedJWTTrustEngine
+    implements TrustedCredentialTrustEngine<SignedJWT> {
+    
+    /** Class logger. */
+    private final Logger log = LoggerFactory.getLogger(ClientInformationJWTTrustEngine.class);
+
+    /** A lookup function for the signature algorithm in the client metadata. */
+    @Nonnull private final Function<OIDCClientInformation, String> signatureAlgorithmLookupStrategy;
+
+    /** The default algorithm value used if lookup strategy returned null. */
+    @Nullable private final String defaultAlgorithmValue;
+
+    /**
+     * 
+     * Constructor.
+     *
+     * @param resolver credential resolver used to resolve trusted credentials.
+     * @param joseObjectResolver resolver which resolve credentials from the headers of a {@link JOSEObject} instance.
+     * @param strategy lookup strategy for the signature algorithm in the client metadata.
+     * @param defaultValue the default signature algorithm value.
+     */
+    public ClientInformationJWTTrustEngine(@Nonnull final @ParameterName(name="resolver") CredentialResolver resolver,
+            @Nonnull final @ParameterName(name="JOSEObjectResolver") JOSEObjectCredentialResolver joseObjectResolver,
+            @Nonnull @ParameterName(name="signatureAlgorithmLookupStrategy")
+            final Function<OIDCClientInformation, String> strategy,
+            @Nullable @ParameterName(name = "defaultAlgorithmValue") final String defaultValue) {
+        super(resolver, joseObjectResolver);
+        signatureAlgorithmLookupStrategy = Constraint.isNotNull(strategy, "Signature algorithm lookup cannot be null");
+        defaultAlgorithmValue = StringSupport.trimOrNull(defaultValue);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doValidate(@Nonnull final SignedJWT signedJWT, @Nonnull final CriteriaSet trustBasisCriteria)
+            throws SecurityException {
+        if (super.doValidate(signedJWT, trustBasisCriteria)) {
+            final String tokenAlgorithm = signedJWT.getHeader().getAlgorithm().getName();
+            final String expectedAlgorithm;
+            if (trustBasisCriteria.contains(ClientInformationCriterion.class)) {
+                expectedAlgorithm = getExpectedAlgorithm(trustBasisCriteria.get(ClientInformationCriterion.class));
+            } else {
+                log.debug("No client information given, using default value {}", defaultAlgorithmValue);
+                expectedAlgorithm = defaultAlgorithmValue;
+            }
+            if (expectedAlgorithm == null) {
+                log.debug("No expected algorithm defined, accepting {} from the token", tokenAlgorithm);
+                return true;
+            }
+            if (tokenAlgorithm.equals(expectedAlgorithm)) {
+                log.debug("The algorithnm specified in the token was expected {}", tokenAlgorithm);
+                return true;
+            }
+            log.warn("The algorithnm specified in the token {} was not expected {}", tokenAlgorithm, expectedAlgorithm);
+            return false;
+        }
+        return false;
+    }
+
+    /**
+     * Fetches the expected signature algorithm from the {@link OIDCClientInformation}.
+     * 
+     * @param criterion criterion containing the client information/metadata.
+     * @return the expected algorithm value.
+     */
+    @Nullable protected String getExpectedAlgorithm(@Nonnull final ClientInformationCriterion criterion) {
+        final OIDCClientInformation metadata = criterion.getOidcClientInformation();
+        if (metadata != null) {
+            final String storedAlgorithm = signatureAlgorithmLookupStrategy.apply(metadata);
+            if (StringSupport.trimOrNull(storedAlgorithm) == null) {
+                log.debug("No algorithm value specified in metadata, using default value {}", defaultAlgorithmValue);
+                return defaultAlgorithmValue;
+            } else {
+                log.debug("Found the expected algorithm from metadata: {}", storedAlgorithm);
+                return storedAlgorithm;
+            }
+        } else {
+            log.debug("No client information given, using default value {}", defaultAlgorithmValue);
+            return defaultAlgorithmValue;
+        }
+        
+    }
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/ClientInformationSignatureSigningParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/ClientInformationSignatureSigningParametersResolver.java
new file mode 100644
index 0000000..564f1a3
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/ClientInformationSignatureSigningParametersResolver.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.oidc.security.jose.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
+import net.shibboleth.oidc.security.jose.SignatureSigningParametersResolver;
+import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ * An implementation of an {@link SignatureSigningParametersResolver} that extends the {@link
+ * BasicSignatureSigningParametersResolver} functionality by adding a configurable lookup strategy for fetching
+ * the desired algorithm value from {@link OIDCClientInformation}. It is expected to be found from the criteria set.
+ */
+public class ClientInformationSignatureSigningParametersResolver 
+            extends BasicSignatureSigningParametersResolver
+                    implements SignatureSigningParametersResolver {
+    
+    /** Class logger.*/
+    private final Logger log = LoggerFactory.getLogger(ClientInformationSignatureSigningParametersResolver.class);
+
+    /** A lookup function for the signature algorithm. */
+    private final Function<OIDCClientInformation, String> signatureAlgorithmLookupStrategy;
+
+    /** The default algorithm value used if lookup strategy returned null. */
+    private final String defaultAlgorithmValue;
+
+    /**
+     * Constructor.
+     *
+     * @param strategy a lookup function for the signature algorithm
+     * @param defaultValue the default algorithm value used if lookup strategy returned null
+     */
+    public ClientInformationSignatureSigningParametersResolver(
+            @Nonnull @ParameterName(name="signatureAlgorithmLookupStrategy")
+            final Function<OIDCClientInformation, String> strategy,
+            @Nullable @ParameterName(name = "defaultAlgorithmValue") final String defaultValue) {
+        super();
+        signatureAlgorithmLookupStrategy = Constraint.isNotNull(strategy, "The signature algorithm lookup strategy "
+                + "can not be null");
+        defaultAlgorithmValue = defaultValue;
+    }
+    
+    
+    /**
+     * Get the effective list of signature algorithm URIs to consider, including application of 
+     * include/exclude policy.
+     * 
+     * @param criteria the input criteria being evaluated
+     * @param includeExcludePredicate  the include/exclude predicate to use
+     * @return the list of effective algorithm URIs
+     */
+    @Override
+    @Nonnull protected List<String> getEffectiveSignatureAlgorithms(@Nonnull final CriteriaSet criteria, 
+            @Nonnull final Predicate<String> includeExcludePredicate) {
+        final List<String> accumulator = super.getEffectiveSignatureAlgorithms(criteria, includeExcludePredicate);
+        OIDCClientInformation metadata = null;
+        if (criteria.contains(ClientInformationCriterion.class)) {
+            metadata = criteria.get(ClientInformationCriterion.class).getOidcClientInformation();
+        }
+        if (metadata == null) {
+            if (StringSupport.trimOrNull(defaultAlgorithmValue) != null) {
+                log.debug("No client information found from the criteria set, using default");
+                return convertIntoListIfEnabled(defaultAlgorithmValue, accumulator);
+            } 
+            log.error("No client information found from the criteria set");
+            return Collections.emptyList();
+        }
+        final String algorithm = signatureAlgorithmLookupStrategy.apply(metadata);
+        if (StringSupport.trimOrNull(algorithm) == null) {
+            if (StringSupport.trimOrNull(defaultAlgorithmValue) != null) {
+                log.debug("No signature algorithm specified in the metadata, using default");
+                return convertIntoListIfEnabled(defaultAlgorithmValue, accumulator);
+            } 
+            log.error("No signature algorith or default value specified, returning empty list");
+            return Collections.emptyList();
+        }
+        return convertIntoListIfEnabled(algorithm, accumulator);
+    }
+
+    /**
+     * Returns the given algorithm in a {@link List} if it was enabled in the list of enabled algorithms. An empty
+     * list is returned if the algorithm was not enabled.
+     * 
+     * @param algorithm the algorithm to be checked against the list
+     * @param enabledAlgorithms the list of enabled algorithms
+     * @return the given algorithm as list if it was enabled, or an empty list if not
+     */
+    @Nonnull protected List<String> convertIntoListIfEnabled(@Nonnull final String algorithm,
+            @Nonnull final List<String> enabledAlgorithms) {
+        if (enabledAlgorithms.contains(algorithm)) {
+            return List.of(algorithm);
+        } else {
+            log.warn("The algorithm {} is not enabled, returning empty list");
+            return Collections.emptyList();
+        }
+    }
+}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ClientInformationJWTTrustEngineTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ClientInformationJWTTrustEngineTest.java
new file mode 100644
index 0000000..57c8fae
--- /dev/null
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ClientInformationJWTTrustEngineTest.java
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.oidc.security.impl;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.security.KeyException;
+import java.util.List;
+import java.util.function.Function;
+
+import org.opensaml.security.SecurityException;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.CredentialResolver;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.security.criteria.UsageCriterion;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.AsymmetricJWK;
+import com.nimbusds.jose.jwk.Curve;
+import com.nimbusds.jose.jwk.ECKey;
+import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
+import net.shibboleth.oidc.security.credential.impl.BasicJOSEObjectCredentialResolver;
+import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** 
+ * Tests for the {@link ClientInformationJWTTrustEngine}.
+ */
+public class ClientInformationJWTTrustEngineTest {
+
+    private ClientInformationJWTTrustEngine engine;
+    
+    private ECKey key;
+    
+    /** The client_secret.*/
+    private static final String CLIENT_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
+    
+    @BeforeMethod
+    public void setup() throws JOSEException {
+        setup(null, info -> "RS256");
+    }
+
+    public void setup(final String defaultAlgValue) throws JOSEException {
+        setup(defaultAlgValue, info -> "RS256");
+    }
+    
+    public void setup(final String defaultAlgValue, Function<OIDCClientInformation, String> sigAlgLookup)
+            throws JOSEException {
+        key = new ECKeyGenerator(Curve.P_256).keyID("123").generate();
+
+        final CredentialResolver credResolver = new CredentialResolver() {
+
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+                jwkCredential.setAlgorithm(key.getAlgorithm());
+                jwkCredential.setKid(key.getKeyID());
+                try {
+                    jwkCredential.setPublicKey(((AsymmetricJWK) key).toPublicKey());
+                } catch (final JOSEException e) {                    
+                    fail();
+                }
+                return jwkCredential;
+            }
+
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        };
+        
+        final JOSEObjectCredentialResolver joseObjectCredResolver = new BasicJOSEObjectCredentialResolver();
+       
+        engine = new ClientInformationJWTTrustEngine(credResolver, joseObjectCredResolver, sigAlgLookup,
+                defaultAlgValue);
+    }
+
+    public void setupSymmetric(final String defaultAlgValue, Function<OIDCClientInformation, String> sigAlgLookup) {
+        final CredentialResolver credResolver = new CredentialResolver() {
+
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+                try {
+                    return TestCredentialHelper
+                            .createClientSecretCredential(CLIENT_SECRET).toSigningCredential();
+                } catch (final KeyException e) {
+                    fail(e.getMessage());
+                    return null;
+                }
+            }
+
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        };
+
+        final JOSEObjectCredentialResolver joseObjectCredResolver = new BasicJOSEObjectCredentialResolver();
+
+        engine = new ClientInformationJWTTrustEngine(credResolver, joseObjectCredResolver, sigAlgLookup,
+                defaultAlgValue);
+    }
+
+    @Test
+    public void testValid_WithTrustedCredential_NoValueNorDefault() throws JOSEException, SecurityException {
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createECSignedJWT(key, key.getKeyID(),
+                JWSAlgorithm.ES256, "https://op.example.com/", "https://rp.example.com"), criteria);
+        assertTrue(valid);
+    }
+
+    @Test
+    public void testValid_WithTrustedCredential_NoValueDefaultMatch() throws JOSEException, SecurityException {
+        setup(JWSAlgorithm.ES256.getName());
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createECSignedJWT(key, key.getKeyID(),
+                JWSAlgorithm.ES256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertTrue(valid);
+    }
+
+    @Test
+    public void testValid_WithTrustedCredential_NoValueDefaultNotMatching() throws JOSEException, SecurityException {
+        setup(JWSAlgorithm.ES512.getName());
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createECSignedJWT(key, key.getKeyID(),
+                JWSAlgorithm.ES256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertFalse(valid);
+    }
+
+    @Test
+    public void testValid_WithTrustedCredential_ValueMatch() throws JOSEException, SecurityException {
+        setup(null, info -> "ES256");
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(buildClientInformationCriterion());
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createECSignedJWT(key, key.getKeyID(),
+                JWSAlgorithm.ES256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertTrue(valid);
+    }
+
+    @Test
+    public void testValid_WithTrustedCredential_ValueNotMatching() throws JOSEException, SecurityException {
+        setup(null, info -> "ES512");
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(buildClientInformationCriterion());
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createECSignedJWT(key, key.getKeyID(),
+                JWSAlgorithm.ES256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertFalse(valid);
+    }
+
+    @Test
+    public void testValid_WithSymmetricKeyCredential_NoValueNorDefault() throws JOSEException, SecurityException {
+        setupSymmetric(null, info -> "HS256");
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createMACSignedJWT(CLIENT_SECRET,
+                key.getKeyID(), JWSAlgorithm.HS256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertTrue(valid);
+    }
+
+    @Test
+    public void testValid_WithSymmetricKeyCredential_NoValueDefaultMatching() throws JOSEException, SecurityException {
+        setupSymmetric("HS256", info -> "HS256");
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createMACSignedJWT(CLIENT_SECRET,
+                key.getKeyID(), JWSAlgorithm.HS256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertTrue(valid);
+    }
+
+    @Test
+    public void testValid_WithSymmetricKeyCredential_NoValueDefaultNotMatching() throws JOSEException,
+            SecurityException {
+        setupSymmetric("HS512", info -> "HS512");
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createMACSignedJWT(CLIENT_SECRET,
+                key.getKeyID(), JWSAlgorithm.HS256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertFalse(valid);
+    }
+
+    @Test
+    public void testValid_WithSymmetricKeyCredential_ValueMatch() throws JOSEException, SecurityException {
+        setupSymmetric(null, info -> "HS256");
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(buildClientInformationCriterion());
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createMACSignedJWT(CLIENT_SECRET,
+                key.getKeyID(), JWSAlgorithm.HS256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertTrue(valid);
+    }
+
+    @Test
+    public void testValid_WithSymmetricKeyCredential_ValueNotNatching() throws JOSEException, SecurityException {
+        setupSymmetric(null, info -> "HS512");
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(buildClientInformationCriterion());
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createMACSignedJWT(CLIENT_SECRET,
+                key.getKeyID(), JWSAlgorithm.HS256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertFalse(valid);
+    }
+
+    @Test
+    public void testValid_WithInlineJWK() throws JOSEException, SecurityException {       
+        
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new UsageCriterion(UsageType.SIGNING));
+        final var valid = engine.validate(ExplicitKeySignedJWTTrustEngineTest.createECSignedJWTWithInlineJWK(key,
+                key.getKeyID(), JWSAlgorithm.ES256, 
+                "https://op.example.com/", "https://rp.example.com"),
+                criteria);
+        assertTrue(valid);
+    }
+    
+    protected static ClientInformationCriterion buildClientInformationCriterion() {
+        return new ClientInformationCriterion(new OIDCClientInformation(new ClientID("mockClient"),
+                new OIDCClientMetadata()));
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
index 5112c6a..9701fa9 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
@@ -353,7 +353,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
      * 
      * @return the constructed claims set
      */
-    private JWTClaimsSet buildStandardClaims( final String issuer, final String audience) {
+    protected static JWTClaimsSet buildStandardClaims( final String issuer, final String audience) {
         
         return new JWTClaimsSet.Builder()
                 .issuer(issuer)
@@ -376,7 +376,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
      * @return the signed JWT
      * @throws JOSEException on error.
      */
-    private SignedJWT createECSignedJWT(final ECKey key, final String keyId, 
+    protected static SignedJWT createECSignedJWT(final ECKey key, final String keyId, 
             final JWSAlgorithm algo, final String issuer,
             final String audience) throws JOSEException {
 
@@ -403,7 +403,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
      * @return the signed JWT
      * @throws JOSEException on error.
      */
-    private SignedJWT createMACSignedJWT(final String key, final String keyId, 
+    protected static SignedJWT createMACSignedJWT(final String key, final String keyId, 
             final JWSAlgorithm algo, final String issuer,
             final String audience) throws JOSEException {
 
@@ -430,7 +430,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
      * @return the signed JWT
      * @throws JOSEException on error.
      */
-    private SignedJWT createECSignedJWTWithJKU(final ECKey key, final String keyId, 
+    protected static SignedJWT createECSignedJWTWithJKU(final ECKey key, final String keyId, 
             final URI jku, final JWSAlgorithm algo, final String issuer,
             final String audience) throws JOSEException, URISyntaxException {
 
@@ -457,7 +457,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
      * @return the signed JWT
      * @throws JOSEException on error.
      */
-    private SignedJWT createECSignedJWTWithInlineJWK(final ECKey key,  final String keyId,
+    protected static SignedJWT createECSignedJWTWithInlineJWK(final ECKey key,  final String keyId,
             final JWSAlgorithm algo, final String issuer,
             final String audience) throws JOSEException {
 
@@ -486,7 +486,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
      * @return the signed JWT
      * @throws JOSEException on error.
      */
-    private SignedJWT createECSignedJWTWithDifferentInlineJWK(final ECKey key, final String keyId,
+    protected static SignedJWT createECSignedJWTWithDifferentInlineJWK(final ECKey key, final String keyId,
             final JWSAlgorithm algo, final ECKey signingKey, final String issuer,
             final String audience) throws JOSEException {
 

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


More information about the commits mailing list