[java-idp-plugin-vci] 04/05: DPoP hardening per rfc9449#section-10.1

Codeberg noreply at shibboleth.net
Mon Sep 28 15:53:45 UTC 2026


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

codeberg pushed a commit to branch dev/FAPI
in repository java-idp-plugin-vci.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/e06eda4951ae2c94b152d6c1cf0b7ef237c84d22

commit e06eda4951ae2c94b152d6c1cf0b7ef237c84d22
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Mon Sep 28 18:10:32 2026 +0300

    DPoP hardening per rfc9449#section-10.1
---
 README.md                                          | 15 ++--
 ...edAuthorizationDPoPJktManipulationStrategy.java | 82 ++++++++++++++++++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  3 +
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index 394e2f6..63fe66f 100644
--- a/README.md
+++ b/README.md
@@ -745,7 +745,8 @@ authorization request:
                         p:tokenEndpointAuthMethods="#{{'none'}}"
                         p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy" />
                   <bean parent="OpenID.VCI.Credentials" />
-                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'none'}}" />
+                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'none'}}"
+                        p:requestUriClaimsSetManipulationStrategy-ref="openidvci.PushedAuthorizationDPoPJktManipulationStrategy" />
               </list>
           </property>
         </bean>
@@ -1579,7 +1580,8 @@ allows an authorization code at most 60 seconds. The OP plugin default is five m
                         p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy"
                         p:tokenEndpointAuthMethods="#{{'attest_jwt_client_auth'}}" />
                   <bean parent="OpenID.VCI.Credentials" />
-                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'attest_jwt_client_auth'}}" />
+                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'attest_jwt_client_auth'}}"
+                        p:requestUriClaimsSetManipulationStrategy-ref="openidvci.PushedAuthorizationDPoPJktManipulationStrategy" />
               </list>
           </property>
         </bean>
@@ -1590,6 +1592,9 @@ allows an authorization code at most 60 seconds. The OP plugin default is five m
 
 DPoP settings are left to their defaults, so a DPoP nonce is required.
 
+`openidvci.PushedAuthorizationDPoPJktManipulationStrategy` on **OAUTH2.PAR** is recommended with
+DPoP, see [RFC 9449 10.1](https://www.rfc-editor.org/rfc/rfc9449#section-10.1).
+
 Add `<AttributeEncoder xsi:type="oidc:OIDCString" name="GeantIncubatorDiploma_HAIP" />` to the
 attribute definition and release the attribute also to the two conformance clients in
 *conf/attribute-filter.xml*.
@@ -2482,7 +2487,8 @@ The file as it is at the end of [First installation, by example](#first-installa
                         p:tokenEndpointAuthMethods="#{{'none'}}"
                         p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy" />
                   <bean parent="OpenID.VCI.Credentials" />
-                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'none'}}" />
+                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'none'}}"
+                        p:requestUriClaimsSetManipulationStrategy-ref="openidvci.PushedAuthorizationDPoPJktManipulationStrategy" />
               </list>
           </property>
         </bean>
@@ -2500,7 +2506,8 @@ The file as it is at the end of [First installation, by example](#first-installa
                         p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy"
                         p:tokenEndpointAuthMethods="#{{'attest_jwt_client_auth'}}" />
                   <bean parent="OpenID.VCI.Credentials" />
-                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'attest_jwt_client_auth'}}" />
+                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'attest_jwt_client_auth'}}"
+                        p:requestUriClaimsSetManipulationStrategy-ref="openidvci.PushedAuthorizationDPoPJktManipulationStrategy" />
               </list>
           </property>
         </bean>
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/logic/PushedAuthorizationDPoPJktManipulationStrategy.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/logic/PushedAuthorizationDPoPJktManipulationStrategy.java
new file mode 100644
index 0000000..1e6dc9e
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/logic/PushedAuthorizationDPoPJktManipulationStrategy.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2025, GÉANT
+ *
+ * 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 org.geant.shibboleth.plugin.openidvci.profile.logic;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultDPoPProofThumbprintLookupFunction;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Manipulation of the claims set stored for a pushed authorization request that sets 'dpop_jkt' to the thumbprint
+ * of the validated DPoP proof key of the request, when the request has no 'dpop_jkt' of its own.
+ */
+public class PushedAuthorizationDPoPJktManipulationStrategy
+        implements BiFunction<ProfileRequestContext, Map<String, Object>, Map<String, Object>> {
+
+    /** Claim name of the DPoP proof key thumbprint. */
+    @Nonnull
+    public static final String DPOP_JKT = "dpop_jkt";
+
+    /** Class logger. */
+    @Nonnull
+    private Logger log = LoggerFactory.getLogger(PushedAuthorizationDPoPJktManipulationStrategy.class);
+
+    /** Strategy used to read the thumbprint of the validated DPoP proof. */
+    @Nonnull
+    private Function<ProfileRequestContext, String> dpopProofThumbprintLookupStrategy =
+            new DefaultDPoPProofThumbprintLookupFunction();
+
+    /**
+     * Set the strategy used to read the thumbprint of the validated DPoP proof.
+     *
+     * @param strategy lookup strategy
+     */
+    public void setDpopProofThumbprintLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, String> strategy) {
+        dpopProofThumbprintLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable
+    public Map<String, Object> apply(@Nullable final ProfileRequestContext profileRequestContext,
+            @Nullable final Map<String, Object> claims) {
+        if (claims == null || claims.get(DPOP_JKT) != null) {
+            return null;
+        }
+        final String thumbprint = dpopProofThumbprintLookupStrategy.apply(profileRequestContext);
+        if (thumbprint == null) {
+            return null;
+        }
+        final Map<String, Object> result = new HashMap<>(claims);
+        result.put(DPOP_JKT, thumbprint);
+        log.debug("Pushed authorization request bound to DPoP proof key {}", thumbprint);
+        return result;
+    }
+
+}
diff --git a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 782627b..95afcd3 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -59,6 +59,9 @@
         
     <bean id="openidvci.TokenManipulationStrategy"
         class="org.geant.shibboleth.plugin.openidvci.profile.logic.OpenIDVCITokenManipulationStrategy" />
+
+    <bean id="openidvci.PushedAuthorizationDPoPJktManipulationStrategy"
+        class="org.geant.shibboleth.plugin.openidvci.profile.logic.PushedAuthorizationDPoPJktManipulationStrategy" />
     
 
     <!--

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


More information about the commits mailing list