[java-oidc-common] 04/35: Add criterion credential resolver

Phil Smart philip.smart at jisc.ac.uk
Tue Sep 20 14:19:04 UTC 2022


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

philsmart pushed a commit to branch dev/JCOMOIDC-41
in repository java-oidc-common.

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

commit f2e26cb1b1429ba616571b44188c489a6195862b
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri May 20 10:39:19 2022 +0100

    Add criterion credential resolver
    
    - Pass client credential from profile config into trust engine
    - Add a factory bean for creating static JWK credentials
---
 .../credential/BasicExpiringJWKCredential.java     |  33 +++++++
 .../security/credential/ExpiringJWKCredential.java |  21 ++++
 .../criterion/ProviderMetadataCriterion.java       |   2 +-
 .../criterion/StaticCredentialCriterion.java       |  70 ++++++++++++++
 oidc-common-crypto-impl/pom.xml                    |  11 ++-
 .../impl/BaseJWTSignatureSecurityHandler.java      |  71 +++++++++++++-
 ...asicExpiringJWTStaticCredentialFactoryBean.java |  86 +++++++++++++++++
 .../security/impl/CriterionCredentialResolver.java | 107 +++++++++++++++++++++
 .../impl/ExplicitKeySignedJWTTrustEngine.java      |   1 +
 .../impl/ProviderMetadataCredentialResolver.java   |  12 ++-
 .../config/OIDCAuthorizationConfiguration.java     |  83 +++++++++++++++-
 .../profile/config/OIDCSecurityConfiguration.java  |   9 +-
 12 files changed, 488 insertions(+), 18 deletions(-)

diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicExpiringJWKCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicExpiringJWKCredential.java
new file mode 100644
index 0000000..5cf2c67
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicExpiringJWKCredential.java
@@ -0,0 +1,33 @@
+package net.shibboleth.oidc.security.credential;
+
+import java.time.Duration;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Basic implementation of an ExpiringJWKCredential.*/
+public class BasicExpiringJWKCredential extends BasicJWKCredential implements ExpiringJWKCredential {
+    
+    /** 
+     * When the credential expires in seconds since 1970-01-01T0:0:0Z.
+     * 0 seconds represents no expiry.
+     */
+    @Nullable private Duration credentialExpiresAt;
+
+    @Override
+    public Duration getCredentialExpiresAt() {
+        return credentialExpiresAt;
+    }
+    
+    /**
+     * Set the expiry in seconds since 1970-01-01T0:0:0Z.
+     * 
+     * @param expiresAt the expiry.
+     */
+    public void setCredentialExpiresAt(@Nonnull final Duration expiresAt) {
+        credentialExpiresAt = Constraint.isNotNull(expiresAt, "Credential expiry can not be null");
+    }
+
+}
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ExpiringJWKCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ExpiringJWKCredential.java
new file mode 100644
index 0000000..46d6940
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ExpiringJWKCredential.java
@@ -0,0 +1,21 @@
+package net.shibboleth.oidc.security.credential;
+
+import java.time.Duration;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@link JWKCredential credential} that expires at some duration in seconds after 1970-01-01T0:0:0Z.
+ * A value of 0 seconds represents a credential that does not expire. 
+ */
+public interface ExpiringJWKCredential extends JWKCredential {
+    
+    /**
+     * Time at which the client_secret will expire or 0 if it will not expire. Its value represents 
+     * the number of seconds from 1970-01-01T0:0:0Z.
+     * 
+     * @return the expiry duration
+     */
+    @Nullable Duration getCredentialExpiresAt();
+
+}
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/ProviderMetadataCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/ProviderMetadataCriterion.java
index 6ac0817..1a3359d 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/ProviderMetadataCriterion.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/ProviderMetadataCriterion.java
@@ -76,7 +76,7 @@ public class ProviderMetadataCriterion implements Criterion {
             return false;
         }
 
-        if (obj instanceof RoleDescriptorCriterion) {
+        if (obj instanceof ProviderMetadataCriterion) {
             return metadata.equals(((ProviderMetadataCriterion) obj).metadata);
         }
 
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/StaticCredentialCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/StaticCredentialCriterion.java
new file mode 100644
index 0000000..4ccafa5
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/StaticCredentialCriterion.java
@@ -0,0 +1,70 @@
+package net.shibboleth.oidc.security.criterion;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.saml.criterion.RoleDescriptorCriterion;
+import org.opensaml.security.credential.Credential;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.Criterion;
+
+/** A {@link Criterion} that holds a single credential.*/
+public class StaticCredentialCriterion implements Criterion {
+    
+    /** The credential to hold.*/
+    @Nonnull private final Credential credential;
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param cred the credential to hold.
+     */
+    public StaticCredentialCriterion(@Nonnull final Credential cred) {
+        credential = Constraint.isNotNull(cred, "Credential can not be null");
+    }
+    
+    /**
+     * The held credential.
+     * 
+     * @return the credential
+     */
+    @Nonnull public Credential getCredential() {
+        return credential;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("StaticCredentialCriterion [credential=");
+        builder.append(credential);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return credential.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof StaticCredentialCriterion) {
+            return credential.equals(((StaticCredentialCriterion) obj).credential);
+        }
+
+        return false;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/pom.xml b/oidc-common-crypto-impl/pom.xml
index 097c258..c7c8b24 100644
--- a/oidc-common-crypto-impl/pom.xml
+++ b/oidc-common-crypto-impl/pom.xml
@@ -30,7 +30,11 @@
             <artifactId>nimbus-jose-jwt</artifactId>
             <scope>compile</scope>
         </dependency>
-
+         <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>oidc-common-profile-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>oidc-common-crypto-api</artifactId>
@@ -45,6 +49,11 @@
             <groupId>${idp.groupId}</groupId>
             <artifactId>idp-authn-api</artifactId>
             <scope>provided</scope>
+        </dependency>
+         <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-profile-spring</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
index cf9fa26..93a63b9 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
@@ -23,17 +23,25 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
 import org.opensaml.security.credential.UsageType;
 import org.opensaml.security.criteria.UsageCriterion;
 import org.opensaml.security.messaging.impl.BaseTrustEngineSecurityHandler;
 import org.opensaml.security.trust.TrustEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
 
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
 import net.shibboleth.oidc.security.context.JWTSecurityParametersContext;
 import net.shibboleth.oidc.security.criterion.ProviderMetadataCriterion;
+import net.shibboleth.oidc.security.criterion.StaticCredentialCriterion;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.logic.FunctionSupport;
@@ -41,18 +49,33 @@ import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 
 public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSecurityHandler<SignedJWT> {
     
+    /** Class logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(BaseJWTSignatureSecurityHandler.class);
+    
+    /** Lookup function for parent ProfileRequestContext. */
+    @Nonnull private static final ParentProfileRequestContextLookup<MessageContext> PRC_LOOKUP
+        = new ParentProfileRequestContextLookup<>();
+    
     /** 
      * Function that looks up provider metadata from the given message context. Can return {@literal null}
      * if not used.
      */
     @Nonnull private Function<MessageContext, OIDCProviderMetadata> providerMetadataLookupStrategy;
     
+    /** Lookup function for relying party context. */
+    @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+    
+    /** Applicable stashed profile configuration. */
+    @Nullable private OIDCAuthorizationConfiguration profileConfiguration;
+    
     /** The provider metadata found from the lookup strategy.*/
     @Nullable private OIDCProviderMetadata providerMetadata;
 
     /** Constructor.*/
     protected BaseJWTSignatureSecurityHandler() {
         providerMetadataLookupStrategy = FunctionSupport.constant(null);
+        relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
     }
     
     /**
@@ -65,7 +88,21 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         providerMetadataLookupStrategy = 
-                Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
+                Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");       
+        
+    }
+    
+    /**
+     * Set lookup strategy for relying party context.
+     * 
+     * @param strategy  lookup strategy
+     */
+    public void setRelyingPartyContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        relyingPartyContextLookupStrategy =
+                Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
     }
     
     @Override
@@ -86,6 +123,13 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
             return false;
         }        
         providerMetadata = providerMetadataLookupStrategy.apply(messageContext);  
+        
+        final RelyingPartyContext rpCtx = adapt(relyingPartyContextLookupStrategy).apply(messageContext);     
+        if (rpCtx != null && rpCtx.getConfiguration() != null &&
+                rpCtx.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
+            profileConfiguration = (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
+        }
+
         return true;
     }
 
@@ -98,9 +142,11 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
         if (providerMetadata != null) {
             criteriaSet.add(new ProviderMetadataCriterion(providerMetadata));
         }
-//        if (!Strings.isNullOrEmpty(entityID)) {
-//            criteriaSet.add(new EntityIdCriterion(entityID) );
-//        }
+        
+        if (profileConfiguration != null) {
+            criteriaSet.add(new StaticCredentialCriterion(
+                    profileConfiguration.getClientCredential(PRC_LOOKUP.apply(messageContext))));
+        }
        
         criteriaSet.add( new UsageCriterion(UsageType.SIGNING) );
         
@@ -113,6 +159,23 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
         
         return criteriaSet;
     }
+    
+    /**
+     * Adapt a {@link ProfileRequestContext} function to a {@link MessageContext} function via composing
+     * with a lookup function.
+     * 
+     * @param function the profile request context function
+     * @return the message context function
+     * 
+     * @param <T> the output type of the functions
+     */
+    @Nullable protected <T> Function<MessageContext, T> adapt(
+            @Nullable final Function<ProfileRequestContext, T> function) {
+        if (function == null) {
+            return null;
+        }
+        return function.compose(PRC_LOOKUP);
+    }
 
 
 }
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTStaticCredentialFactoryBean.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTStaticCredentialFactoryBean.java
new file mode 100644
index 0000000..851a31b
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTStaticCredentialFactoryBean.java
@@ -0,0 +1,86 @@
+package net.shibboleth.oidc.security.impl;
+
+import java.time.Duration;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.opensaml.security.credential.UsageType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Enums;
+
+import net.shibboleth.idp.profile.spring.factory.AbstractCredentialFactoryBean;
+import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.credential.ExpiringJWKCredential;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** A factory bean for creating a {@link BasicExpiringJWKCredential} from the static secret injected.*/
+//TODO do we need to fix the algorithm here? maybe not, as it depends on its usage
+public class BasicExpiringJWTStaticCredentialFactoryBean extends AbstractCredentialFactoryBean<ExpiringJWKCredential> {
+    
+    /** Class logger. */
+    private final Logger log = LoggerFactory.getLogger(BasicExpiringJWTStaticCredentialFactoryBean.class);
+    
+    /** The secret to use when creating a BasicJWKCredential.*/
+    @Nullable private String secret;
+    
+    /** 
+     * When the credential expires in seconds since 1970-01-01T0:0:0Z.
+     * 0 seconds represents no expiry. Defaults to 0.
+     */
+    @Nonnull private Duration credentialExpiresAt;
+    
+    /** Constructor.*/
+    public BasicExpiringJWTStaticCredentialFactoryBean() {
+        credentialExpiresAt = Duration.ZERO;
+    }
+    
+    /**
+     * Set the expiry in seconds since 1970-01-01T0:0:0Z.
+     * 
+     * @param expiresAt the expiry.
+     */
+    public void setCredentialExpiresAt(@Nonnull final Duration expiresAt) {
+        credentialExpiresAt = Constraint.isNotNull(expiresAt, "Credential expiry can not be null");
+    }
+    
+    /** 
+     * Set the secret to use. 
+     * 
+     * @param secretIn the secret
+     */
+    public void setSecret(@Nonnull @NotEmpty final String secretIn) {
+        secret = Constraint.isNotEmpty(secretIn, "Secret can not be null or empty");
+    }
+
+    @Override
+    protected ExpiringJWKCredential doCreateInstance() throws Exception {
+        
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setSecretKey(new SecretKeySpec(JWSAssemblyUtils.getSecretBytes(secret), "NONE"));
+        jwkCredential.setCredentialExpiresAt(credentialExpiresAt);
+        jwkCredential.setEntityId(getEntityID());
+        if (getUsageType() != null) {
+            jwkCredential.setUsageType(Enums.getIfPresent(UsageType.class, getUsageType()).or(UsageType.UNSPECIFIED));
+        } else {
+            jwkCredential.setUsageType(UsageType.UNSPECIFIED);
+        }
+        final List<String> keyNames = getKeyNames();
+        if (keyNames != null) {
+            jwkCredential.getKeyNames().addAll(keyNames);
+        }
+        return jwkCredential;
+    }
+
+    @Override
+    public Class<?> getObjectType() {
+        return BasicJWKCredential.class;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CriterionCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CriterionCredentialResolver.java
new file mode 100644
index 0000000..4d93160
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CriterionCredentialResolver.java
@@ -0,0 +1,107 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.security.credential.impl.AbstractCriteriaFilteringCredentialResolver;
+import org.opensaml.security.criteria.KeyAlgorithmCriterion;
+import org.opensaml.security.criteria.UsageCriterion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.oidc.security.criterion.StaticCredentialCriterion;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * Extracts the credential from the {@link StaticCredentialCriterion} inside the given criteria set,
+ * inspects its suitability and passes it back.
+ */
+//TODO Docs
+//TODO Algorithm filters?
+public class CriterionCredentialResolver extends AbstractCriteriaFilteringCredentialResolver {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(CriterionCredentialResolver.class);
+    
+    @Override
+    protected Iterable<Credential> resolveFromSource(@Nonnull final CriteriaSet criteriaSet) throws ResolverException {        
+        Constraint.isNotNull(criteriaSet, "CriteriaSet was null");
+        
+        final UsageType usage = getEffectiveUsageInput(criteriaSet);
+        
+        if (criteriaSet.contains(StaticCredentialCriterion.class)) {
+            final StaticCredentialCriterion credentialCriterion = criteriaSet.get(StaticCredentialCriterion.class);
+            final Credential credential = credentialCriterion.getCredential();
+            if (matchUsage(credential.getUsageType(), usage)) { 
+                
+                final KeyAlgorithmCriterion keyAlg = criteriaSet.get(KeyAlgorithmCriterion.class);
+                
+                log.debug("Selected key '{}', for usage '{}', matched to alg '{}'", 
+                        credential.getKeyNames(),usage, keyAlg);
+                return List.of(credential);                
+            } else {
+                log.warn("Usage type of credential from criteria did not match the effective usage input");
+                return Collections.emptyList();
+            }
+        } else {
+            log.warn("Criteria did not contain a StaticCredentialCriterion " 
+                    + "could not perform resolution");
+            return Collections.emptyList();
+        }
+    }
+    
+    
+    /**
+     * Match usage enum type values from credential in the criteria set to the usage in the criteria.
+     * 
+     * @param credentialUsage the value from the credential in the criteria set
+     * @param criteriaUsage the value from credential criteria
+     * @return true if the two usage specifiers match for purposes of resolving credentials, false otherwise
+     */
+    protected boolean matchUsage(@Nonnull final UsageType credentialUsage, @Nonnull final UsageType criteriaUsage) {
+        if (credentialUsage == UsageType.UNSPECIFIED || criteriaUsage == UsageType.UNSPECIFIED) {
+            return true;
+        }
+        return credentialUsage == criteriaUsage;
+    }
+
+    /**
+     * Get the effective {@link UsageType} input to use.
+     * 
+     * @param criteriaSet the criteria set being processed
+     * @return the effective usage value
+     */
+    @Nonnull protected UsageType getEffectiveUsageInput(@Nonnull final CriteriaSet criteriaSet) {
+        final UsageCriterion usageCriteria = criteriaSet.get(UsageCriterion.class);
+        if (usageCriteria != null) {
+            return usageCriteria.getUsage();
+        }
+        return UsageType.UNSPECIFIED; 
+    }
+
+
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngine.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngine.java
index 0f8ca2f..3ecdf82 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngine.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngine.java
@@ -79,6 +79,7 @@ public class ExplicitKeySignedJWTTrustEngine extends BaseSignedJWTTrustEngine<It
             criteriaSet.add(new UsageCriterion(UsageType.SIGNING));
         }
         
+        // TODO these need matching?
         final String jcaAlgorithm = AlgorithmSupport.getKeyAlgorithm(signedJWT.getHeader().getAlgorithm().getName());
         if (!Strings.isNullOrEmpty(jcaAlgorithm)) {
             criteriaSet.add(new KeyAlgorithmCriterion(jcaAlgorithm), true);
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataCredentialResolver.java
index f649997..f94a120 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataCredentialResolver.java
@@ -27,6 +27,7 @@ import javax.annotation.Nonnull;
 import org.opensaml.security.credential.Credential;
 import org.opensaml.security.credential.UsageType;
 import org.opensaml.security.credential.impl.AbstractCriteriaFilteringCredentialResolver;
+import org.opensaml.security.criteria.KeyAlgorithmCriterion;
 import org.opensaml.security.criteria.UsageCriterion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -128,8 +129,6 @@ public class ProviderMetadataCredentialResolver extends AbstractCriteriaFilterin
         
         final LinkedHashSet<Credential> credentials = new LinkedHashSet<>(1);
         
-        // TODO: Need something like this final List<String> algorithms = 
-        // getEffectiveSignatureAlgorithms(criteria, whitelistBlacklistPredicate);
         if (metadata.getJWKSetURI() != null) {
             final JWKSet keySet = remoteJwkSetCache.fetch(metadata.getJWKSetURI(),
                     Instant.now().plus(keyFetchInterval));
@@ -139,6 +138,9 @@ public class ProviderMetadataCredentialResolver extends AbstractCriteriaFilterin
                     continue;
                 }
                 // Check against supported algo's here? although OP should only have keys for algo's it supports?
+                //TODO needs to support the JWA alg names first?
+                final KeyAlgorithmCriterion keyAlg = criteriaSet.get(KeyAlgorithmCriterion.class);
+                
                 if (key instanceof RSAKey || key instanceof ECKey) {
                     final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                     jwkCredential.setAlgorithm(key.getAlgorithm());
@@ -147,11 +149,11 @@ public class ProviderMetadataCredentialResolver extends AbstractCriteriaFilterin
                     try {
                         jwkCredential.setPublicKey(((AsymmetricJWK) key).toPublicKey());
                     } catch (final JOSEException e) {
-                        log.warn("Unable to parse key from keyset");
+                        log.warn("Unable to parse key '{}' from keyset", key.getKeyID());
                         continue;
                     }
-                    log.debug("Selected key '{}', of type '{}', for alg '{}'", 
-                            key.getKeyID(), key.getKeyType(), key.getAlgorithm());
+                    log.debug("Selected key '{}', of type '{}', matched to alg '{}'", 
+                            key.getKeyID(), key.getKeyType(), keyAlg);
                     credentials.add(jwkCredential);
                 }                
             }            
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
index fc3ab2f..708f902 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
@@ -30,9 +30,9 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.security.credential.Credential;
 
 import com.google.common.base.Predicates;
-import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.profile.config.OverriddenIssuerProfileConfiguration;
@@ -114,8 +114,15 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
      */
     @Nonnull private Function<ProfileRequestContext, String> clientIdLookupStrategy;
 
+    /**
+     * Lookup function to retrieve a client credential from the given profile request context.
+     */
+    @Nonnull private Function<ProfileRequestContext, Credential> clientCredentialLookupStrategy;
+
     /** Lookup function to determine the client_authentication method.  */
-    @Nonnull private Function<ProfileRequestContext, ClientAuthentication> clientAuthenticationLookupStrategy;
+//    @Nonnull private Function<ProfileRequestContext, ClientAuthentication> clientAuthenticationLookupStrategy;
+    //TODO same as tokenEndpointAuthMethodsLookupStrategy?
+    @Nonnull private Function<ProfileRequestContext, String> clientAuthenticationMethodLookupStrategy;
 
     /**
      * Constructor.
@@ -143,7 +150,8 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
         deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
         redirectUriOverrideLookupStrategy = FunctionSupport.constant(null);
         clientIdLookupStrategy = FunctionSupport.constant(null);
-        clientAuthenticationLookupStrategy = FunctionSupport.constant(null);
+        clientAuthenticationMethodLookupStrategy = FunctionSupport.constant(null);
+        clientCredentialLookupStrategy = FunctionSupport.constant(null);
         httpRequestMethodLookupStrategy = FunctionSupport.constant(OIDCHttpRequestMethod.GET);
 
         includeIssuerInResponsePredicate = Predicates.alwaysFalse();
@@ -166,7 +174,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
      * @param clientId the static clientId to use
      */
     public void setClientId(@Nullable final String clientId) {
-        clientIdLookupStrategy = FunctionSupport.constant(clientId);
+        clientIdLookupStrategy = FunctionSupport.constant(StringSupport.trimOrNull(clientId));
     }
 
     /**
@@ -206,6 +214,73 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
         return clientIdLookupStrategy.apply(profileRequestContext);
     }
 
+     /**
+     * Set the client authentication method lookup strategy which will locate the client_authentication method
+     * for a given client.
+     *
+     * @param strategy the strategy to use
+     */
+    public void setClientAuthenticationMethodLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, String> strategy) {
+        clientAuthenticationMethodLookupStrategy =
+                Constraint.isNotNull(strategy, "Client authentication strategy can not be null");
+    }
+
+    /**
+     * Set the client authentication method.
+     *
+     * @param clientAuthMethod the client_authentication method
+     */
+    public void setClientAuthenticationMethod(@Nullable final String clientAuthMethod) {
+        clientAuthenticationMethodLookupStrategy = FunctionSupport.constant(clientAuthMethod);
+    }
+
+     /**
+      * Get the client_authentication for the given context. Typically that associated with the
+      * current client_id.
+      *
+      * @param profileRequestContext the profile request context
+      *
+      * @return the client_authentication method
+      */
+     public String getClientAuthenticationMethod(
+             @Nullable final ProfileRequestContext profileRequestContext) {
+         return clientAuthenticationMethodLookupStrategy.apply(profileRequestContext);
+     }
+
+    /**
+     * Set the client credential lookup strategy.
+     *
+     * @param strategy the strategy to use
+     */
+    public void setClientCredentialLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, Credential> strategy) {
+        clientCredentialLookupStrategy =
+                Constraint.isNotNull(strategy, "Client credential lookup strategy can not be null");
+    }
+
+    /**
+     * Set a fixed client credential to use no matter what the context/request.
+     *
+     * @param clientCredential the static client credential to use
+     */
+    public void setClientCredential(@Nullable final Credential clientCredential) {
+        clientCredentialLookupStrategy = FunctionSupport.constant(clientCredential);
+    }
+
+    /**
+     * Get the client credential for the given context. Typically a client_secret
+     * associated with the current client_id.
+     *
+     * @param profileRequestContext the profile request context
+     *
+     * @return the client credential
+     */
+    public Credential getClientCredential(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return clientCredentialLookupStrategy.apply(profileRequestContext);
+    }
+
     /**
      * Set the redirect_uri lookup strategy to use to locate an override redirect_rui.
      *
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java
index f948cb4..c8399ef 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java
@@ -22,6 +22,8 @@ import javax.annotation.Nullable;
 import org.opensaml.xmlsec.EncryptionConfiguration;
 import org.opensaml.xmlsec.SignatureSigningConfiguration;
 
+import com.nimbusds.jwt.SignedJWT;
+
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
 
 /**
@@ -44,7 +46,7 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
     
     /** Configuration used when validating id_token JWT signatures. */
     @Nullable
-    private net.shibboleth.oidc.security.SignatureValidationConfiguration<?> idTokenJwtSignatureValidationConfig;
+    private net.shibboleth.oidc.security.SignatureValidationConfiguration<SignedJWT> idTokenJwtSignatureValidationConfig;
 
     /**
      * Get the configuration used when decrypting request object information.
@@ -110,7 +112,7 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
      * @return configuration used when validating id_token JWT signatures, or null
      */
     @Nullable
-    public net.shibboleth.oidc.security.SignatureValidationConfiguration<?> getIdTokenJwtSignatureValidationConfig() {
+    public net.shibboleth.oidc.security.SignatureValidationConfiguration<SignedJWT> getIdTokenJwtSignatureValidationConfig() {
         return idTokenJwtSignatureValidationConfig;
     }
 
@@ -119,7 +121,8 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
      * 
      * @param config configuration used when validating id_token JWT signatures, or null
      */
-    public void setIdTokenJwtSignatureValidationConfig(@Nullable final  net.shibboleth.oidc.security.SignatureValidationConfiguration<?> config) {
+    public void setIdTokenJwtSignatureValidationConfig(
+            @Nullable final net.shibboleth.oidc.security.SignatureValidationConfiguration<SignedJWT> config) {
         idTokenJwtSignatureValidationConfig = config;
     }
 

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


More information about the commits mailing list