[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