[java-oidc-common] 01/02: JCOMOIDC-112 - Profile configuration settings for OAuth2 DPoP

Henri Mikkonen henri.mikkonen at iki.fi
Wed May 8 09:46:04 UTC 2024


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

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

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

commit ad04d27db6887fe0bc6e1dec78409233683f6a55
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed May 8 12:38:48 2024 +0300

    JCOMOIDC-112 - Profile configuration settings for OAuth2 DPoP
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-112
    
    - New interface OAuth2DPoPProofValidatingProfileConfiguration
      - Inherited by OAuth2ClientAuthenticableProfileConfiguration and OAuth2PushedAuthorizationRequestConfiguration
      - Implemented in AbstractOAuth2ClientAuthenticableProfileConfiguration
    - Included requireDpopJkt-setting to OAuth2AuthorizationProfileConfiguration
      - Implemented in DefaultOIDCAuthorizationConfiguration
    - Included new DPoP-specific event IDs
---
 .../logic/RequireDPoPJktParameterPredicate.java    |  47 ++++++++++
 .../config/logic/RequireDPoPProofPredicate.java    |  47 ++++++++++
 .../DPoPProofClaimsValidatorLookupFunction.java    |  53 +++++++++++
 ...atureValidationConfigurationLookupFunction.java |  62 +++++++++++++
 .../shibboleth/oidc/profile/core/OidcEventIds.java |  21 +++++
 .../OAuth2AuthorizationProfileConfiguration.java   |  11 +++
 ...th2ClientAuthenticableProfileConfiguration.java |   4 +-
 ...th2DPoPProofValidatingProfileConfiguration.java |  64 +++++++++++++
 ...th2PushedAuthorizationRequestConfiguration.java |   4 +-
 .../DefaultOIDCAuthorizationConfiguration.java     |  32 +++++++
 ...th2ClientAuthenticableProfileConfiguration.java | 102 +++++++++++++++++++++
 11 files changed, 443 insertions(+), 4 deletions(-)

diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/RequireDPoPJktParameterPredicate.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/RequireDPoPJktParameterPredicate.java
new file mode 100644
index 0000000..0d5fc6d
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/RequireDPoPJktParameterPredicate.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.logic;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.logic.AbstractRelyingPartyPredicate;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2AuthorizationProfileConfiguration;
+
+/**
+ * A predicate implementation that forwards to
+ * {@link OAuth2AuthorizationProfileConfiguration#isRequireDpopJkt(ProfileRequestContext)}. Defaults to false.
+ * 
+ * @since 3.2.0
+ */
+public class RequireDPoPJktParameterPredicate extends AbstractRelyingPartyPredicate {
+    
+    /** {@inheritDoc} */
+    @Override
+    public boolean test(@Nullable final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc instanceof OAuth2AuthorizationProfileConfiguration oapc) {
+                return oapc.isRequireDpopJkt(input);
+            }
+        }
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/RequireDPoPProofPredicate.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/RequireDPoPProofPredicate.java
new file mode 100644
index 0000000..fd8750a
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/RequireDPoPProofPredicate.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.logic;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.logic.AbstractRelyingPartyPredicate;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2PushedAuthorizationRequestConfiguration;
+
+/**
+ * A predicate implementation that forwards to
+ * {@link OAuth2PushedAuthorizationRequestConfiguration#isRequireDpopProof(ProfileRequestContext)}. Defaults to false.
+ * 
+ * @since 3.2.0
+ */
+public class RequireDPoPProofPredicate extends AbstractRelyingPartyPredicate {
+    
+    /** {@inheritDoc} */
+    @Override
+    public boolean test(@Nullable final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc instanceof OAuth2PushedAuthorizationRequestConfiguration oapc) {
+                return oapc.isRequireDpopProof(input);
+            }
+        }
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/DPoPProofClaimsValidatorLookupFunction.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/DPoPProofClaimsValidatorLookupFunction.java
new file mode 100644
index 0000000..3f92ebe
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/DPoPProofClaimsValidatorLookupFunction.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.navigate;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2DPoPProofValidatingProfileConfiguration;
+
+/**
+ * A function that obtains
+ * {@link OAuth2DPoPProofValidatingProfileConfiguration#getDpopProofClaimsValidator(ProfileRequestContext)}
+ * if such a profile is available from a {@link RelyingPartyContext} obtained via a lookup function,
+ * by default a child of the {@link ProfileRequestContext}.
+ * 
+ * <p>If a specific setting is unavailable, a null value is returned.</p>
+ * 
+ * @since 3.2.0
+ */
+public class DPoPProofClaimsValidatorLookupFunction extends AbstractRelyingPartyLookupFunction<ClaimsValidator> {
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable public ClaimsValidator apply(@Nullable final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc instanceof OAuth2DPoPProofValidatingProfileConfiguration odpvpc) {
+                return odpvpc.getDpopProofClaimsValidator(input);
+            }
+        }
+        
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/DPoPProofSignatureValidationConfigurationLookupFunction.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/DPoPProofSignatureValidationConfigurationLookupFunction.java
new file mode 100644
index 0000000..66ffd44
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/DPoPProofSignatureValidationConfigurationLookupFunction.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.navigate;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2DPoPProofValidatingProfileConfiguration;
+import net.shibboleth.oidc.security.jose.SignatureValidationConfiguration;
+
+/**
+ * A function that obtains {@link
+ * OAuth2DPoPProofValidatingProfileConfiguration#getDpopProofSignatureValidationConfiguration(ProfileRequestContext)}
+ * if such a profile is available from a {@link RelyingPartyContext} obtained via a lookup function,
+ * by default a child of the {@link ProfileRequestContext}. The value is returned as a single-valued list.
+ * 
+ * <p>If a specific setting is unavailable, an empty list value is returned.</p>
+ * 
+ * @since 3.2.0
+ */
+public class DPoPProofSignatureValidationConfigurationLookupFunction
+    extends AbstractRelyingPartyLookupFunction<List<SignatureValidationConfiguration>> {
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull public List<SignatureValidationConfiguration> apply(@Nullable final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc instanceof OAuth2DPoPProofValidatingProfileConfiguration odpvpc) {
+                final SignatureValidationConfiguration config =
+                        odpvpc.getDpopProofSignatureValidationConfiguration(input);
+                if (config != null) {
+                    return CollectionSupport.listOf(config);
+                }
+            }
+        }
+        
+        return CollectionSupport.emptyList();
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/core/OidcEventIds.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/core/OidcEventIds.java
index a0ae31f..b54e86c 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/core/OidcEventIds.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/core/OidcEventIds.java
@@ -154,6 +154,27 @@ public final class OidcEventIds {
      */
     @Nonnull @NotEmpty public static final String SESSION_NOT_FOUND = "SessionNotFound";
 
+    /**
+     * ID of event returned if the mandatory dpop_jkt parameter is missing.
+     * 
+     * @since 3.2.0
+     */
+    @Nonnull @NotEmpty public static final String MISSING_DPOP_JKT = "DPoPJktRequired";
+
+    /**
+     * ID of event returned if the mandatory DPoP proof is missing.
+     * 
+     * @since 3.2.0
+     */
+    @Nonnull @NotEmpty public static final String MISSING_DPOP_PROOF = "DPoPProofRequired";
+
+    /**
+     * ID of event returned if the DPoP proof is invalid.
+     * 
+     * @since 3.2.0
+     */
+    @Nonnull @NotEmpty public static final String INVALID_DPOP_PROOF = "DPoPProofInvalid";
+
     /**
      * Constructor.
      */
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2AuthorizationProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2AuthorizationProfileConfiguration.java
index 3c6530c..52f5130 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2AuthorizationProfileConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2AuthorizationProfileConfiguration.java
@@ -117,4 +117,15 @@ public interface OAuth2AuthorizationProfileConfiguration {
     @ConfigurationSetting(name="requireAuthenticationRequest")
     boolean isRequireAuthenticationRequest(@Nullable final ProfileRequestContext profileRequestContext);
 
+    /**
+     * Get whether client is required to include jkt parameter in authorization requests.
+     *
+     * @param profileRequestContext the profile request context
+     *
+     * @return whether client is required to include jkt parameter in authorization requests
+     * 
+     * @since 3.2.0
+     */
+    @ConfigurationSetting(name="requireDpopJkt")
+    boolean isRequireDpopJkt(@Nullable final ProfileRequestContext profileRequestContext);
 }
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2ClientAuthenticableProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2ClientAuthenticableProfileConfiguration.java
index 48a6038..e03c884 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2ClientAuthenticableProfileConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2ClientAuthenticableProfileConfiguration.java
@@ -31,8 +31,8 @@ import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 
 /** OAuth 2.0 profile configurations that support OAuth-defined client authentication methods.*/
-public interface OAuth2ClientAuthenticableProfileConfiguration 
-                    extends AuthenticationProfileConfiguration, OAuth2ProfileConfiguration {
+public interface OAuth2ClientAuthenticableProfileConfiguration  extends AuthenticationProfileConfiguration,
+        OAuth2ProfileConfiguration, OAuth2DPoPProofValidatingProfileConfiguration {
     
     /**
      * Get the {@link ClaimsValidator} to apply to JWT-based client authentication.
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2DPoPProofValidatingProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2DPoPProofValidatingProfileConfiguration.java
new file mode 100644
index 0000000..a3d79ab
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2DPoPProofValidatingProfileConfiguration.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package net.shibboleth.oidc.profile.oauth2.config;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
+import net.shibboleth.oidc.security.jose.SignatureValidationConfiguration;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
+
+/**
+ * Profile configuration for validating DPoP proof JWTs.
+ * 
+ * @since 3.2.0
+ */
+public interface OAuth2DPoPProofValidatingProfileConfiguration extends OAuth2ProfileConfiguration {
+
+    /**
+     * Get the {@link ClaimsValidator} to apply to DPoP Proof JWTs being validated by this profile.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return the validator to use
+     */
+    @ConfigurationSetting(name="dpopProofClaimsValidator")
+    @Nullable ClaimsValidator getDpopProofClaimsValidator(@Nullable final ProfileRequestContext profileRequestContext);
+
+    /**
+     * Get the {@link SignatureValidationConfiguration} to be used for DPoP Proof JWT signature validation.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return the signature validation configuration to use
+     */
+    @ConfigurationSetting(name="dpopProofSignatureValidationConfiguration")
+    @Nullable SignatureValidationConfiguration getDpopProofSignatureValidationConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext);
+
+    /**
+     * Get whether client is required to include DPoP Proof JWT in request.
+     *
+     * @param profileRequestContext the profile request context
+     *
+     * @return whether client is required to include DPoP Proof JWT in request
+     */
+    @ConfigurationSetting(name="requireDpopProof")
+    boolean isRequireDpopProof(@Nullable final ProfileRequestContext profileRequestContext);
+
+}
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2PushedAuthorizationRequestConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2PushedAuthorizationRequestConfiguration.java
index 98a0e14..3be99a5 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2PushedAuthorizationRequestConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2PushedAuthorizationRequestConfiguration.java
@@ -37,7 +37,8 @@ import net.shibboleth.shared.annotation.constraint.Positive;
  */
 public interface OAuth2PushedAuthorizationRequestConfiguration extends OAuth2ClientAuthenticableProfileConfiguration, 
     OAuth2AuthorizationProfileConfiguration, OAuth2ProfileConfiguration, OverriddenIssuerProfileConfiguration,
-    OIDCAuthenticationRelyingPartyProfileConfiguration, OIDCAuthenticationProfileConfiguration {
+    OIDCAuthenticationRelyingPartyProfileConfiguration, OIDCAuthenticationProfileConfiguration,
+    OAuth2DPoPProofValidatingProfileConfiguration {
 
     /** OAuth2 Pushed Authorization Requests URI. */
     @Nonnull @NotEmpty public static final String PROTOCOL_URI = "https://tools.ietf.org/html/rfc9126";
@@ -78,5 +79,4 @@ public interface OAuth2PushedAuthorizationRequestConfiguration extends OAuth2Cli
     @Nullable BiFunction<ProfileRequestContext,Map<String,Object>,Map<String,Object>>
         getRequestUriClaimsSetManipulationStrategy(
                 @Nullable final ProfileRequestContext profileRequestContext);
-
 }
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/config/impl/DefaultOIDCAuthorizationConfiguration.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/config/impl/DefaultOIDCAuthorizationConfiguration.java
index 05d4931..837c3ef 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/config/impl/DefaultOIDCAuthorizationConfiguration.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/config/impl/DefaultOIDCAuthorizationConfiguration.java
@@ -146,6 +146,9 @@ public class DefaultOIDCAuthorizationConfiguration extends AbstractOIDCSSOConfig
     @Nonnull private Function<ProfileRequestContext, Predicate<ProfileRequestContext>>
         requireAuthenticationRequestPredicateLookupStrategy;
 
+    /** Whether client is required to include dpop_jkt in authorization request. */
+    @Nonnull private Predicate<ProfileRequestContext> requireDpopJktPredicate;
+
     /**
      * Constructor.
      */
@@ -188,6 +191,7 @@ public class DefaultOIDCAuthorizationConfiguration extends AbstractOIDCSSOConfig
         responseModesLookupStrategy = FunctionSupport.constant(CollectionSupport.emptySet());
         requireAuthenticationRequestPredicateLookupStrategy =
                 FunctionSupport.constant(PredicateSupport.alwaysTrue());
+        requireDpopJktPredicate = PredicateSupport.alwaysFalse();
     }
 
     /** {@inheritDoc} */
@@ -992,4 +996,32 @@ public class DefaultOIDCAuthorizationConfiguration extends AbstractOIDCSSOConfig
                 Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isRequireDpopJkt(@Nullable final ProfileRequestContext profileRequestContext) {
+        return requireDpopJktPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether client is required to include dpop_jkt in authorization request.
+     *
+     * @param flag flag to set
+     * 
+     * @since 3.2.0
+     */
+    public void setRequireDpopJkt(final boolean flag) {
+        requireDpopJktPredicate = flag ? PredicateSupport.alwaysTrue() : PredicateSupport.alwaysFalse();
+    }
+
+    /**
+     * Set condition for whether client is required to include dpop_jkt in authorization request.
+     *
+     * @param condition condition to set
+     * 
+     * @since 3.2.0
+     */
+    public void setRequireDpopJktPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        requireDpopJktPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
+
 }
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/oauth2/config/impl/AbstractOAuth2ClientAuthenticableProfileConfiguration.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/oauth2/config/impl/AbstractOAuth2ClientAuthenticableProfileConfiguration.java
index 1567d66..b046a08 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/oauth2/config/impl/AbstractOAuth2ClientAuthenticableProfileConfiguration.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/oauth2/config/impl/AbstractOAuth2ClientAuthenticableProfileConfiguration.java
@@ -35,6 +35,7 @@ import net.shibboleth.oidc.metadata.policy.UnregisteredClientPolicy;
 import net.shibboleth.oidc.profile.oauth2.config.OAuth2ClientAuthenticableClientProfileConfiguration;
 import net.shibboleth.oidc.profile.oauth2.config.OAuth2ClientAuthenticableProfileConfiguration;
 import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.jose.SignatureValidationConfiguration;
 import net.shibboleth.shared.annotation.constraint.NonNegative;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -88,6 +89,16 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
     @Nonnull private Function<ProfileRequestContext, Map<String, UnregisteredClientPolicy>>
             unregisteredClientPolicyLookupStrategy;
 
+    /** Validation of JWT claims for DPoP proofs. */
+    @Nonnull private Function<ProfileRequestContext,ClaimsValidator> dpopProofClaimsValidatorLookupStrategy;
+
+    /** Validation of JWT signature of DPoP proofs. */
+    @Nonnull private Function<ProfileRequestContext,SignatureValidationConfiguration>
+        dpopSignatureValidationConfigurationLookupStrategy;
+
+    /** Whether client is required to include DPoP Proof JWT in API request. */
+    @Nonnull private Predicate<ProfileRequestContext> requireDpopProofPredicate;
+
     /**
      * Constructor.
      *
@@ -113,6 +124,9 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
         clientCredentialLookupStrategy = FunctionSupport.constant(null);
         clientIdLookupStrategy = FunctionSupport.constant(null);   
         unregisteredClientPolicyLookupStrategy = FunctionSupport.constant(null);
+        dpopProofClaimsValidatorLookupStrategy = FunctionSupport.constant(null);
+        dpopSignatureValidationConfigurationLookupStrategy = FunctionSupport.constant(null);
+        requireDpopProofPredicate = PredicateSupport.alwaysFalse();
     }
 
     /** {@inheritDoc} */
@@ -479,4 +493,92 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
         unregisteredClientPolicyLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
+    /** {@inheritDoc} */
+    @Override
+    @Nullable public ClaimsValidator getDpopProofClaimsValidator(@Nullable final ProfileRequestContext profileRequestContext) {
+        return dpopProofClaimsValidatorLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set the {@link ClaimsValidator} to apply to DPoP Proof JWT.
+     * 
+     * @param validator validator to use
+     * 
+     * @since 3.2.0
+     */
+    public void setDpopProofClaimsValidator(@Nullable final ClaimsValidator validator) {
+        dpopProofClaimsValidatorLookupStrategy = FunctionSupport.constant(validator);
+    }
+
+    /**
+     * Set a lookup strategy for the {@link ClaimsValidator} to apply to DPoP Proof JWT.
+     *
+     * @param strategy  lookup strategy
+     * 
+     * @since 3.2.0
+     */
+    public void setDpopProofClaimsValidatorLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,ClaimsValidator> strategy) {
+        dpopProofClaimsValidatorLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable public SignatureValidationConfiguration getDpopProofSignatureValidationConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return dpopSignatureValidationConfigurationLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set the {@link SignatureValidationConfiguration} to validate the DPoP Proof JWT signatures.
+     * 
+     * @param configuration configuration to use
+     * 
+     * @since 3.2.0
+     */
+    public void setDpopProofSignatureValidationConfiguration(
+            @Nullable final SignatureValidationConfiguration configuration) {
+        dpopSignatureValidationConfigurationLookupStrategy = FunctionSupport.constant(configuration);
+    }
+
+    /**
+     * Set a lookup strategy for the {@link SignatureValidationConfiguration} to validate the DPoP Proof JWT signatures.
+     *
+     * @param strategy  lookup strategy
+     * 
+     * @since 3.2.0
+     */
+    public void setDpopProofSignatureValidationConfigurationLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,SignatureValidationConfiguration> strategy) {
+        dpopSignatureValidationConfigurationLookupStrategy =
+                Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isRequireDpopProof(@Nullable final ProfileRequestContext profileRequestContext) {
+        return requireDpopProofPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether client is required to include DPoP proof in request.
+     *
+     * @param flag flag to set
+     * 
+     * @since 3.2.0
+     */
+    public void setRequireDpopProof(final boolean flag) {
+        requireDpopProofPredicate = flag ? PredicateSupport.alwaysTrue() : PredicateSupport.alwaysFalse();
+    }
+
+    /**
+     * Set condition for whether client is required to include DPoP proof in request.
+     *
+     * @param condition condition to set
+     * 
+     * @since 3.2.0
+     */
+    public void setRequireDpopProofPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        requireDpopProofPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
 }
\ No newline at end of file

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


More information about the commits mailing list