[java-idp-plugin-vci] branch main updated: Nonce endpoint, refactoring profile configurations
Codeberg
noreply at shibboleth.net
Wed Nov 19 14:38:24 UTC 2025
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-idp-plugin-vci.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/804055fb70ea19d83bd6b68c51dde8e3a85010b4
The following commit(s) were added to refs/heads/main by this push:
new 804055f Nonce endpoint, refactoring profile configurations
804055f is described below
commit 804055fb70ea19d83bd6b68c51dde8e3a85010b4
Author: jlauros <janne.lauros at csc.fi>
AuthorDate: Wed Nov 19 16:38:13 2025 +0200
Nonce endpoint, refactoring profile configurations
---
.../openidvci/config/OpenIDVCIConfiguration.java | 24 ++++-
...on.java => AbstractOpenIDVCIConfiguration.java} | 13 ++-
...faultOpenIDVCICredentialOfferConfiguration.java | 11 +++
.../DefaultOpenIDVCICredentialsConfiguration.java | 11 +++
.../impl/DefaultOpenIDVCINonceConfiguration.java | 11 +++
.../impl/DefaultOpenIDVCITokenConfiguration.java | 11 +++
.../messaging/impl/CredentialSuccessResponse.java | 14 +++
...cessResponse.java => NonceSuccessResponse.java} | 66 +++++--------
.../FormOutboundCredentialsResponseMessage.java | 46 ++++++++-
.../impl/FormOutboundNonceResponseMessage.java | 109 +++++++++++++++++++++
.../META-INF/net.shibboleth.idp/postconfig.xml | 22 +----
.../openid/vci/abstract-api/abstract-api-beans.xml | 2 +-
.../flows/openid/vci/abstract/abstract-beans.xml | 4 +-
.../credential-offer/credential-offer-beans.xml | 2 +
.../openid/vci/credentials/credentials-beans.xml | 16 ++-
.../idp/flows/openid/vci/nonce/nonce-beans.xml | 38 +++++++
.../idp/flows/openid/vci/nonce/nonce-flow.xml | 21 ++++
.../idp/flows/openid/vci/token/token-beans.xml | 16 ++-
.../idp/service/relying-party}/postconfig.xml | 55 +++++++----
.../impl/FormOutboundTokenResponseMessageTest.java | 4 +-
20 files changed, 391 insertions(+), 105 deletions(-)
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java
index ee922f4..461095d 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java
@@ -29,7 +29,7 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.annotation.constraint.Positive;
/**
- * Profile configuration for the OpenID VCI.
+ * Profile configuration shared by all OpenID VCI endpointsß.
*/
public interface OpenIDVCIConfiguration extends ConditionalProfileConfiguration {
@@ -38,10 +38,30 @@ public interface OpenIDVCIConfiguration extends ConditionalProfileConfiguration
@NotEmpty
public static final String PROTOCOL_URI = "https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html";
- /** ID for this profile configuration. */
+ /** Main id for this profile configuration. */
@Nonnull
@NotEmpty
public static final String PROFILE_ID = "http://geant.org/ns/profiles/openid/vci";
+
+ /** ID for credential offer profile configuration. */
+ @Nonnull
+ @NotEmpty
+ public static final String PROFILE_ID_CREDENTIAL_OFFER = "http://geant.org/ns/profiles/openid/vci/credential-offer";
+
+ /** ID for token configuration. */
+ @Nonnull
+ @NotEmpty
+ public static final String PROFILE_ID_TOKEN = "http://geant.org/ns/profiles/openid/vci/token";
+
+ /** ID for credentials configuration. */
+ @Nonnull
+ @NotEmpty
+ public static final String PROFILE_ID_CREDENTIALS = "http://geant.org/ns/profiles/openid/vci/credentials";
+
+ /** ID for nonce configuration. */
+ @Nonnull
+ @NotEmpty
+ public static final String PROFILE_ID_NONCE = "http://geant.org/ns/profiles/openid/vci/nonce";
/**
* Get pre-authorized code length. Length of zero means there is no requirement
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/AbstractOpenIDVCIConfiguration.java
similarity index 96%
rename from openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java
rename to openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/AbstractOpenIDVCIConfiguration.java
index 4438f2a..9869b43 100644
--- 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/AbstractOpenIDVCIConfiguration.java
@@ -30,7 +30,6 @@ import javax.annotation.Nullable;
import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
import org.geant.shibboleth.plugin.openidvci.config.impl.stolen.AbstractOAuth2ClientAuthenticableProfileConfiguration;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.security.config.SecurityConfiguration;
import net.shibboleth.oidc.profile.config.OIDCSSOProfileConfiguration;
import net.shibboleth.profile.config.OverriddenIssuerProfileConfiguration;
@@ -41,7 +40,7 @@ import net.shibboleth.shared.logic.FunctionSupport;
import net.shibboleth.shared.logic.PredicateSupport;
import net.shibboleth.shared.primitive.StringSupport;
-public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthenticableProfileConfiguration
+public abstract class AbstractOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthenticableProfileConfiguration
implements OpenIDVCIConfiguration, OverriddenIssuerProfileConfiguration, OIDCSSOProfileConfiguration {
/** Lookup function to override issuer value. */
@@ -56,7 +55,6 @@ public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthentic
@Nonnull
private Function<ProfileRequestContext, String> accessTokenTypeLookupStrategy;
- // TODO: property not applied. Remove or apply.
/**
* Lookup function to supply strategy bi-function for manipulating access token
* claims set.
@@ -83,8 +81,8 @@ public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthentic
/**
* Constructor.
*/
- public DefaultOpenIDVCIConfiguration() {
- super(OpenIDVCIConfiguration.PROFILE_ID);
+ protected AbstractOpenIDVCIConfiguration(@Nonnull @NotEmpty final String profileId) {
+ super(profileId);
issuerLookupStrategy = FunctionSupport.constant(null);
accessTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofMinutes(10));
accessTokenTypeLookupStrategy = FunctionSupport.constant(null);
@@ -211,8 +209,9 @@ public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthentic
}
/**
- * Set a lookup strategy for the pre-authorized code length. Length of zero means
- * there is no requirement and code does not require storage configuration.
+ * Set a lookup strategy for the pre-authorized code length. Length of zero
+ * means there is no requirement and code does not require storage
+ * configuration.
*
* @param strategy lookup strategy
*/
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialOfferConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialOfferConfiguration.java
new file mode 100644
index 0000000..ce80a74
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialOfferConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCICredentialOfferConfiguration extends AbstractOpenIDVCIConfiguration{
+
+ public DefaultOpenIDVCICredentialOfferConfiguration() {
+ super(OpenIDVCIConfiguration.PROFILE_ID_CREDENTIAL_OFFER);
+ }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialsConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialsConfiguration.java
new file mode 100644
index 0000000..b379bc7
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialsConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCICredentialsConfiguration extends AbstractOpenIDVCIConfiguration{
+
+ public DefaultOpenIDVCICredentialsConfiguration() {
+ super(OpenIDVCIConfiguration.PROFILE_ID_CREDENTIALS);
+ }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCINonceConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCINonceConfiguration.java
new file mode 100644
index 0000000..7df9b97
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCINonceConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCINonceConfiguration extends AbstractOpenIDVCIConfiguration{
+
+ public DefaultOpenIDVCINonceConfiguration() {
+ super(OpenIDVCIConfiguration.PROFILE_ID_NONCE);
+ }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCITokenConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCITokenConfiguration.java
new file mode 100644
index 0000000..5e51cdf
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCITokenConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCITokenConfiguration extends AbstractOpenIDVCIConfiguration{
+
+ public DefaultOpenIDVCITokenConfiguration() {
+ super(OpenIDVCIConfiguration.PROFILE_ID_TOKEN);
+ }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
index 6f4ebe1..4544a7c 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
@@ -16,9 +16,21 @@
package org.geant.shibboleth.plugin.openidvci.messaging.impl;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import javax.annotation.Nullable;
@@ -87,6 +99,8 @@ public class CredentialSuccessResponse implements SuccessResponse {
httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
httpResponse.setCacheControl("no-store");
httpResponse.setPragma("no-cache");
+
+ httpResponse.setHeader("Date", DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()));
try {
httpResponse.setContent(toOffer());
} catch (JsonProcessingException e) {
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/NonceSuccessResponse.java
similarity index 50%
copy from openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
copy to openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/NonceSuccessResponse.java
index 6f4ebe1..87328f4 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/NonceSuccessResponse.java
@@ -16,12 +16,10 @@
package org.geant.shibboleth.plugin.openidvci.messaging.impl;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -30,48 +28,30 @@ import com.nimbusds.common.contenttype.ContentType;
import com.nimbusds.oauth2.sdk.SuccessResponse;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+
/**
- * https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-response
+ * hhttps://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-nonce-response
*
- * Forms a credential response. Now a mix of specifications v14 and v15.
+ * Forms a nonce response.
*
*/
-public class CredentialSuccessResponse implements SuccessResponse {
-
- /** v15 credentials parameter. */
- @JsonProperty("credentials")
- private final List<Map<String, String>> credentials = new ArrayList<Map<String, String>>();
+public class NonceSuccessResponse implements SuccessResponse {
+
+ /** Class logger. */
+ @Nonnull
+ private Logger log = LoggerFactory.getLogger(NonceSuccessResponse.class);
- /**
- * Get v15 credentials parameter.
- *
- * @return v15 credentials parameter
- */
- public List<Map<String, String>> getCredentials() {
- return credentials;
- }
-
- /**
- * Constructor. TODO: No safeguards in place. Add when finalized.
- *
- * @param credentialv15 v15 credentials parameter
- * @param credentialv14 v14 credential parameter
- */
- public CredentialSuccessResponse(@Nullable List<String> credentialv15) {
- Map<String, String> cred = new HashMap<String, String>();
- credentialv15.forEach(credential -> cred.put("credential", credential));
- credentials.add(cred);
- }
+ /** c_nonce. */
+ @Nonnull
+ @NotEmpty
+ @JsonProperty("c_nonce")
+ private final String cNonce;
- /**
- * Response content as JSON.
- *
- * @return
- * @throws JsonProcessingException
- */
- public String toOffer() throws JsonProcessingException {
- ObjectMapper objectMapper = new ObjectMapper();
- return objectMapper.writeValueAsString(this);
+ public NonceSuccessResponse(@Nonnull @NotEmpty String cNonce) {
+ assert cNonce != null;
+ assert !cNonce.isEmpty();
+ this.cNonce = cNonce;
}
/** {@inheritDoc} */
@@ -85,10 +65,10 @@ public class CredentialSuccessResponse implements SuccessResponse {
public HTTPResponse toHTTPResponse() {
HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
- httpResponse.setCacheControl("no-store");
+ //httpResponse.setCacheControl("no-store");
httpResponse.setPragma("no-cache");
try {
- httpResponse.setContent(toOffer());
+ httpResponse.setContent(new ObjectMapper().writeValueAsString(this));
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java
index 8b729ab..7a2f893 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java
@@ -27,6 +27,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.security.interfaces.ECPrivateKey;
+import java.time.Instant;
import org.geant.shibboleth.plugin.openidvci.messaging.context.CredentialsContext;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferRequestedCredential;
@@ -48,11 +49,13 @@ import net.shibboleth.profile.context.navigate.IssuerLookupFunction;
import net.shibboleth.shared.logic.Constraint;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.ECDSASigner;
+import com.nimbusds.jose.util.Base64;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.JWTClaimsSet.Builder;
import com.nimbusds.jwt.SignedJWT;
@@ -182,17 +185,37 @@ public class FormOutboundCredentialsResponseMessage extends AbstractOIDCResponse
// Map<String, String> cnfKid = null;
if (ctx.getProofs() != null && !ctx.getProofs().isEmpty()) {
ctx.getProofs().forEach(proof -> {
- Map<String, String> cnfKid = new HashMap<>();
- cnfKid.put("jwk", proof.getHeader().getJWK().toJSONString());
+ Map<String, Object> cnfKid = new HashMap<>();
+ try {
+ cnfKid.put("jwk", new ObjectMapper().readValue(proof.getHeader().getJWK().toJSONString(), Object.class));
+ } catch (JsonProcessingException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
// TODO: vct is the credential configuration id in SD JWT. Here we use however "instance" specific
// identifier that happes to be in our case derived from it. We need to get the real configuration id here.
Builder build = new JWTClaimsSet.Builder().claim("vct", ctx.getCredentialIdentifier().split("_")[0])
.claim("iss", issuerLookupStrategy.apply(profileRequestContext))
+ // Just to pass happy path test.
+ .claim("exp", Instant.now().getEpochSecond()+3600)
.claim("_sd", sdClaims.get_sd()).claim("_sd_alg", sdClaims.get_alg()).claim("cnf", cnfKid)
.issueTime(new Date());
JWTClaimsSet claimsSet = build.build();
+ //Now we pretend setting a certificate chain here.
+ List<Base64> chain= new ArrayList<>();
+ chain.add(new Base64("MIIB4DCCAYWgAwIBAgIUaVbPKGSv6mVnyNbTOo1E9AWr+r4wCgYIKoZIzj0EAwIw\n"
+ + "RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu\n"
+ + "dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTA1MDkwOTI4MTVaFw0zNTA1MDcw\n"
+ + "OTI4MTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD\n"
+ + "VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO\n"
+ + "PQMBBwNCAASpD0RJ4itDfomKNYz7zF1yNfBjjpFben1gO0/QxVouceclWUasKdbX\n"
+ + "XvwpyguutsFvlxUIRDqxgD4tC0xuDqSPo1MwUTAdBgNVHQ4EFgQUTC/h0/AgKp/3\n"
+ + "FVZJBJoJBcX/hQMwHwYDVR0jBBgwFoAUTC/h0/AgKp/3FVZJBJoJBcX/hQMwDwYD\n"
+ + "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA87tC4qr0HJIMZylNO3Xv\n"
+ + "FhSb/DHZt3Pp/WVTCRpby7YCIQCbvW/6IEk1hNxpX49zLyoQpSF8DW1a/cTMr2Te\n"
+ + "Aa1KHw=="));
SignedJWT signedJWT = new SignedJWT(
- new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm()))
+ new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm())).x509CertChain(chain)
.type(new JOSEObjectType("dc+sd-jwt")).keyID("signing").build(),
claimsSet);
try {
@@ -209,11 +232,26 @@ public class FormOutboundCredentialsResponseMessage extends AbstractOIDCResponse
});
} else {
Builder build = new JWTClaimsSet.Builder().claim("vct", ctx.getCredentialIdentifier())
+ // Just to pass happy path test.
+ .claim("exp", Instant.now().getEpochSecond()+3600)
.claim("iss", issuerLookupStrategy.apply(profileRequestContext)).claim("_sd", sdClaims.get_sd())
.claim("_sd_alg", sdClaims.get_alg()).issueTime(new Date());
JWTClaimsSet claimsSet = build.build();
+ //Now we pretend setting a certificate chain here.
+ List<Base64> chain= new ArrayList<>();
+ chain.add(new Base64("MIIB4DCCAYWgAwIBAgIUaVbPKGSv6mVnyNbTOo1E9AWr+r4wCgYIKoZIzj0EAwIw\n"
+ + "RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu\n"
+ + "dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTA1MDkwOTI4MTVaFw0zNTA1MDcw\n"
+ + "OTI4MTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD\n"
+ + "VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO\n"
+ + "PQMBBwNCAASpD0RJ4itDfomKNYz7zF1yNfBjjpFben1gO0/QxVouceclWUasKdbX\n"
+ + "XvwpyguutsFvlxUIRDqxgD4tC0xuDqSPo1MwUTAdBgNVHQ4EFgQUTC/h0/AgKp/3\n"
+ + "FVZJBJoJBcX/hQMwHwYDVR0jBBgwFoAUTC/h0/AgKp/3FVZJBJoJBcX/hQMwDwYD\n"
+ + "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA87tC4qr0HJIMZylNO3Xv\n"
+ + "FhSb/DHZt3Pp/WVTCRpby7YCIQCbvW/6IEk1hNxpX49zLyoQpSF8DW1a/cTMr2Te\n"
+ + "Aa1KHw=="));
SignedJWT signedJWT = new SignedJWT(
- new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm()))
+ new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm())).x509CertChain(chain)
.type(new JOSEObjectType("dc+sd-jwt")).keyID("signing").build(),
claimsSet);
try {
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
new file mode 100644
index 0000000..5d17c06
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java
@@ -0,0 +1,109 @@
+/*
+ * 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.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+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 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) {
+ 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 c7f2ea7..2775a71 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
@@ -15,35 +15,17 @@
<bean id="shibboleth.PropertySourcesPlaceholderConfigurer"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
p:placeholderPrefix="%{" p:placeholderSuffix="}" />
-
-
- <bean id="AbstractVCIProfile" abstract="true"
- p:issuer="#{getObject('shibboleth.oidc.issuer')}"
- p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
- p:forcePKCE="%{idp.oidc.forcePKCE:false}"
- p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
- p:accessTokenType="%{idp.oauth2.accessToken.type:}"
- p:accessTokenLifetime="%{idp.oidc.accessToken.defaultLifetime:PT10M}"
- p:tokenEndpointAuthMethod="%{idp.authn.oidc.rp.client.authenticationMethod:client_secret_basic}"
- p:securityConfiguration-ref="%{idp.security.oidc.config:shibboleth.oidc.DefaultSecurityConfiguration}"
- p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}" />
-
- <bean id="OpenID.VCI" parent="AbstractVCIProfile" lazy-init="true"
- class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration"
- p:issuer="#{getObject('shibboleth.oidc.issuer')}"
- p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
- p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
- p:accessTokenLifetime="%{openidvci.accessToken.defaultLifetime:PT5M}"/>
<!-- 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" />
+
</beans>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml
index 71345ee..e4e4c05 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml
@@ -11,7 +11,7 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize" default-destroy-method="destroy">
- <bean id="shibboleth.oidc.browserProfile" class="java.lang.Boolean" c:_0="false"/>
+ <bean id="shibboleth.openidvci.browserProfile" class="java.lang.Boolean" c:_0="false"/>
<bean id="InitializeRelyingPartyContext" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeRelyingPartyContext"
scope="prototype" p:clientIDLookupStrategy-ref="shibboleth.ClientIDLookupStrategy"/>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml
index cc1ab97..db210c7 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml
@@ -10,8 +10,8 @@
<import resource="classpath*:/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml"/>
<bean id="InitializeProfileRequestContext" class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext"
- scope="prototype" p:profileId="http://geant.org/ns/profiles/openid/vci" p:loggingId="%{idp.service.logging.saml2sso:SSO}"
- p:browserProfile-ref="shibboleth.oidc.browserProfile"/>
+ scope="prototype" p:profileId-ref="shibboleth.openidvci.profileId" p:loggingId="%{idp.service.logging.saml2sso:SSO}"
+ p:browserProfile-ref="shibboleth.openidvci.browserProfile"/>
<bean id="openidvci.CredentialOfferCache" class="org.geant.shibboleth.plugin.openidvci.storage.CredentialOfferCache"
depends-on="shibboleth.LoggingService" p:storage-ref="#{'%{openidvci.StorageService:shibboleth.StorageService}'.trim()}"/>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml
index 3ceda55..ae555cf 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml
@@ -11,6 +11,8 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize" default-destroy-method="destroy">
+ <bean id="shibboleth.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/credential-offer"/>
+
<bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.CredentialOfferRequestDecoder"
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml
index 2888a0d..dd4fd65 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml
@@ -1,6 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://ww [...]
-
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize" default-destroy-method="destroy">
+
+ <bean id="shibboleth.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/credentials"/>
+
<bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCICredentialsRequestDecoder"
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-beans.xml
new file mode 100644
index 0000000..57870b7
--- /dev/null
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-beans.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize" default-destroy-method="destroy">
+
+ <bean id="shibboleth.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/nonce"/>
+
+ <bean id="InitializeUnverifiedRelyingPartyContext"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext" scope="prototype" />
+
+ <bean id="FormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundNonceResponseMessage"
+ scope="prototype" />
+
+ <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ scope="prototype" p:defaultStatusCode="400" p:defaultCode="invalid_request"
+ p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
+ <property name="eventContextLookupStrategy">
+ <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
+ </property>
+ <property name="mappedErrors">
+ <map value-type="com.nimbusds.oauth2.sdk.ErrorObject">
+ <!--
+ ADD SOME
+ -->
+ </map>
+ </property>
+ </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
new file mode 100644
index 0000000..69ebc74
--- /dev/null
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<flow xmlns="http://www.springframework.org/schema/webflow"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+ parent="openid/vci/abstract-api">
+
+ <action-state id="InitializeMandatoryContexts">
+ <evaluate expression="InitializeProfileRequestContext"/>
+ <evaluate expression="PopulateMetricContext"/>
+ <evaluate expression="FlowStartPopulateAuditContext"/>
+ <evaluate expression="InitializeOutboundMessageContext"/>
+ <evaluate expression="InitializeUnverifiedRelyingPartyContext" />
+ <evaluate expression="SelectRelyingPartyConfiguration" />
+ <evaluate expression="SelectProfileConfiguration" />
+ <evaluate expression="'proceed'"/>
+ <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/flows/openid/vci/token/token-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml
index f5a8eab..6210619 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml
@@ -1,6 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://ww [...]
-
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize" default-destroy-method="destroy">
+
+ <bean id="shibboleth.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/token"/>
+
<bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCITokenRequestDecoder"
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 54%
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 c7f2ea7..7e77d6c 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,8 +17,10 @@
p:placeholderPrefix="%{" p:placeholderSuffix="}" />
- <bean id="AbstractVCIProfile" abstract="true"
- p:issuer="#{getObject('shibboleth.oidc.issuer')}"
+ <bean id="AbstractVCIProfile" abstract="true"
+ p:issuer="#{getObject('shibboleth.oidc.issuer')}"
+ p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
+ p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
p:forcePKCE="%{idp.oidc.forcePKCE:false}"
p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
@@ -26,24 +28,37 @@
p:accessTokenLifetime="%{idp.oidc.accessToken.defaultLifetime:PT10M}"
p:tokenEndpointAuthMethod="%{idp.authn.oidc.rp.client.authenticationMethod:client_secret_basic}"
p:securityConfiguration-ref="%{idp.security.oidc.config:shibboleth.oidc.DefaultSecurityConfiguration}"
- p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}" />
-
- <bean id="OpenID.VCI" parent="AbstractVCIProfile" lazy-init="true"
- class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration"
- p:issuer="#{getObject('shibboleth.oidc.issuer')}"
- p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
- p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
- p:accessTokenLifetime="%{openidvci.accessToken.defaultLifetime:PT5M}"/>
-
- <!-- 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" />
+ p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}"
+ p:dpopProofClaimsValidator="#{getObject('DefaultDPoPProofClaimsValidator')}"
+ p:dpopProofSignatureValidationConfiguration="#{getObject('DPoPSignatureValidationConfiguration')}"
+ p:dpopProofNonceGenerator="#{getObject('DefaultOAuth2DPoPNonceGenerator')}" />
+
- <bean id="openidvci.AuthzCodeManipulationStrategy"
- class="org.geant.shibboleth.plugin.openidvci.profile.logic.AuthorizationCodeManipulationStrategy" />
+ <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"
+ p:dpopProofNonceGenerator="#{getObject('DefaultOpenIDVCINonceGenerator')}" />
+
+
+ <!-- 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