[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