[java-idp-plugin-oidc-rp] branch main updated: JOIDCRP-16 - Add a relying party signing parameters resolver

Phil Smart philip.smart at jisc.ac.uk
Wed Jun 29 10:08:17 UTC 2022


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

philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=1fd74f9b1197cbea644578185ffb64c14999138c

The following commit(s) were added to refs/heads/main by this push:
     new 1fd74f9  JOIDCRP-16 - Add a relying party signing parameters resolver
1fd74f9 is described below

commit 1fd74f9b1197cbea644578185ffb64c14999138c
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Jun 29 11:08:09 2022 +0100

    JOIDCRP-16 - Add a relying party signing parameters resolver
    
    
    https://shibboleth.atlassian.net/browse/JOIDCRP-16
---
 ...RelyingPartyProxySigningParametersResolver.java | 246 ++++++++++++++++++
 ...ingPartyProxySigningParametersResolverTest.java | 275 +++++++++++++++++++++
 2 files changed, 521 insertions(+)

diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/RelyingPartyProxySigningParametersResolver.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/RelyingPartyProxySigningParametersResolver.java
new file mode 100644
index 0000000..7ab808b
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/RelyingPartyProxySigningParametersResolver.java
@@ -0,0 +1,246 @@
+/*
+ * 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.idp.plugin.authn.oidc.rp.impl;
+
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.xmlsec.SignatureSigningParameters;
+import org.opensaml.xmlsec.impl.BasicSignatureSigningParametersResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.Algorithm;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.Curve;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.oidc.security.criterion.ProviderMetadataCriterion;
+import net.shibboleth.oidc.security.criterion.StaticCredentialCriterion;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ * A specialization of {@link BasicSignatureSigningParametersResolver} which supports selecting signing credentials
+ * from static credential criterion (e.g. from the reyling party configuration) in addition to the configured signing 
+ * credentials inside the signing configuration (determined by the superclass). 
+ * 
+ * <p>The downstream OP's metadata is also used to filter for those algorithms supported by the OP in addition to
+ * those supported by the security configuration.</p>
+ * 
+ *  * <p>
+ * In addition to the {@link net.shibboleth.utilities.java.support.resolver.Criterion} inputs documented in
+ * {@link BasicSignatureSigningParametersResolver}, the following inputs are also supported:
+ * </p>
+ * <ul>
+ * <li>{@link StaticCredentialCriterion} - optional</li>
+ * <li>{@link ProviderMetadataCriterion} - required</li>
+ * </ul>
+ */
+public class RelyingPartyProxySigningParametersResolver extends BasicSignatureSigningParametersResolver {
+    
+    /** Logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(RelyingPartyProxySigningParametersResolver.class);
+    
+    /** 
+     * A strategy to pull out the correct set of supported algorithms from the {@link OIDCProviderMetadata}.
+     * By default returns {@literal null} signalling 'do not filter'.
+     */
+    @Nonnull private Function<OIDCProviderMetadata, List<String>> providerMetadataAlgorithmLookupStrategy;
+    
+    /** Constructor.*/
+    public RelyingPartyProxySigningParametersResolver() {
+        // Always provide a strategy to avoid NPE, but default returns null e.g. do not filter.
+        providerMetadataAlgorithmLookupStrategy = FunctionSupport.constant(null);
+    }
+    
+    /**
+     * Set the strategy used to locate the supported signing algorithms from the OP's metadata for this
+     * resolver instance. For example, id_token or request object signing algorithms.
+     *  
+     * @param strategy the strategy
+     */
+    public void setProviderMetadataAlgorithmLookupStrategy(
+            @Nonnull final Function<OIDCProviderMetadata, List<String>> strategy) {
+        providerMetadataAlgorithmLookupStrategy = 
+                Constraint.isNotNull(strategy, "ProviderMetadataAlgorithmLookupStrategy can not be null");
+    }
+    
+ // Checkstyle: CyclomaticComplexity|ReturnCount OFF
+    /** {@inheritDoc} */
+    @Override
+    protected void resolveAndPopulateCredentialAndSignatureAlgorithm(@Nonnull final SignatureSigningParameters params, 
+            @Nonnull final CriteriaSet criteria, @Nonnull final Predicate<String> includeExcludePredicate) {
+        
+        final List<Credential> allCredentials = new ArrayList<>();
+        
+        // Add any static credentials from the criteria
+        if (criteria.contains(StaticCredentialCriterion.class)) {
+            final Credential staticCred = criteria.get(StaticCredentialCriterion.class).getCredential();
+            log.trace("Signing credential found in criterion '{}'", staticCred.getKeyNames());
+            allCredentials.add(staticCred);
+        }
+        
+        // Add any credentials from the configuration
+        allCredentials.addAll(getEffectiveSigningCredentials(criteria));
+        
+        // Get effective signature algorithms from configuration and include/exclude predicate
+        final List<String> algorithms = getEffectiveSignatureAlgorithms(criteria, includeExcludePredicate);        
+        
+        // Filter by those supported by the downstream OP
+        final List<String> filteredAlgorithms = filterForOPSupportedAlgorithms(criteria, algorithms);
+        final List<JWSAlgorithm> supportedAlgorithms = convertSupportAlgorithmsToJwkAlgorithms(filteredAlgorithms);
+        log.trace("Resolved effective signature algorithms: {}", supportedAlgorithms);
+        
+        // Pick the first credential that matches one of the supported algorithms
+        for (final Credential credential : allCredentials) {
+            log.trace("Evaluating signing credential '{}'", credential.getKeyNames());
+            final JWSAlgorithm foundSupportedAlgorithm = 
+                    credentialSupportsSigningAlgorithm(credential, supportedAlgorithms);
+            if (foundSupportedAlgorithm != null) {    
+                log.trace("Credential supports algorithm '{}'", foundSupportedAlgorithm);
+                params.setSigningCredential(credential);
+                params.setSignatureAlgorithm(foundSupportedAlgorithm.getName());
+                return;
+            }
+            log.trace("Credential failed eval against Signing Algorithm");
+            
+        }
+    }
+    
+    /** {@inheritDoc} 
+     * 
+     * <p>Does not include validation of the SignatureCanonicalizationAlgorithm or the
+     * SignatureReferenceDigestMethod. These will be null in the JWT case.</p>
+     */
+    @Override
+    protected boolean validate(@Nonnull final SignatureSigningParameters params) {
+        if (params.getSigningCredential() == null) {
+            log.debug("Validation failure: Unable to resolve signing credential");
+            return false;
+        }
+        if (params.getSignatureAlgorithm() == null) {
+            log.debug("Validation failure: Unable to resolve signing algorithm URI");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Convert the algorithms represented as strings, into Nimbus {@link Algorithm}s for later comparison.
+     * 
+     * @param algos the algorithms to convert
+     * 
+     * @return the converted algorithms
+     */
+    @Nonnull private List<JWSAlgorithm> convertSupportAlgorithmsToJwkAlgorithms(@Nonnull final List<String> algos) {
+        return algos.stream().map(JWSAlgorithm::parse).collect(Collectors.toList());
+    }
+
+    /**
+     * Check the credential supports one of the supported algorithms input. If it does, the algorithm it supports
+     * is returned. If none are supported, {@literal null} is returned.
+     * 
+     * @param credential the credential to test
+     * @param supportedAlgorithms the list of supported algorithms to check support for
+     * 
+     * @return the supported algorithm, or {@literal null} if none are supported
+     */
+    @Nullable private JWSAlgorithm credentialSupportsSigningAlgorithm(@Nonnull final Credential credential, 
+            @Nonnull final List<JWSAlgorithm> supportedAlgorithms) {
+    
+        for (final JWSAlgorithm algorithm : supportedAlgorithms) {
+            
+            if (JWSAlgorithm.Family.HMAC_SHA.contains(algorithm) && credential.getSecretKey() != null ||
+                  (JWSAlgorithm.Family.RSA.contains(algorithm) && 
+                    credential.getPrivateKey() instanceof RSAPrivateKey) ||
+                  (JWSAlgorithm.Family.EC.contains(algorithm)
+                    && credential.getPrivateKey() instanceof ECPrivateKey
+                    && curveMatchesESAlgorithm(Curve.forECParameterSpec(
+                                    ((java.security.interfaces.ECKey) credential.getPrivateKey()).getParams()),
+                            algorithm))) {
+                return algorithm;
+            } 
+        }
+        return null;
+    }
+    
+    /**
+     * Helper to match ECKey curve to JWS algorithm ES256, ES384 and ES512.
+     * 
+     * @param curve curve to match.
+     * @param algorithm algorithm to match.
+     * @return true if key curve matches algorithm, otherwise false.
+     */
+    // TODO: Move to helper
+    private boolean curveMatchesESAlgorithm(final Curve curve, final JWSAlgorithm algorithm) {
+        if (algorithm.equals(JWSAlgorithm.ES256)) {
+            return curve.equals(Curve.P_256);
+        }
+        if (algorithm.equals(JWSAlgorithm.ES384)) {
+            return curve.equals(Curve.P_384);
+        }
+        if (algorithm.equals(JWSAlgorithm.ES512)) {
+            return curve.equals(Curve.P_521);
+        }
+        return false;
+    }
+
+    /**
+     * Filter the set of algorithms against the set supported by the downstream OP.
+     * Always returns a new list reference. 
+     * 
+     * @param criteria the criteria to extract the OP's metadata from to check supported algorithms.
+     * @param algorithms the current set of supported algorithms
+     * 
+     * @return the current set of supported algorithms filtered by those also supported by the OP.
+     */
+    private List<String> filterForOPSupportedAlgorithms(
+            @Nonnull final CriteriaSet criteria, @Nonnull final List<String> algorithms) {
+
+        if (criteria.contains(ProviderMetadataCriterion.class)) {
+            final OIDCProviderMetadata metadata = criteria.get(ProviderMetadataCriterion.class).getMetadata();
+            
+            final List<String> opSupportedAlgNames = providerMetadataAlgorithmLookupStrategy.apply(metadata);
+            log.trace("Provider metadata supports the following signature algorithms '{}'",opSupportedAlgNames);
+            
+            if (opSupportedAlgNames == null) {
+                log.trace("Lookup strategy could not determine OP supported algorithms from metadata, "
+                        + "no further filtering performed");
+                return List.copyOf(algorithms);
+            }
+            return algorithms.stream().filter(opSupportedAlgNames::contains).collect(Collectors.toList());
+            
+        } else {
+            log.debug("No provider metadata criterion, unable to filter for OP supported algorithms");
+            return List.copyOf(algorithms);
+        }
+    }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/RelyingPartyProxySigningParametersResolverTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/RelyingPartyProxySigningParametersResolverTest.java
new file mode 100644
index 0000000..5bb5338
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/RelyingPartyProxySigningParametersResolverTest.java
@@ -0,0 +1,275 @@
+/*
+ * 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.idp.plugin.authn.oidc.rp.impl;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.time.Duration;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.opensaml.core.config.InitializationException;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.xmlsec.SignatureSigningParameters;
+import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
+import org.opensaml.xmlsec.criterion.SignatureSigningConfigurationCriterion;
+import org.opensaml.xmlsec.impl.BasicSignatureSigningConfiguration;
+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.JWK;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
+import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
+import com.nimbusds.oauth2.sdk.id.Issuer;
+import com.nimbusds.openid.connect.sdk.SubjectType;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.oidc.jwa.support.SignatureConstants;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
+import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.oidc.security.criterion.ProviderMetadataCriterion;
+import net.shibboleth.oidc.security.criterion.StaticCredentialCriterion;
+import net.shibboleth.oidc.security.impl.JWSAssemblyUtils;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** Tests for RelyingPartyProxySigningParametersResolver.*/
+public class RelyingPartyProxySigningParametersResolverTest extends AbstractOIDCTest {
+    
+    private RelyingPartyProxySigningParametersResolver resolver;
+    
+    private RelyingPartyContext rpc;
+    
+    private OIDCAuthorizationConfiguration oidcAuthzConfig;   
+    
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        resolver = new RelyingPartyProxySigningParametersResolver(); 
+        rpc = prc.getSubcontext(RelyingPartyContext.class, true); 
+        oidcAuthzConfig = new OIDCAuthorizationConfiguration();
+        final RelyingPartyConfiguration rpConfig = new RelyingPartyConfiguration();
+        rpc.setProfileConfig(oidcAuthzConfig);
+        rpc.setConfiguration(rpConfig);
+
+        //resolver.setAlgorithmRegistry(new AlgorithmRegistry());
+        resolver.setProviderMetadataAlgorithmLookupStrategy(
+                m -> m.getRequestObjectJWSAlgs().stream().map(JWSAlgorithm::getName).collect(Collectors.toList()));
+        
+      //Create an algorithm registry here, as opensaml init will not take place for these tests      
+        try {
+            final GlobalAlgorithmRegistryInitializer gar = new GlobalAlgorithmRegistryInitializer();
+            gar.init();
+        } catch (final InitializationException e) {           
+            fail();
+        }
+    }
+    
+    
+    @Test
+    public void testResolveSuccess_StaticCredentials() throws ResolverException {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_HS_256));
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertTrue(params.iterator().hasNext());
+        assertNotNull(params.iterator().next().getSigningCredential());
+        assertNotNull(params.iterator().next().getSigningCredential().getSecretKey());
+    }
+    
+    @Test
+    public void testResolveFail_StaticCredentials_UnsupportedMethod() throws ResolverException {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_RS_256));
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertFalse(params.iterator().hasNext());
+    }
+    
+    @Test
+    public void testResolveSuccess_StaticCredentials_ConfigSupportsOne() throws ResolverException {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_RS_256, 
+                SignatureConstants.ALGO_ID_SIGNATURE_HS_256));
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertTrue(params.iterator().hasNext());
+        assertNotNull(params.iterator().next().getSigningCredential());
+        assertNotNull(params.iterator().next().getSigningCredential().getSecretKey());
+    }
+    
+    @Test
+    public void testResolveSuccess_StaticCredentials_OPSupportsOne() throws ResolverException, URISyntaxException {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_RS_256, 
+                SignatureConstants.ALGO_ID_SIGNATURE_HS_256));
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        
+        // Now let the OP support one of those which matches the credential
+        final OIDCProviderMetadata metadata = 
+                new OIDCProviderMetadata(new Issuer("test"), List.of(SubjectType.PUBLIC), new URI("nowhere"));
+        metadata.setRequestObjectJWSAlgs(List.of(JWSAlgorithm.HS256));
+        criteria.add(new ProviderMetadataCriterion(metadata));
+        
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertTrue(params.iterator().hasNext());
+        assertNotNull(params.iterator().next().getSigningCredential());
+        assertNotNull(params.iterator().next().getSigningCredential().getSecretKey());
+    }
+    
+    @Test
+    public void testResolveSuccess_StaticCredentials_OPSupportsNone() throws ResolverException, URISyntaxException {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_RS_256, 
+                SignatureConstants.ALGO_ID_SIGNATURE_HS_256));
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        
+        // Now let the OP support none of those supported by the config
+        final OIDCProviderMetadata metadata = 
+                new OIDCProviderMetadata(new Issuer("test"), List.of(SubjectType.PUBLIC), new URI("nowhere"));
+        metadata.setRequestObjectJWSAlgs(List.of(JWSAlgorithm.EdDSA));
+        criteria.add(new ProviderMetadataCriterion(metadata));
+        
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertFalse(params.iterator().hasNext());
+    }
+    
+    @Test
+    public void testResolveSuccess_RSACredentials_OPSupportsOne() throws Exception {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_RS_256, 
+                SignatureConstants.ALGO_ID_SIGNATURE_HS_256));
+        
+        // Create the normal client_secret
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        
+        // Add an RSA type to the security config
+        final BasicSignatureSigningConfiguration config = 
+                (BasicSignatureSigningConfiguration) 
+                criteria.get(SignatureSigningConfigurationCriterion.class).getConfigurations().get(0);
+        
+        config.setSigningCredentials(List.of(createRSASigningCredential(new RSAKeyGenerator(2048)
+                .keyID("1")
+                .keyUse(KeyUse.SIGNATURE)
+                .generate())));
+        
+        // Now let the OP support one of those which matches one of the credentials
+        final OIDCProviderMetadata metadata = 
+                new OIDCProviderMetadata(new Issuer("test"), List.of(SubjectType.PUBLIC), new URI("nowhere"));
+        metadata.setRequestObjectJWSAlgs(List.of(JWSAlgorithm.RS256));
+        criteria.add(new ProviderMetadataCriterion(metadata));
+        
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertTrue(params.iterator().hasNext());
+        assertNotNull(params.iterator().next().getSigningCredential());
+        assertNotNull(params.iterator().next().getSigningCredential().getPrivateKey());
+        assertTrue(params.iterator().next().getSigningCredential().getPrivateKey() instanceof RSAPrivateKey);
+    }
+    
+    @Test
+    public void testResolveSuccess_ECCredentials_OPSupportsTwo() throws Exception {
+        final CriteriaSet criteria = buildCriteria(List.of(SignatureConstants.ALGO_ID_SIGNATURE_RS_256, 
+                SignatureConstants.ALGO_ID_SIGNATURE_HS_256, SignatureConstants.ALGO_ID_SIGNATURE_ES_256));
+        
+        // Create the normal client_secret
+        criteria.add(new StaticCredentialCriterion(createClientSecretCredential("atestsecret")));
+        
+        // Add an RSA type to the security config
+        final BasicSignatureSigningConfiguration config = 
+                (BasicSignatureSigningConfiguration) 
+                criteria.get(SignatureSigningConfigurationCriterion.class).getConfigurations().get(0);
+        
+        config.setSigningCredentials(List.of(createRSASigningCredential(
+                new ECKeyGenerator(Curve.P_256).keyID("123").generate())));
+        
+        // Now let the OP support one of those which matches one of the credentials
+        final OIDCProviderMetadata metadata = 
+                new OIDCProviderMetadata(new Issuer("test"), List.of(SubjectType.PUBLIC), new URI("nowhere"));
+        metadata.setRequestObjectJWSAlgs(List.of(JWSAlgorithm.RS256, JWSAlgorithm.ES256));
+        criteria.add(new ProviderMetadataCriterion(metadata));
+        
+        final Iterable<SignatureSigningParameters> params = resolver.resolve(criteria);
+        assertNotNull(params);
+        assertTrue(params.iterator().hasNext());
+        assertNotNull(params.iterator().next().getSigningCredential());
+        assertNotNull(params.iterator().next().getSigningCredential().getPrivateKey());
+        assertTrue(params.iterator().next().getSigningCredential().getPrivateKey() instanceof ECPrivateKey);
+    }
+    
+    
+    private CriteriaSet buildCriteria(final List<String> supportedSigningAlgos) {
+        final CriteriaSet crit = new CriteriaSet();
+        final BasicSignatureSigningConfiguration config = new BasicSignatureSigningConfiguration();
+        config.setSignatureAlgorithms(supportedSigningAlgos);
+        crit.add(new SignatureSigningConfigurationCriterion(List.of(config)));
+        return crit;
+    }
+    
+    private JWKCredential createClientSecretCredential(final String secret) {
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setSecretKey(new SecretKeySpec(JWSAssemblyUtils.getSecretBytes(secret), "NONE"));
+        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
+        jwkCredential.setUsageType(UsageType.UNSPECIFIED);
+        jwkCredential.setKid("mockKey");
+        jwkCredential.getKeyNames().add("mockKey");
+        return jwkCredential;
+    }
+    
+    /**
+     * Create an AsymmetricJWK credential from the given key.
+     * 
+     * @param secret the key to convert to a {@link JWKCredential}.
+     * 
+     * @return the credential
+     * @throws JOSEException 
+     */
+    private JWKCredential createRSASigningCredential(final JWK secret) throws JOSEException {
+        assertTrue(secret instanceof AsymmetricJWK);
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setPrivateKey(((AsymmetricJWK)secret).toPrivateKey());
+        jwkCredential.setPublicKey(((AsymmetricJWK)secret).toPublicKey());
+        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
+        jwkCredential.setUsageType(UsageType.SIGNING);
+        
+        jwkCredential.setKid(secret.getKeyID());
+        jwkCredential.getKeyNames().add("mockKey");
+        jwkCredential.setAlgorithm(secret.getAlgorithm());
+        return jwkCredential;
+    }
+
+}

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


More information about the commits mailing list