[java-idp-plugin-vci] branch bugs/LowHanging updated: Drop partially implemented supprort for creating code flow offer and 'issuer_state'. We simply do not support that use case for now.
Codeberg
noreply at shibboleth.net
Mon Sep 21 11:37:43 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch bugs/LowHanging
in repository java-idp-plugin-vci.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/cdfcd4ddd155435150363def2297540244c63fea
The following commit(s) were added to refs/heads/bugs/LowHanging by this push:
new cdfcd4d Drop partially implemented supprort for creating code flow offer and 'issuer_state'. We simply do not support that use case for now.
cdfcd4d is described below
commit cdfcd4ddd155435150363def2297540244c63fea
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Mon Sep 21 14:37:20 2026 +0300
Drop partially implemented supprort for creating code flow offer and 'issuer_state'. We simply do not support that use case for now.
---
README.md | 26 +++++----
.../messaging/context/CredentialOfferContext.java | 39 ++-----------
.../messaging/impl/CredentialOfferRequest.java | 65 ++++++----------------
.../impl/CredentialOfferSuccessResponse.java | 39 ++-----------
.../profile/impl/BuildCredentialOfferToken.java | 8 +--
...FormOutboundCredentialOfferResponseMessage.java | 5 +-
.../profile/impl/ValidateCredentialOffering.java | 35 ++++++------
.../messaging/impl/CredentialOfferRequestTest.java | 8 +--
.../impl/ValidateCredentialOfferingTest.java | 23 +++-----
9 files changed, 77 insertions(+), 171 deletions(-)
diff --git a/README.md b/README.md
index 0a7d6dd..7f495c3 100644
--- a/README.md
+++ b/README.md
@@ -636,15 +636,21 @@ values in it, only the ids of the credentials the wallet may ask for. After it t
a normal authorization request, the user authenticates at the IdP as usual and the credential
content comes from an IdP attribute that is resolved for the user that just logged in.
-Nothing in the offer is per user here, so you write it by hand. The same url serves everybody
-and you may print it once as a QR code:
+Nothing in the offer is per user here, so you write it by hand. The credential offer endpoint
+does not produce this one: with no claim values to seal and no state to carry, the response
+would be the same bytes for every call. The same url serves everybody and you may print it
+once as a QR code:
```
openid-credential-offer://?credential_offer=%7B%22credential_issuer%22:%22https://issuer.example.org%22,%22credential_configuration_ids%22:%5B%22GeantIncubatorDiploma_SDJWT%22%5D,%22grants%22:%7B%22authorization_code%22:%7B%7D%7D%7D
```
-The `authorization_code` grant is what tells the wallet to run this flow. What is issued comes
-from the attribute below, not from the offer.
+The `authorization_code` grant is what tells the wallet to run this flow. It is empty;
+`issuer_state` is not supported. What is issued comes from the attribute below, not from the
+offer.
+
+The `credential_issuer` value has to be the Credential Issuer Identifier this deployment
+publishes, the same string as in *openid-credential-issuer.json*.
The wallet is a normal OIDC client of one identity, there is no second one as in the
pre-authorized code flow. You register it with the client metadata resolver of the OP plugin:
@@ -1600,14 +1606,14 @@ Creates a Credential Offer. A `POST` of `application/json` to
| Name | Type | Description |
|---|---|---|
-| `preAuthorizedCredentials` | Object | The credentials of a pre-authorized code offer, keyed with the credential configuration id. The value of each is an array of `{"path": [...], "value": ...}`, the claims and the values as they are issued. Exactly one of this and `codeCredentials`. |
-| `codeCredentials` | Array of String | The credential configuration ids of an authorization code offer. No values here, the claims are resolved from attributes when the user authenticates. Exactly one of this and `preAuthorizedCredentials`. |
-| `txCode` | Object | Transaction Code the wallet has to present in the token request. `value` is the code. `input_mode` (`numeric` or `text`), `length` and `description` are optional hints the wallet draws its input screen from and nothing checks them against `value`. `value` is not published in the offer, so delivering it to the user is the job of the caller and it has to happen in some other way than the offer itself. Read only together with `preAuthorizedCredentials`. |
+| `preAuthorizedCredentials` | Object | Required. The credentials of a pre-authorized code offer, keyed with the credential configuration id. The value of each is an array of `{"path": [...], "value": ...}`, the claims and the values as they are issued. |
+| `txCode` | Object | Transaction Code the wallet has to present in the token request. `value` is the code. `input_mode` (`numeric` or `text`), `length` and `description` are optional hints the wallet draws its input screen from and nothing checks them against `value`. `value` is not published in the offer, so delivering it to the user is the job of the caller and it has to happen in some other way than the offer itself. |
| `client_id` | String | Identifies the caller when the request carries no client authentication. Of use only where you accept unauthenticated clients. |
-Both `preAuthorizedCredentials` and `codeCredentials` in one request is an error and so is
-neither of them. Every credential configuration id has to exist in
-*metadata/verifiable-credentials.json*.
+This endpoint serves the pre-authorized code flow. A request without
+`preAuthorizedCredentials` is an error. Every credential configuration id has to exist in
+*metadata/verifiable-credentials.json*. An authorization code flow offer is a static link,
+described under *Authorization code flow*.
<details>
<summary>Example of a call</summary>
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/CredentialOfferContext.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/CredentialOfferContext.java
index ada7e56..1717da6 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/CredentialOfferContext.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/CredentialOfferContext.java
@@ -16,7 +16,6 @@
package org.geant.shibboleth.plugin.openidvci.messaging.context;
-import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -40,16 +39,12 @@ public class CredentialOfferContext extends BaseContext {
@Nullable
private Map<String, CredentialOfferRequestedCredential> preAuthorizedCredentials;
- /** List of credentials for Credential offer in code flow. */
- @Nullable
- private List<String> codeCredentials;
-
/** Transaction Code. */
@Nullable
private CredentialOfferTxCode credentialOfferTxCode;
/**
- * Token that serves both as pre-authorized code and issuer_state in responses.
+ * Token returned as the pre-authorized code in responses.
*/
@Nullable
private String credentialOfferToken;
@@ -96,26 +91,7 @@ public class CredentialOfferContext extends BaseContext {
return preAuthorizedCredentials;
}
- /**
- * Set list of credentials for Credential offer in code flow.
- *
- * @param credentials List of credentials for Credential offer in code flow
- */
- @Nullable
- public void setValidatedCodeCredentials(@Nullable final List<String> credentials) {
- this.codeCredentials = credentials;
- }
-
- /**
- * Get list of credentials for Credential offer in code flow.
- *
- * @return List of credentials for Credential offer in code flow
- */
- @Nullable
- public List<String> getValidatedCodeCredentials() {
- return codeCredentials;
- }
/**
* Get Transaction Code.
@@ -137,11 +113,9 @@ public class CredentialOfferContext extends BaseContext {
}
/**
- * Get token that serves both as pre-authorized code and issuer_state in
- * responses.
+ * Get token returned as the pre-authorized code in responses.
*
- * @return Token that serves both as pre-authorized code and issuer_state in
- * responses
+ * @return Token returned as the pre-authorized code in responses
*/
@Nullable
public String getCredentialOfferToken() {
@@ -149,11 +123,10 @@ public class CredentialOfferContext extends BaseContext {
}
/**
- * Set token that serves both as pre-authorized code and issuer_state in
- * responses.
+ * Set token returned as the pre-authorized code in responses.
*
- * @param credentialOfferToken Token that serves both as pre-authorized code and
- * issuer_state in responses
+ * @param credentialOfferToken Token returned as the pre-authorized code in
+ * responses
*/
public void setCredentialOfferToken(@Nullable final String credentialOfferToken) {
this.credentialOfferToken = credentialOfferToken;
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequest.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequest.java
index 675fe6b..257fbb8 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequest.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequest.java
@@ -19,7 +19,6 @@ package org.geant.shibboleth.plugin.openidvci.messaging.impl;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
@@ -53,10 +52,6 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
@Nullable
private final Map<String, CredentialOfferRequestedCredential> preAuthorizedCredentials;
- /** List of credentials for Credential offer in code flow. */
- @Nullable
- private final List<String> codeCredentials;
-
/** Transaction Code. */
@Nullable
private final CredentialOfferTxCode credentialOfferTxCode;
@@ -70,17 +65,13 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
* used).
* @param clientAuth The client authentication, {@code null} if none.
* @param preAuthorizedCredentials Credentials offered in the pre-authorized code flow.
- * @param codeCredentials Credentials offered in the authorization code flow.
* @param credentialOfferTxCode Transaction Code the wallet must present.
*/
public CredentialOfferRequest(@Nullable final URI uri, @Nullable final ClientAuthentication clientAuth,
@Nullable final Map<String, CredentialOfferRequestedCredential> preAuthorizedCredentials,
- @Nullable final List<String> codeCredentials, @Nullable final CredentialOfferTxCode credentialOfferTxCode) {
+ @Nullable final CredentialOfferTxCode credentialOfferTxCode) {
super(uri, clientAuth);
- assert !(preAuthorizedCredentials == null && codeCredentials == null);
- assert !(preAuthorizedCredentials != null && codeCredentials != null);
this.preAuthorizedCredentials = preAuthorizedCredentials;
- this.codeCredentials = codeCredentials;
this.credentialOfferTxCode = credentialOfferTxCode;
}
@@ -92,17 +83,13 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
* the {@link #toHTTPRequest()} method will not be used).
* @param clientID The client identifier, {@code null} if not specified.
* @param preAuthorizedCredentials Credentials offered in the pre-authorized code flow.
- * @param codeCredentials Credentials offered in the authorization code flow.
* @param credentialOfferTxCode Transaction Code the wallet must present.
*/
public CredentialOfferRequest(@Nullable final URI uri, @Nullable final ClientID clientID,
@Nullable final Map<String, CredentialOfferRequestedCredential> preAuthorizedCredentials,
- @Nullable final List<String> codeCredentials, @Nullable final CredentialOfferTxCode credentialOfferTxCode) {
+ @Nullable final CredentialOfferTxCode credentialOfferTxCode) {
super(uri, clientID);
- assert !(preAuthorizedCredentials == null && codeCredentials == null);
- assert !(preAuthorizedCredentials != null && codeCredentials != null);
this.preAuthorizedCredentials = preAuthorizedCredentials;
- this.codeCredentials = codeCredentials;
this.credentialOfferTxCode = credentialOfferTxCode;
}
@@ -115,15 +102,6 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
return preAuthorizedCredentials;
}
- /**
- * Get list of credentials for Credential offer in code flow.
- *
- * @return List of credentials for Credential offer in code flow
- */
- public List<String> getCodeCredentials() {
- return codeCredentials;
- }
-
/**
* Get Transaction Code.
*
@@ -164,35 +142,29 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
throw new ParseException(e1.getMessage());
}
- if (content.containsKey("preAuthorizedCredentials") && content.containsKey("codeCredentials")
- || !content.containsKey("preAuthorizedCredentials") && !content.containsKey("codeCredentials")) {
-
+ if (content.containsKey("codeCredentials")) {
+ throw new ParseException("Invalid credential offer request: The parameter 'codeCredentials' is not "
+ + "supported. This endpoint offers the pre-authorized code flow only; an authorization code "
+ + "flow offer carries no per request state and is published as a static link");
+ }
+ if (!content.containsKey("preAuthorizedCredentials")) {
throw new ParseException(
- "Invalid credential offer request: Exactly one of the parameters "
- + "'preAuthorizedCredentials' 'codeCredentials' must exist");
+ "Invalid credential offer request: The parameter 'preAuthorizedCredentials' must exist");
}
- Map<String, CredentialOfferRequestedCredential> preAuthorizedCredentials = null;
- if (content.containsKey("preAuthorizedCredentials")) {
- final Map<String, Object> preAuthorizedCredentialsInRequest = (Map<String, Object>) content
- .get("preAuthorizedCredentials");
- preAuthorizedCredentials = new HashMap<>();
- for (final String key : preAuthorizedCredentialsInRequest.keySet()) {
- preAuthorizedCredentials.put(key,
- CredentialOfferRequestedCredential.parse(preAuthorizedCredentialsInRequest.get(key)));
- }
+ final Map<String, Object> preAuthorizedCredentialsInRequest = (Map<String, Object>) content
+ .get("preAuthorizedCredentials");
+ final Map<String, CredentialOfferRequestedCredential> preAuthorizedCredentials = new HashMap<>();
+ for (final String key : preAuthorizedCredentialsInRequest.keySet()) {
+ preAuthorizedCredentials.put(key,
+ CredentialOfferRequestedCredential.parse(preAuthorizedCredentialsInRequest.get(key)));
}
CredentialOfferTxCode credentialOfferTxCode = null;
- if (content.containsKey("preAuthorizedCredentials") && content.containsKey("txCode")) {
+ if (content.containsKey("txCode")) {
credentialOfferTxCode = CredentialOfferTxCode.parse(content.get("txCode"));
}
- List<String> codeCredentials = null;
- if (content.get("codeCredentials") instanceof List<?> credentials) {
- codeCredentials = (List<String>) credentials;
- }
-
final URI uri;
try {
uri = httpRequest.getURL().toURI();
@@ -200,8 +172,7 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
throw new ParseException(e.getMessage(), e);
}
if (clientAuth != null) {
- return new CredentialOfferRequest(uri, clientAuth, preAuthorizedCredentials, codeCredentials,
- credentialOfferTxCode);
+ return new CredentialOfferRequest(uri, clientAuth, preAuthorizedCredentials, credentialOfferTxCode);
}
// We parse non authenticated client id from JSON content.
@@ -210,7 +181,7 @@ public class CredentialOfferRequest extends AbstractOptionallyIdentifiedRequest
throw new ParseException(
"Invalid credential offer request: No client authentication or client_id parameter found");
}
- return new CredentialOfferRequest(uri, new ClientID(clientIDString), preAuthorizedCredentials, codeCredentials,
+ return new CredentialOfferRequest(uri, new ClientID(clientIDString), preAuthorizedCredentials,
credentialOfferTxCode);
}
// Checkstyle: CyclomaticComplexity ON
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java
index 78cee42..485499b 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java
@@ -70,24 +70,17 @@ public class CredentialOfferSuccessResponse implements SuccessResponse {
* Constructor.
*
* @param issuer Credential Issuer identifier.
- * @param codeOrState Pre-authorized code, or issuer_state in the authorization code flow.
+ * @param preAuthorizedCode Pre-authorized code.
* @param preAuthCredentials Credentials offered in the pre-authorized code flow.
- * @param codeCredentials Credentials offered in the authorization code flow.
* @param credentialOfferTxCode Transaction Code the wallet must present.
*/
- public CredentialOfferSuccessResponse(@Nonnull final String issuer, @Nonnull final String codeOrState,
- @Nullable final Map<String, CredentialOfferRequestedCredential> preAuthCredentials,
- @Nullable final List<String> codeCredentials, @Nullable final CredentialOfferTxCode credentialOfferTxCode) {
+ public CredentialOfferSuccessResponse(@Nonnull final String issuer, @Nonnull final String preAuthorizedCode,
+ @Nonnull final Map<String, CredentialOfferRequestedCredential> preAuthCredentials,
+ @Nullable final CredentialOfferTxCode credentialOfferTxCode) {
credentialIssuer = issuer;
- if (preAuthCredentials != null) {
- credentialConfigurationIds = preAuthCredentials.keySet().stream().collect(Collectors.toList());
- grants = buildPreAuthGrant(codeOrState, credentialOfferTxCode);
-
- } else {
- credentialConfigurationIds = codeCredentials;
- grants = buildCodeGrant(codeOrState, null);
- }
+ credentialConfigurationIds = preAuthCredentials.keySet().stream().collect(Collectors.toList());
+ grants = buildPreAuthGrant(preAuthorizedCode, credentialOfferTxCode);
}
/**
@@ -151,26 +144,6 @@ public class CredentialOfferSuccessResponse implements SuccessResponse {
return httpResponse;
}
- /**
- * Build the authorization code grant of a Credential Offer.
- *
- * @param issuerState issuer_state carried to the authorization request
- * @param authorizationServer authorization server the wallet must use, or null
- * @return grant as a map
- */
- @SuppressWarnings("unchecked")
- public static Map<String, Object> buildCodeGrant(@Nonnull final String issuerState,
- @Nullable final String authorizationServer) {
- assert issuerState != null;
- final Map<String, Object> grant = new HashMap<>();
- grant.put("authorization_code", new HashMap<>());
- ((Map<String, Object>) grant.get("authorization_code")).put("issuer_state", issuerState);
- if (authorizationServer != null) {
- ((Map<String, Object>) grant.get("authorization_code")).put("authorization_server", authorizationServer);
- }
- return grant;
- }
-
/**
* Build the pre-authorized code grant of a Credential Offer.
*
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/BuildCredentialOfferToken.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/BuildCredentialOfferToken.java
index 1090b0f..8f946b4 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/BuildCredentialOfferToken.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/BuildCredentialOfferToken.java
@@ -56,8 +56,9 @@ import net.shibboleth.shared.security.impl.SecureRandomIdentifierGenerationStrat
/**
* Action that builds credential offer token. Token value is either a key to
* storage or a serialized {@link CredentialOfferClaimsSet}. Token is stored to
- * {@link CredentialOfferContext} to be returned in resposen either as
- * pre-authorized_code (pre-authorized flow) or as issuer_state (code flow).
+ * {@link CredentialOfferContext} to be returned in the response as the
+ * pre-authorized_code. The authorization code flow carries no token of its own,
+ * its offer holding only credential configuration ids.
*/
public class BuildCredentialOfferToken extends AbstractProfileAction {
@@ -230,8 +231,7 @@ public class BuildCredentialOfferToken extends AbstractProfileAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final String rpId = rpCtx.getRelyingPartyId();
final CredentialOfferObject credentialRequest = new CredentialOfferObject(new ClientID(rpId),
- ctx.getValidatedPreAuthorizedCredentials(), ctx.getValidatedCodeCredentials(),
- ctx.getCredentialOfferTxCode());
+ ctx.getValidatedPreAuthorizedCredentials(), null, ctx.getCredentialOfferTxCode());
String credentialOfferToken;
if (preAuthorizedCodeLength != 0) {
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialOfferResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialOfferResponseMessage.java
index 1ce80ec..9a36e85 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialOfferResponseMessage.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialOfferResponseMessage.java
@@ -93,12 +93,9 @@ public class FormOutboundCredentialOfferResponseMessage extends AbstractProfileA
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- // TODO: code flow ignores 'issuer_state'. Authentication endpoint should check
- // it. See Specification for guidance.
final CredentialOfferSuccessResponse offer = new CredentialOfferSuccessResponse(
issuerLookupStrategy.apply(profileRequestContext), ctx.getCredentialOfferToken(),
- ctx.getValidatedPreAuthorizedCredentials(), ctx.getValidatedCodeCredentials(),
- ctx.getCredentialOfferTxCode());
+ ctx.getValidatedPreAuthorizedCredentials(), ctx.getCredentialOfferTxCode());
profileRequestContext.ensureOutboundMessageContext().setMessage(offer);
}
}
\ No newline at end of file
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOffering.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOffering.java
index 0b644d3..6d401d7 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOffering.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOffering.java
@@ -71,10 +71,12 @@ public class ValidateCredentialOffering extends AbstractCredentialValidationActi
return false;
}
request = (CredentialOfferRequest) profileRequestContext.getInboundMessageContext().getMessage();
- // Either of the two always exist
- credentialConfIds = request.getPreAuthorizedCredentials() != null
- ? request.getPreAuthorizedCredentials().keySet()
- : Set.copyOf(request.getCodeCredentials());
+ if (request.getPreAuthorizedCredentials() == null) {
+ log.error("{} No pre-authorized credentials in the credential offer request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OpenIDVCIEventIds.NO_CREDENTIALS_REQUEST);
+ return false;
+ }
+ credentialConfIds = request.getPreAuthorizedCredentials().keySet();
return super.doPreExecute(profileRequestContext);
}
@@ -89,26 +91,23 @@ public class ValidateCredentialOffering extends AbstractCredentialValidationActi
}
});
- if (request.getPreAuthorizedCredentials() != null) {
- for (final Map.Entry<String, CredentialOfferRequestedCredential> entry
- : request.getPreAuthorizedCredentials().entrySet()) {
- final CredentialConfiguration configuration = getCredentialConfigurations().get(entry.getKey());
- if (configuration == null) {
- continue;
- }
- if (!hasAllMandatoryClaims(configuration, entry.getValue())) {
- log.error("{} Requested credential {} is missing one or more mandatory claims", getLogPrefix(),
- entry.getKey());
- ActionSupport.buildEvent(profileRequestContext, OpenIDVCIEventIds.NO_CREDENTIALS_REQUEST);
- return;
- }
+ for (final Map.Entry<String, CredentialOfferRequestedCredential> entry
+ : request.getPreAuthorizedCredentials().entrySet()) {
+ final CredentialConfiguration configuration = getCredentialConfigurations().get(entry.getKey());
+ if (configuration == null) {
+ continue;
+ }
+ if (!hasAllMandatoryClaims(configuration, entry.getValue())) {
+ log.error("{} Requested credential {} is missing one or more mandatory claims", getLogPrefix(),
+ entry.getKey());
+ ActionSupport.buildEvent(profileRequestContext, OpenIDVCIEventIds.NO_CREDENTIALS_REQUEST);
+ return;
}
}
final CredentialOfferContext ctx = new CredentialOfferContext();
ctx.setCredentialConfigurations(getCredentialConfigurations());
ctx.setValidatedPreAuthorizedCredentials(request.getPreAuthorizedCredentials());
- ctx.setValidatedCodeCredentials(request.getCodeCredentials());
ctx.setCredentialOfferTxCode(request.getCredentialOfferTxCode());
profileRequestContext.getInboundMessageContext().addSubcontext(ctx, true);
}
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestTest.java
index 26a3b86..d8297db 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferRequestTest.java
@@ -88,14 +88,10 @@ public class CredentialOfferRequestTest {
request = CredentialOfferRequest.parse(httpRequest);
}
- @Test
- public void testCodeFlowSuccess() throws ParseException {
+ @Test(expectedExceptions = ParseException.class)
+ public void testCodeFlowRejected() throws ParseException {
httpRequest.setQuery("{\"codeCredentials\":[\"GeantIncubatorSdJwt1\",\"GeantIncubatorSdJwt2\"]}");
request = CredentialOfferRequest.parse(httpRequest);
- Assert.assertNull(request.getPreAuthorizedCredentials());
- Assert.assertEquals(request.getCodeCredentials().size(), 2);
- Assert.assertTrue(request.getCodeCredentials().contains("GeantIncubatorSdJwt2"));
-
}
}
\ No newline at end of file
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOfferingTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOfferingTest.java
index b19195a..0c1f411 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOfferingTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateCredentialOfferingTest.java
@@ -34,6 +34,7 @@ import org.springframework.webflow.execution.RequestContext;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
@@ -131,18 +132,13 @@ public class ValidateCredentialOfferingTest {
ActionTestingSupport.assertEvent(action.execute(requestCtx), OpenIDVCIEventIds.NO_CREDENTIALS_REQUEST);
}
- @Test
- public void testCodeFlowSuccess() throws Exception {
+ @Test(expectedExceptions = ParseException.class)
+ public void testCodeFlowRejected() throws Exception {
HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
httpRequest.setAuthorization("Basic dGVzdDp0ZXN0");
httpRequest.setContentType("application/json");
httpRequest.setQuery("{\"codeCredentials\":[\"GeantIncubatorDiploma\"]}");
- profileRequestCtx.getInboundMessageContext().setMessage(CredentialOfferRequest.parse(httpRequest));
- ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
- CredentialOfferContext ctx = profileRequestCtx.getInboundMessageContext()
- .getSubcontext(CredentialOfferContext.class);
- Assert.notNull(ctx, "Must not be null");
- Assert.notNull(ctx.getValidatedCodeCredentials(), "Must not be null");
+ CredentialOfferRequest.parse(httpRequest);
}
@Test
@@ -172,18 +168,13 @@ public class ValidateCredentialOfferingTest {
ActionTestingSupport.assertEvent(action.execute(requestCtx), OpenIDVCIEventIds.NO_CREDENTIALS_REQUEST);
}
- @Test
- public void testCodeFlowSuccessVcSdJwt() throws Exception {
+ @Test(expectedExceptions = ParseException.class)
+ public void testCodeFlowRejectedVcSdJwt() throws Exception {
HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
httpRequest.setAuthorization("Basic dGVzdDp0ZXN0");
httpRequest.setContentType("application/json");
httpRequest.setQuery("{\"codeCredentials\":[\"GeantIncubatorDiploma2\"]}");
- profileRequestCtx.getInboundMessageContext().setMessage(CredentialOfferRequest.parse(httpRequest));
- ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
- CredentialOfferContext ctx = profileRequestCtx.getInboundMessageContext()
- .getSubcontext(CredentialOfferContext.class);
- Assert.notNull(ctx, "Must not be null");
- Assert.notNull(ctx.getValidatedCodeCredentials(), "Must not be null");
+ CredentialOfferRequest.parse(httpRequest);
}
/** Resolver that has nothing to resolve. */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list