[java-idp-plugin-vci] branch dev/PROFILES_AND_DPOP_AND_NONCE updated: Reworking/nonce endpoint
Codeberg
noreply at shibboleth.net
Wed Nov 19 14:14:35 UTC 2025
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch dev/PROFILES_AND_DPOP_AND_NONCE
in repository java-idp-plugin-vci.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/f30ff1ecbf5043a4a1ea44ecd11cec7139d9b17e
The following commit(s) were added to refs/heads/dev/PROFILES_AND_DPOP_AND_NONCE by this push:
new f30ff1e Reworking/nonce endpoint
f30ff1e is described below
commit f30ff1ecbf5043a4a1ea44ecd11cec7139d9b17e
Author: jlauros <janne.lauros at csc.fi>
AuthorDate: Wed Nov 19 16:14:17 2025 +0200
Reworking/nonce endpoint
---
.../config/impl/DefaultOpenIDVCIConfiguration.java | 11 ----
.../impl/FormOutboundNonceResponseMessage.java | 77 ++++++++++++++++++++--
.../META-INF/net.shibboleth.idp/postconfig.xml | 36 +++++-----
.../idp/flows/openid/vci/nonce/nonce-flow.xml | 1 -
.../idp/service/relying-party}/postconfig.xml | 36 +++++-----
.../impl/FormOutboundTokenResponseMessageTest.java | 4 +-
6 files changed, 112 insertions(+), 53 deletions(-)
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java
deleted file mode 100644
index 43824d6..0000000
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.geant.shibboleth.plugin.openidvci.config.impl;
-
-import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
-
-public class DefaultOpenIDVCIConfiguration extends AbstractOpenIDVCIConfiguration{
-
- public DefaultOpenIDVCIConfiguration() {
- super(OpenIDVCIConfiguration.PROFILE_ID);
- }
-
-}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java
index b79cd2b..5d17c06 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java
@@ -16,31 +16,94 @@
package org.geant.shibboleth.plugin.openidvci.profile.impl;
+import java.util.function.Function;
+
import javax.annotation.Nonnull;
-import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferSuccessResponse;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.NonceSuccessResponse;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2DPoPProofValidatingProfileConfiguration;
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.logic.Constraint;
/**
- * Action forming {@link CredentialOfferSuccessResponse}
+ * Action forming {@link NonceSuccessResponse}
*/
public class FormOutboundNonceResponseMessage extends AbstractProfileAction {
/** Class logger. */
@Nonnull
private Logger log = LoggerFactory.getLogger(FormOutboundNonceResponseMessage.class);
-
+
+ @NonnullAfterInit
+ private Function<ProfileRequestContext, String> generator;
+
+ /**
+ * Strategy used to locate the {@link RelyingPartyContext} associated with a
+ * given {@link ProfileRequestContext}.
+ */
+ @Nonnull
+ private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+ /** Relying party context. */
+ private RelyingPartyContext rpCtx;
+
+ public FormOutboundNonceResponseMessage() {
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ }
+
+ /**
+ * Set the strategy used to locate the {@link RelyingPartyContext} associated
+ * with a given {@link ProfileRequestContext}.
+ *
+ * @param strategy strategy used to locate the {@link RelyingPartyContext}
+ * associated with a given {@link ProfileRequestContext}
+ */
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, RelyingPartyContext> strategy) {
+ checkSetterPreconditions();
+
+ relyingPartyContextLookupStrategy = Constraint.isNotNull(strategy,
+ "RelyingPartyContext lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpCtx == null) {
+ log.error("{} No relying party context associated with this profile request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+ return false;
+ }
+ final ProfileConfiguration pc = rpCtx.getProfileConfig();
+ if (pc instanceof OAuth2DPoPProofValidatingProfileConfiguration configuration) {
+ generator = configuration.getDpopProofNonceGenerator(profileRequestContext);
+ } else {
+ log.error("{} No OpenID VCI profile configuration associated with this profile request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+ return false;
+ }
+ if (generator == null) {
+ log.error("{} No nonce generator available for this profile request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+ return false;
+ }
+ return super.doPreExecute(profileRequestContext);
+ }
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- // TODO: code flow ignores 'issuer_state'. Authentication endpoint should check
- // it. See Specification for guidance.
- profileRequestContext.ensureOutboundMessageContext().setMessage(new NonceSuccessResponse("nonocenonocenocneocneocneocneonceocn"));
+ profileRequestContext.ensureOutboundMessageContext()
+ .setMessage(new NonceSuccessResponse(generator.apply(profileRequestContext)));
}
}
\ No newline at end of file
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 4f9a82c..bb0eba3 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
@@ -17,7 +17,7 @@
p:placeholderPrefix="%{" p:placeholderSuffix="}" />
- <bean id="AbstractVCIProfile" abstract="true"
+ <bean id="AbstractVCIProfile" abstract="true"
p:issuer="#{getObject('shibboleth.oidc.issuer')}"
p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
@@ -33,33 +33,37 @@
p:dpopProofSignatureValidationConfiguration="#{getObject('DPoPSignatureValidationConfiguration')}"
p:dpopProofNonceGenerator="#{getObject('DefaultOAuth2DPoPNonceGenerator')}" />
- <!-- TB REMOVED -->
- <bean id="OpenID.VCI" parent="AbstractVCIProfile" lazy-init="true"
- class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration"
- p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
- p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"/>
<bean id="OpenID.VCI.CredentialOffer" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCICredentialOfferConfiguration" />
-
+
<bean id="OpenID.VCI.Token" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCITokenConfiguration" />
-
+
<bean id="OpenID.VCI.Credentials" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCICredentialsConfiguration" />
-
+
<bean id="OpenID.VCI.Nonce" parent="AbstractVCIProfile" lazy-init="true"
- class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCINonceConfiguration" />
+ class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCINonceConfiguration"
+ p:dpopProofNonceGenerator="#{getObject('DefaultOpenIDVCINonceGenerator')}" />
<!-- Property-based definition of login flows for OAuth endpoints. -->
<bean id="openidvci.PotentialFlows"
class="org.springframework.beans.factory.config.ListFactoryBean"
p:sourceList="#{getObject('shibboleth.AuthenticationFlowDescriptorManager').getComponents().?[id matches 'authn/(' + '%{openidvci.authn.flows:OAuth2Client}'.trim() + ')']}" />
-
- <bean id="openidvci.PublicClientValidator"
- class="org.geant.shibboleth.plugin.openidvci.authn.impl.WalletCredentialValidator" />
-
- <bean id="openidvci.AuthzCodeManipulationStrategy"
- class="org.geant.shibboleth.plugin.openidvci.profile.logic.AuthorizationCodeManipulationStrategy" />
+
+
+ <!-- We use special DPoP Nonce generator for Nonce endpoint. -->
+ <!-- The generator does not tie client id to nonce to accomodate unprotected Nonce endpoint. -->
+ <bean id="DefaultOpenIDVCINonceGenerator" parent="DefaultOAuth2DPoPNonceGenerator" lazy-init="true"
+ p:relyingPartyIdLookupStrategy-ref="openidvci.RelyingPartyForNonce">
+ </bean>
+
+ <!-- Mock relying party for Nonce generation. -->
+ <bean id="openidvci.RelyingPartyForNonce" parent="shibboleth.Functions.Constant">
+ <constructor-arg>
+ <bean class="java.lang.String" c:_0="mockRelyingParty" />
+ </constructor-arg>
+ </bean>
</beans>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml
index 82aa916..69ebc74 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml
@@ -16,7 +16,6 @@
<transition on="proceed" to="BuildResponse"/>
</action-state>
-
<bean-import resource="nonce-beans.xml"/>
</flow>
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/service/relying-party/postconfig.xml
similarity index 80%
copy from openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
copy to openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index 4f9a82c..bb0eba3 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/service/relying-party/postconfig.xml
@@ -17,7 +17,7 @@
p:placeholderPrefix="%{" p:placeholderSuffix="}" />
- <bean id="AbstractVCIProfile" abstract="true"
+ <bean id="AbstractVCIProfile" abstract="true"
p:issuer="#{getObject('shibboleth.oidc.issuer')}"
p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
@@ -33,33 +33,37 @@
p:dpopProofSignatureValidationConfiguration="#{getObject('DPoPSignatureValidationConfiguration')}"
p:dpopProofNonceGenerator="#{getObject('DefaultOAuth2DPoPNonceGenerator')}" />
- <!-- TB REMOVED -->
- <bean id="OpenID.VCI" parent="AbstractVCIProfile" lazy-init="true"
- class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration"
- p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
- p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"/>
<bean id="OpenID.VCI.CredentialOffer" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCICredentialOfferConfiguration" />
-
+
<bean id="OpenID.VCI.Token" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCITokenConfiguration" />
-
+
<bean id="OpenID.VCI.Credentials" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCICredentialsConfiguration" />
-
+
<bean id="OpenID.VCI.Nonce" parent="AbstractVCIProfile" lazy-init="true"
- class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCINonceConfiguration" />
+ class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCINonceConfiguration"
+ p:dpopProofNonceGenerator="#{getObject('DefaultOpenIDVCINonceGenerator')}" />
<!-- Property-based definition of login flows for OAuth endpoints. -->
<bean id="openidvci.PotentialFlows"
class="org.springframework.beans.factory.config.ListFactoryBean"
p:sourceList="#{getObject('shibboleth.AuthenticationFlowDescriptorManager').getComponents().?[id matches 'authn/(' + '%{openidvci.authn.flows:OAuth2Client}'.trim() + ')']}" />
-
- <bean id="openidvci.PublicClientValidator"
- class="org.geant.shibboleth.plugin.openidvci.authn.impl.WalletCredentialValidator" />
-
- <bean id="openidvci.AuthzCodeManipulationStrategy"
- class="org.geant.shibboleth.plugin.openidvci.profile.logic.AuthorizationCodeManipulationStrategy" />
+
+
+ <!-- We use special DPoP Nonce generator for Nonce endpoint. -->
+ <!-- The generator does not tie client id to nonce to accomodate unprotected Nonce endpoint. -->
+ <bean id="DefaultOpenIDVCINonceGenerator" parent="DefaultOAuth2DPoPNonceGenerator" lazy-init="true"
+ p:relyingPartyIdLookupStrategy-ref="openidvci.RelyingPartyForNonce">
+ </bean>
+
+ <!-- Mock relying party for Nonce generation. -->
+ <bean id="openidvci.RelyingPartyForNonce" parent="shibboleth.Functions.Constant">
+ <constructor-arg>
+ <bean class="java.lang.String" c:_0="mockRelyingParty" />
+ </constructor-arg>
+ </bean>
</beans>
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java
index c18d615..7720558 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java
@@ -22,7 +22,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
-import org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration;
+import org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCITokenConfiguration;
import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferRequest;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferTxCode;
@@ -76,7 +76,7 @@ public class FormOutboundTokenResponseMessageTest {
.addSubcontext(new TokenContext());
RelyingPartyContext rpCtx = ((RelyingPartyContext) profileRequestCtx.addSubcontext(new RelyingPartyContext(),
- true)).setProfileConfig(new DefaultOpenIDVCIConfiguration());
+ true)).setProfileConfig(new DefaultOpenIDVCITokenConfiguration());
rpCtx.setRelyingPartyId("clientID");
BasicRelyingPartyConfiguration rpConf = new BasicRelyingPartyConfiguration();
rpConf.setId("mock");
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list