[java-idp-plugin-vci] 02/02: Moving token flow logic incrementally closet to OP Token flow by unwrapping grant in post decode phase
Codeberg
noreply at shibboleth.net
Wed Dec 3 15:16:08 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/4b748aad80fb875465abb131ccde8fcb55d8d755
commit 4b748aad80fb875465abb131ccde8fcb55d8d755
Author: jlauros <janne.lauros at csc.fi>
AuthorDate: Wed Dec 3 17:15:33 2025 +0200
Moving token flow logic incrementally closet to OP Token flow by unwrapping grant in post decode phase
---
.../plugin/openidvci/profile/impl/UnwrapGrant.java | 257 +++++++++++++++++++++
.../profile/impl/ValidateAuthorizedCodeGrant.java | 91 --------
.../impl/ValidatePreAuthorizedCodeGrant.java | 161 -------------
.../idp/flows/openid/vci/token/token-beans.xml | 12 +-
.../idp/flows/openid/vci/token/token-flow.xml | 27 ++-
5 files changed, 281 insertions(+), 267 deletions(-)
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/UnwrapGrant.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/UnwrapGrant.java
new file mode 100644
index 0000000..37a9358
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/UnwrapGrant.java
@@ -0,0 +1,257 @@
+/*
+ * 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.io.IOException;
+import java.text.ParseException;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
+import org.geant.shibboleth.plugin.openidvci.messaging.impl.AbstractOpenIDVCITokenResponseAction;
+import org.geant.shibboleth.plugin.openidvci.profile.context.navigate.APIRequestClientIDLookupFunction;
+import org.geant.shibboleth.plugin.openidvci.storage.CredentialOfferCache;
+import org.geant.shibboleth.plugin.openidvci.storage.CredentialOfferObject;
+import org.geant.shibboleth.plugin.openidvci.token.support.CredentialOfferClaimsSet;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.GrantType;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
+import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.security.DataSealer;
+import net.shibboleth.shared.security.DataSealerException;
+
+/**
+ * Action that unwraps an authorization grant or pre-authorized grant.
+ *
+ * <p>
+ * Operation is valid if it is successfully unwrapped, parsed as a code or
+ * refresh token, is unexpired and was issued to the expected client.
+ *
+ * Pre-authorized grant may also be located from storage.
+ * </p>
+ *
+ * <p>
+ * The claims set from the authorization grant grant is stored to response context via
+ * {@link OIDCAuthenticationResponseContext#setAuthorizationGrantClaimsSet(TokenClaimsSet)}.
+ * </p>
+ *
+ * <p>
+ * The credential offer object from pre-authorised grant is stored to response context via
+ * {@link TokenContext#setCredentialOfferObject}.
+ * </p>
+ *
+ * <p>
+ * The potential credentials from pre-authorised grant is stored to response context via
+ * {@link TokenContext#setPotentialCredentials}.
+ * </p>
+ *
+ * @since 4.4.0
+ */
+public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
+
+ /** Class logger. */
+ @Nonnull
+ private Logger log = LoggerFactory.getLogger(UnwrapGrant.class);
+
+ /** Data sealer for unwrapping authorization code. */
+ @Nonnull
+ private final DataSealer dataSealer;
+
+ /** Strategy used to obtain the client id value from token request. */
+ @Nonnull
+ private Function<MessageContext, ClientID> clientIDLookupStrategy;
+
+ @NonnullAfterInit
+ private CredentialOfferCache credentialOfferCache;
+
+ /**
+ * Constructor.
+ *
+ * @param sealer sealer to decrypt/hmac authorize code.
+ */
+ public UnwrapGrant(@Nonnull @ParameterName(name = "sealer") final DataSealer sealer) {
+ dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
+ clientIDLookupStrategy = new APIRequestClientIDLookupFunction();
+ }
+
+ /**
+ * Set the credential offer cache instance to use.
+ *
+ * @param cache The credential offer cache to set.
+ */
+ public void setCredentialOfferCache(@Nonnull final CredentialOfferCache cache) {
+ checkSetterPreconditions();
+ credentialOfferCache = Constraint.isNotNull(cache, "CredentialOfferCache cannot be null");
+ }
+
+
+ /**
+ * Set the strategy used to locate the client id of the request.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setClientIDLookupStrategy(@Nonnull final Function<MessageContext, ClientID> strategy) {
+ ifInitializedThrowUnmodifiabledComponentException();
+ clientIDLookupStrategy = Constraint.isNotNull(strategy,
+ "ClientIDLookupStrategy lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+ if (credentialOfferCache == null) {
+ throw new ComponentInitializationException("CredentialOfferCache cannot be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ final AuthorizationGrant grant = getTokenRequest() != null ? getTokenRequest().getAuthorizationGrant():null;
+ //DO NOT ADD IT YET
+ TokenContext tokenContext = profileRequestContext.getInboundMessageContext().ensureSubcontext(TokenContext.class);
+ if (grant != null) {
+ // Grant type is something OP traditionally understands, not OP
+ // Most of the code executed in this block is from OP Unwrap implementation.
+ log.debug("{} Unwrapping grant type: {}", getLogPrefix(), grant.getType());
+ TokenClaimsSet tokenClaimsSet = null;
+ if (GrantType.AUTHORIZATION_CODE.equals(grant.getType())) {
+ final AuthorizationCodeGrant codeGrant = (AuthorizationCodeGrant) grant;
+ if (codeGrant.getAuthorizationCode() != null && codeGrant.getAuthorizationCode().getValue() != null) {
+ try {
+ final String codeValue = codeGrant.getAuthorizationCode().getValue();
+ assert codeValue != null;
+ final AuthorizeCodeClaimsSet authzCodeClaimsSet = AuthorizeCodeClaimsSet.parse(codeValue,
+ dataSealer);
+ assert authzCodeClaimsSet != null;
+ final String jti = authzCodeClaimsSet.getID();
+ if (jti == null) {
+ log.warn("{} Invalid contents in the authz code grant: no JTI", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ return;
+ }
+ log.debug("{} Authz code unwrapped {}", getLogPrefix(), authzCodeClaimsSet.serialize());
+ tokenClaimsSet = authzCodeClaimsSet;
+
+ } catch (final DataSealerException | ParseException e) {
+ log.warn("{} Unwrapping authz code failed: {}", getLogPrefix(), e.getMessage());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ return;
+ }
+ }
+ }
+ validateTokenClaimsSet(profileRequestContext, tokenClaimsSet);
+ final OIDCAuthenticationResponseContext oidcResponseContext = getOidcResponseContext();
+ assert oidcResponseContext != null;
+ oidcResponseContext.setAuthorizationGrantClaimsSet(tokenClaimsSet);
+ tokenContext.setPotentialCredentials(tokenClaimsSet.getUserinfoDeliveryClaims());
+ return;
+ }else if (getOpenIDVCITokenRequest().getPreAuthorizedCode() instanceof String ){
+ // This is pre-authorized grant
+ String code = getOpenIDVCITokenRequest().getPreAuthorizedCode();
+ log.info("{} Unwrapping pre-authorization code: {}", getLogPrefix(), code);
+
+ Exception e;
+ try {
+ CredentialOfferClaimsSet credentialOffer = CredentialOfferClaimsSet.parse(code, dataSealer);
+ assert credentialOffer != null;
+ final String jti = credentialOffer.getID();
+ if (jti == null) {
+ log.warn("{} Invalid contents in the pre-authorized grant: no JTI", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ return;
+ }
+ log.debug("{} pre-authorized grant unwrapped {}", getLogPrefix(), credentialOffer.serialize());
+ validateTokenClaimsSet(profileRequestContext, credentialOffer);
+ tokenContext.setCredentialOfferObject(CredentialOfferObject.parse(credentialOffer.getSubject()));
+ setPotentialCredentials(tokenContext);
+ return;
+ } catch (final DataSealerException | JsonProcessingException | com.nimbusds.oauth2.sdk.ParseException | ParseException e2) {
+ log.warn("{} Unwrapping authz code failed: {}, might be storage based", getLogPrefix(), e2.getMessage());
+ }
+
+ try {
+ tokenContext.setCredentialOfferObject(credentialOfferCache.getCredentialOffer(code));
+ setPotentialCredentials(tokenContext);
+ credentialOfferCache.removeCredentialOffer(code);
+ return;
+ } catch (IOException | net.minidev.json.parser.ParseException e1) {
+ e = e1;
+ }
+ log.error("{} Validating pre-authorized code {} failed", getLogPrefix(), code, e);
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ }
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+
+ }
+
+ private void validateTokenClaimsSet(@Nonnull final ProfileRequestContext profileRequestContext, TokenClaimsSet tokenClaimsSet) {
+ if (tokenClaimsSet == null) {
+ log.warn("{} Grant type not supported", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ return;
+ }
+ if (!tokenClaimsSet.isTimeValid()) {
+ log.warn("{} Token is expired or not net valid", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ return;
+ }
+ final ClientID clientId = tokenClaimsSet.getClientID();
+ assert clientId != null;
+ final ClientID requestClientId = clientIDLookupStrategy
+ .apply(profileRequestContext.ensureInboundMessageContext());
+ final ClientID inheritedClientId = new ClientID(clientId.getValue()+"/wallet");
+ if (!clientId.equals(requestClientId) && !inheritedClientId.equals(requestClientId)) {
+ log.warn("{} Token issued to client {}, invalid for {}", getLogPrefix(), clientId.getValue(),
+ requestClientId);
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+ return;
+ }
+ }
+
+ private void setPotentialCredentials(@Nonnull TokenContext ctx) {
+ ClaimsSet credentialOfferClaims = new ClaimsSet();
+ ctx.getCredentialOfferObject().getPreAuthorizedCredentials().forEach((key, value) -> {
+ try {
+ credentialOfferClaims.setClaim(key, value.serialize());
+ } catch (JsonProcessingException e) {
+ log.warn("{} Error occurred while handling CredentialOfferObject {}", getLogPrefix(), e);
+
+ }
+ });
+ ctx.setPotentialCredentials(credentialOfferClaims);
+ }
+
+
+}
\ No newline at end of file
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateAuthorizedCodeGrant.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateAuthorizedCodeGrant.java
deleted file mode 100644
index 865d5e6..0000000
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidateAuthorizedCodeGrant.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.geant.shibboleth.plugin.openidvci.profile.impl;
-
-import java.text.ParseException;
-
-import javax.annotation.Nonnull;
-
-import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
-import org.geant.shibboleth.plugin.openidvci.messaging.impl.OpenIDVCITokenRequest;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
-import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
-import net.shibboleth.idp.profile.AbstractProfileAction;
-import net.shibboleth.oidc.profile.core.OidcEventIds;
-import net.shibboleth.shared.annotation.ParameterName;
-import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.security.DataSealer;
-import net.shibboleth.shared.security.DataSealerException;
-import net.shibboleth.shared.primitive.LoggerFactory;
-
-public class ValidateAuthorizedCodeGrant extends AbstractProfileAction {
-
- /** Class logger. */
- @Nonnull
- private Logger log = LoggerFactory.getLogger(ValidateAuthorizedCodeGrant.class);
-
- /** Data sealer for unwrapping authorization code. */
- @Nonnull
- private final DataSealer dataSealer;
-
- @NonnullBeforeExec
- private String code;
-
- /**
- * Constructor.
- *
- * @param sealer sealer to decrypt/hmac authorize code.
- */
- public ValidateAuthorizedCodeGrant(@Nonnull @ParameterName(name = "sealer") final DataSealer sealer) {
- dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- if (!super.doPreExecute(profileRequestContext)) {
- return false;
- }
- if (profileRequestContext.getInboundMessageContext() == null) {
- log.error("{} No inbound message context", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return false;
- }
- if (profileRequestContext.getInboundMessageContext().getMessage() instanceof OpenIDVCITokenRequest request) {
- code = request.getCode();
- }
- if (code == null) {
- log.error("{} No authorization code in vci token request", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
- return false;
- }
- return true;
- }
-
- @Override
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- log.info("{} Validating authorization code: {}", getLogPrefix(), code);
- try {
- TokenContext ctx = profileRequestContext.getInboundMessageContext().ensureSubcontext(TokenContext.class);
- ctx.setAuthorizeCodeClaimsSet(AuthorizeCodeClaimsSet.parse(code, dataSealer));
- ctx.setPotentialCredentials(ctx.getAuthorizeCodeClaimsSet().getUserinfoDeliveryClaims());
- // TODO: Now we are using mix of OIDCAuthenticationResponseContext and flow
- // specific TokenContext. Make a policy decision on that.
- OIDCAuthenticationResponseContext oidcRespCtx = profileRequestContext.getOutboundMessageContext()
- .ensureSubcontext(OIDCAuthenticationResponseContext.class);
- oidcRespCtx.setAuthorizationGrantClaimsSet(ctx.getAuthorizeCodeClaimsSet());
- } catch (ParseException | DataSealerException e) {
- log.warn("{} Unwrapping authz code failed: {}", getLogPrefix(), e.getMessage());
- ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
- return;
- }
-
- }
-
-}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidatePreAuthorizedCodeGrant.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidatePreAuthorizedCodeGrant.java
deleted file mode 100644
index dbe5880..0000000
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/ValidatePreAuthorizedCodeGrant.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.io.IOException;
-import java.text.ParseException;
-
-import javax.annotation.Nonnull;
-
-import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
-import org.geant.shibboleth.plugin.openidvci.messaging.impl.OpenIDVCITokenRequest;
-import org.geant.shibboleth.plugin.openidvci.storage.CredentialOfferCache;
-import org.geant.shibboleth.plugin.openidvci.storage.CredentialOfferObject;
-import org.geant.shibboleth.plugin.openidvci.token.support.CredentialOfferClaimsSet;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
-
-import net.shibboleth.idp.profile.AbstractProfileAction;
-import net.shibboleth.oidc.profile.core.OidcEventIds;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.shared.security.DataSealer;
-import net.shibboleth.shared.security.DataSealerException;
-
-public class ValidatePreAuthorizedCodeGrant extends AbstractProfileAction {
-
- /** Class logger. */
- @Nonnull
- private Logger log = LoggerFactory.getLogger(ValidatePreAuthorizedCodeGrant.class);
-
- @NonnullAfterInit
- private CredentialOfferCache credentialOfferCache;
-
- /** Data sealer for unwrapping pre-authorized code. */
- @NonnullAfterInit
- private DataSealer dataSealer;
-
- @NonnullBeforeExec
- private String code;
-
- /**
- * Set the credential offer cache instance to use.
- *
- * @param cache The credential offer cache to set.
- */
- public void setCredentialOfferCache(@Nonnull final CredentialOfferCache cache) {
- checkSetterPreconditions();
- credentialOfferCache = Constraint.isNotNull(cache, "CredentialOfferCache cannot be null");
- }
-
- /**
- * Set the data sealer instance to use.
- *
- * @param sealer sealer to use
- */
- public void setDataSealer(@Nonnull final DataSealer sealer) {
- ifInitializedThrowUnmodifiabledComponentException();
- dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (dataSealer == null) {
- throw new ComponentInitializationException("DataSealer cannot be null");
- }
- if (credentialOfferCache == null) {
- throw new ComponentInitializationException("CredentialOfferCache cannot be null");
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- if (!super.doPreExecute(profileRequestContext)) {
- return false;
- }
- if (profileRequestContext.getInboundMessageContext() == null) {
- log.error("{} No inbound message context", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return false;
- }
- if (profileRequestContext.getInboundMessageContext().getMessage() instanceof OpenIDVCITokenRequest request) {
- code = request.getPreAuthorizedCode();
- }
- if (code == null) {
- log.error("{} No pre-authorization code in vci token request.", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
- return false;
- }
- return true;
- }
-
- @Override
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- log.info("{} Validating pre-authorization code: {}", getLogPrefix(), code);
- TokenContext ctx = profileRequestContext.getInboundMessageContext().ensureSubcontext(TokenContext.class);
- Exception e;
- try {
- CredentialOfferClaimsSet credentialOffer = CredentialOfferClaimsSet.parse(code, dataSealer);
- ctx.setCredentialOfferObject(CredentialOfferObject.parse(credentialOffer.getSubject()));
- setPotentialCredentials(ctx);
- return;
- } catch (ParseException | DataSealerException | JsonProcessingException
- | com.nimbusds.oauth2.sdk.ParseException e1) {
- // Unable to parse, assuming it is storage based
- e = e1;
- }
- try {
- ctx.setCredentialOfferObject(credentialOfferCache.getCredentialOffer(code));
- setPotentialCredentials(ctx);
- credentialOfferCache.removeCredentialOffer(code);
- return;
- } catch (IOException | net.minidev.json.parser.ParseException e1) {
- e = e1;
- }
- log.error("{} Validating pre-authorized code {} failed", getLogPrefix(), code, e);
- ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
- return;
-
- }
-
- private void setPotentialCredentials(@Nonnull TokenContext ctx) {
- ClaimsSet credentialOfferClaims = new ClaimsSet();
- ctx.getCredentialOfferObject().getPreAuthorizedCredentials().forEach((key, value) -> {
- try {
- credentialOfferClaims.setClaim(key, value.serialize());
- } catch (JsonProcessingException e) {
- log.warn("{} Error occurred while handling CredentialOfferObject {}", getLogPrefix(), e);
-
- }
- });
- ctx.setPotentialCredentials(credentialOfferClaims);
- }
-
-}
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 fc184d3..6ffc14d 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
@@ -19,22 +19,20 @@
scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
</constructor-arg>
</bean>
+
+ <bean id="UnwrapOrLocateGrant" class="org.geant.shibboleth.plugin.openidvci.profile.impl.UnwrapGrant" scope="prototype"
+ c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
+ p:clientIDLookupStrategy-ref="shibboleth.ClientIDLookupStrategy"
+ p:credentialOfferCache-ref="openidvci.CredentialOfferCache"/>
<bean id="ValidateExpectedGrantType" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidateExpectedGrantType"
scope="prototype"/>
- <bean id="ValidateAuthorizedCodeGrant" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidateAuthorizedCodeGrant"
- scope="prototype" c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"/>
-
<bean id="ValidatePKCE" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidatePKCE" scope="prototype"
p:codeVerifierLookupStrategy-ref="RequestCodeVerifierLookupFunction"/>
<bean id="RequestCodeVerifierLookupFunction" class="org.geant.shibboleth.plugin.openidvci.messaging.context.navigate.RequestCodeVerifierLookupFunction" />
- <bean id="ValidatePreAuthorizedCodeGrant" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidatePreAuthorizedCodeGrant"
- scope="prototype" p:credentialOfferCache-ref="openidvci.CredentialOfferCache"
- p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}" />
-
<bean id="ValidateTxCode" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidateTxCode"
scope="prototype"/>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-flow.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-flow.xml
index 336ef26..a008b4c 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-flow.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-flow.xml
@@ -5,12 +5,25 @@
parent="openid/vci/abstract-api">
<action-state id="InitializeMandatoryContexts">
- <evaluate expression="InitializeProfileRequestContext"/>
- <evaluate expression="PopulateMetricContext"/>
- <evaluate expression="FlowStartPopulateAuditContext"/>
- <evaluate expression="InitializeOutboundMessageContext"/>
- <evaluate expression="'proceed'"/>
- <transition on="proceed" to="DecodeMessage"/>
+ <evaluate expression="InitializeProfileRequestContext" />
+ <evaluate expression="PopulateMetricContext" />
+ <evaluate expression="FlowStartPopulateAuditContext" />
+ <evaluate expression="InitializeOutboundMessageContext" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="DecodeMessage">
+ <set name="flowScope.transitionAfterDecode" value="'PostDecodeMessage'" />
+ </transition>
+ </action-state>
+
+ <action-state id="PostDecodeMessage">
+ <!-- flow specific implementation to unwrap both grants -->
+ <!-- target it to be closer to mother flow with outcome to use mother flow actions -->
+ <evaluate expression="UnwrapOrLocateGrant" />
+ <evaluate expression="'proceed'" />
+
+ <!-- DoMetadataLookup is expected to proceed to SelectConfiguration -->
+ <transition on="proceed" to="DoMetadataLookup" />
</action-state>
<!-- Authentication subflow happens here. -->
@@ -28,14 +41,12 @@
<action-state id="ValidateCodeFlow">
<evaluate expression="ValidateExpectedGrantType"/>
- <evaluate expression="ValidateAuthorizedCodeGrant"/>
<evaluate expression="'proceed'"/>
<transition on="proceed" to="PostValidation"/>
</action-state>
<action-state id="ValidatePreAuthFlow">
<evaluate expression="ValidateExpectedGrantType"/>
- <evaluate expression="ValidatePreAuthorizedCodeGrant"/>
<evaluate expression="ValidateTxCode"/>
<evaluate expression="'proceed'"/>
<transition on="proceed" to="PostValidation"/>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list