[java-idp-plugin-vci] 02/06: clientIDLookupStrategy is now expected to take ProfileRequestContext and not MessageContext as input

Codeberg noreply at shibboleth.net
Tue Dec 9 07:21:57 UTC 2025


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch dev/DPOP
in repository java-idp-plugin-vci.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/7948ad3b66ca6342f9529308a43e1110ae56955b

commit 7948ad3b66ca6342f9529308a43e1110ae56955b
Author: jlauros <janne.lauros at csc.fi>
AuthorDate: Tue Dec 9 08:54:12 2025 +0200

    clientIDLookupStrategy is now expected to take ProfileRequestContext and not MessageContext as input
---
 .../plugin/openidvci/profile/impl/UnwrapGrant.java | 80 +++++++++++++---------
 1 file changed, 47 insertions(+), 33 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
index 37a9358..d331cba 100644
--- 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
@@ -16,6 +16,7 @@ package org.geant.shibboleth.plugin.openidvci.profile.impl;
 
 import java.io.IOException;
 import java.text.ParseException;
+import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -26,9 +27,9 @@ import org.geant.shibboleth.plugin.openidvci.profile.context.navigate.APIRequest
 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.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.slf4j.Logger;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -46,6 +47,7 @@ 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.logic.FunctionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
@@ -55,27 +57,27 @@ import net.shibboleth.shared.security.DataSealerException;
  * 
  * <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 code, 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
+ * 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}.
+ * 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}.
+ * 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 {
 
@@ -89,8 +91,8 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
 
     /** Strategy used to obtain the client id value from token request. */
     @Nonnull
-    private Function<MessageContext, ClientID> clientIDLookupStrategy;
-    
+    private Function<ProfileRequestContext, ClientID> clientIDLookupStrategy;
+
     @NonnullAfterInit
     private CredentialOfferCache credentialOfferCache;
 
@@ -101,9 +103,11 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
      */
     public UnwrapGrant(@Nonnull @ParameterName(name = "sealer") final DataSealer sealer) {
         dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
-        clientIDLookupStrategy = new APIRequestClientIDLookupFunction();
+        APIRequestClientIDLookupFunction lookup = new APIRequestClientIDLookupFunction();
+        lookup.setDataSealer(sealer);
+        clientIDLookupStrategy = FunctionSupport.compose(lookup, new InboundMessageContextLookup());
     }
-    
+
     /**
      * Set the credential offer cache instance to use.
      * 
@@ -114,18 +118,17 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
         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) {
+    public void setClientIDLookupStrategy(@Nonnull final Function<ProfileRequestContext, ClientID> strategy) {
         ifInitializedThrowUnmodifiabledComponentException();
         clientIDLookupStrategy = Constraint.isNotNull(strategy,
                 "ClientIDLookupStrategy lookup strategy cannot be null");
     }
-    
+
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -138,12 +141,8 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
     /** {@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);
+        final AuthorizationGrant grant = getTokenRequest() != null ? getTokenRequest().getAuthorizationGrant() : null;
         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())) {
@@ -163,25 +162,26 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
                         }
                         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 tokenContext = profileRequestContext.getInboundMessageContext()
+                    .ensureSubcontext(TokenContext.class);
             tokenContext.setPotentialCredentials(tokenClaimsSet.getUserinfoDeliveryClaims());
             return;
-        }else if (getOpenIDVCITokenRequest().getPreAuthorizedCode() instanceof String  ){
+        } 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);
@@ -194,17 +194,32 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
                 }
                 log.debug("{} pre-authorized grant unwrapped {}", getLogPrefix(), credentialOffer.serialize());
                 validateTokenClaimsSet(profileRequestContext, credentialOffer);
+                TokenContext tokenContext = profileRequestContext.getInboundMessageContext()
+                        .ensureSubcontext(TokenContext.class);
                 tokenContext.setCredentialOfferObject(CredentialOfferObject.parse(credentialOffer.getSubject()));
+                getOidcResponseContext().setAuthTime(Instant.now());
                 setPotentialCredentials(tokenContext);
+                // Subject and auth time set for access token creation. TODO make sure what
+                // content to use.
+                getOidcResponseContext().setSubject(clientIDLookupStrategy.apply(profileRequestContext).getValue());
+                getOidcResponseContext().setAuthTime(Instant.now());
                 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());
+            } 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 tokenContext = profileRequestContext.getInboundMessageContext()
+                        .ensureSubcontext(TokenContext.class);
                 tokenContext.setCredentialOfferObject(credentialOfferCache.getCredentialOffer(code));
                 setPotentialCredentials(tokenContext);
                 credentialOfferCache.removeCredentialOffer(code);
+                // Subject and auth time set for access token creation. TODO make sure what
+                // content to use.
+                getOidcResponseContext().setSubject(clientIDLookupStrategy.apply(profileRequestContext).getValue());
+                getOidcResponseContext().setAuthTime(Instant.now());
                 return;
             } catch (IOException | net.minidev.json.parser.ParseException e1) {
                 e = e1;
@@ -216,7 +231,8 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
 
     }
 
-    private void validateTokenClaimsSet(@Nonnull final ProfileRequestContext profileRequestContext, TokenClaimsSet tokenClaimsSet) {
+    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);
@@ -229,9 +245,8 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
         }
         final ClientID clientId = tokenClaimsSet.getClientID();
         assert clientId != null;
-        final ClientID requestClientId = clientIDLookupStrategy
-                .apply(profileRequestContext.ensureInboundMessageContext());
-        final ClientID inheritedClientId = new ClientID(clientId.getValue()+"/wallet");
+        final ClientID requestClientId = clientIDLookupStrategy.apply(profileRequestContext);
+        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);
@@ -239,7 +254,7 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
             return;
         }
     }
-    
+
     private void setPotentialCredentials(@Nonnull TokenContext ctx) {
         ClaimsSet credentialOfferClaims = new ClaimsSet();
         ctx.getCredentialOfferObject().getPreAuthorizedCredentials().forEach((key, value) -> {
@@ -253,5 +268,4 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
         ctx.setPotentialCredentials(credentialOfferClaims);
     }
 
-
 }
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list