[java-idp-plugin-vci] branch dev/REFRESH updated: Adopt OP token flow features, Refresh tokens etc.Credential Issuer Identifier as access token audience
Codeberg
noreply at shibboleth.net
Wed Nov 4 09:00:36 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch dev/REFRESH
in repository java-idp-plugin-vci.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/7e5f791cb283d2cbd0cb2a75bf81ae8845d2a01e
The following commit(s) were added to refs/heads/dev/REFRESH by this push:
new 7e5f791 Adopt OP token flow features, Refresh tokens etc.Credential Issuer Identifier as access token audience
7e5f791 is described below
commit 7e5f791cb283d2cbd0cb2a75bf81ae8845d2a01e
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Wed Nov 4 10:59:50 2026 +0200
Adopt OP token flow features, Refresh tokens etc.Credential Issuer Identifier as access token audience
---
.../impl/OpenIDVCITokenRequestDecoder.java | 81 +-
.../PotentialCredentialsLookupFunction.java | 45 +
.../messaging/impl/OpenIDVCITokenRequest.java | 191 ++++-
.../impl/DefaultOpenIDVCITokenConfiguration.java | 90 +-
.../impl/FormOutboundTokenResponseMessage.java | 83 +-
.../impl/InitializePotentialCredentials.java | 65 ++
.../SetCredentialsAudienceToResponseContext.java | 70 +-
...wrapGrant.java => UnwrapPreAuthorizedCode.java} | 88 +-
.../idp/flows/did/document/document-beans.xml | 4 +-
.../authorization-server-beans.xml | 4 +-
.../oauth/jwt-vc-issuer/jwt-vc-issuer-beans.xml | 4 +-
.../status-list/assignments/assignments-beans.xml | 6 +-
.../flows/oauth/status-list/list/list-beans.xml | 4 +-
.../oauth/status-list/revoke/revoke-beans.xml | 6 +-
.../openid/vci/abstract-api/abstract-api-flow.xml | 6 +-
.../credential-offer/credential-offer-beans.xml | 6 +-
.../openid/vci/credentials/credentials-beans.xml | 6 +-
.../vci/issuer-metadata/issuer-metadata-beans.xml | 4 +-
.../idp/flows/openid/vci/nonce/nonce-beans.xml | 4 +-
.../idp/flows/openid/vci/token/token-beans.xml | 917 +++------------------
.../idp/flows/openid/vci/token/token-flow.xml | 95 ++-
.../idp/service/relying-party/postconfig.xml | 35 +-
.../plugin/openidvci/conf/openid-vci.properties | 4 +
.../static/oauth-authorization-server.json | 1 +
.../impl/OpenIDVCITokenRequestDecoderTest.java | 28 +-
.../messaging/impl/OpenIDVCITokenRequestTest.java | 63 +-
.../DefaultOpenIDVCITokenConfigurationTest.java | 18 +-
...etCredentialsAudienceToResponseContextTest.java | 52 +-
28 files changed, 873 insertions(+), 1107 deletions(-)
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoder.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoder.java
index e74bb39..e64135c 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoder.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoder.java
@@ -14,42 +14,65 @@
* limitations under the License.
*/
+/*
+ * Derived from net.shibboleth.idp.plugin.oidc.op.decoding.impl.OIDCTokenRequestDecoder
+ * of the Shibboleth OpenID Connect Provider plugin, Apache License 2.0, modified by GÉANT.
+ */
+
package org.geant.shibboleth.plugin.openidvci.decoding.impl;
import java.io.IOException;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.OpenIDVCITokenRequest;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.shibboleth.idp.plugin.oidc.op.decoding.impl.RequestUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.MoreObjects;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.TokenRequest;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.JakartaServletUtils;
+import jakarta.servlet.http.HttpServletRequest;
+import net.shibboleth.idp.plugin.oidc.op.decoding.impl.RequestUtil;
+import net.shibboleth.idp.plugin.oidc.op.decoding.impl.OIDCTokenRequestDecoder;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
/**
* Message decoder decoding {@link OpenIDVCITokenRequest}s.
*/
-public class OpenIDVCITokenRequestDecoder extends BaseOpenIDVCIRequestDecoder<OpenIDVCITokenRequest> {
+public class OpenIDVCITokenRequestDecoder extends OIDCTokenRequestDecoder {
/** Class logger. */
@Nonnull
private final Logger log = LoggerFactory.getLogger(OpenIDVCITokenRequestDecoder.class);
+ /** Constructor. */
+ public OpenIDVCITokenRequestDecoder() {
+ setProtocolMessageLoggerSubCategory("OAUTH2.OpenIDVCI");
+ }
+
/** {@inheritDoc} */
@Override
- protected OpenIDVCITokenRequest parseMessage() throws MessageDecodingException {
+ protected TokenRequest parseMessage() throws MessageDecodingException {
try {
- final HTTPRequest httpReq = JakartaServletUtils.createHTTPRequest(getHttpServletRequest());
- getProtocolMessageLogger().trace("Inbound request {}", RequestUtil.toString(httpReq));
- return OpenIDVCITokenRequest.parse(httpReq);
- } catch (final com.nimbusds.oauth2.sdk.ParseException | IOException e) {
+ final HttpServletRequest httpServletRequest = getHttpServletRequest();
+ if (httpServletRequest != null) {
+ getProtocolMessageLogger().trace("Inbound request {}",
+ RequestUtil.toString(JakartaServletUtils.createHTTPRequest(httpServletRequest)));
+ final HTTPRequest httpReq = JakartaServletUtils.createHTTPRequest(
+ new RemoveScopeWhenCodeGrantHttpServletRequestWrapper(httpServletRequest));
+ if (httpReq != null) {
+ return OpenIDVCITokenRequest.parse(httpReq);
+ }
+ }
+ throw new MessageDecodingException("Could not create HTTPRequest object from the incoming request");
+ } catch (final ParseException | IOException e) {
log.error("Unable to decode inbound request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
@@ -57,28 +80,34 @@ public class OpenIDVCITokenRequestDecoder extends BaseOpenIDVCIRequestDecoder<Op
/** {@inheritDoc} */
@Override
- protected String getMessageToLog(final OpenIDVCITokenRequest message) {
+ protected String getMessageToLog(@Nullable final TokenRequest message) {
+ if (!(message instanceof OpenIDVCITokenRequest request)) {
+ return super.getMessageToLog(message);
+ }
String details = null;
try {
- details = message.getCredentialAuthorizationDetails() != null
- ? new ObjectMapper().writeValueAsString(message.getCredentialAuthorizationDetails())
+ details = request.getCredentialAuthorizationDetails() != null
+ ? new ObjectMapper().writeValueAsString(request.getCredentialAuthorizationDetails())
: null;
} catch (final JsonProcessingException e) {
log.warn("Failed serializing authorization_details", e);
- // ignore
}
- return message == null ? null
- : MoreObjects.toStringHelper(this).omitNullValues()
- .add("grant_type", message.getGrantType())
- .add("code", message.getCode())
- .add("code_verifier", message.getCodeVerifier())
- .add("pre-authorized_code", message.getPreAuthorizedCode())
- .add("tx_code", message.getTxCode())
- .add("client_authentication",
- RequestUtil.getClientAuthenticationLog(message.getClientAuthentication()))
- .add("client_id", message.getClientID() != null ? message.getClientID().getValue() : null)
- .add("authorization_details", details)
- .toString();
+ return MoreObjects.toStringHelper(this).omitNullValues()
+ .add("grant_type", request.getGrantType())
+ .add("code", request.getCode())
+ .add("code_verifier", request.getCodeVerifier())
+ .add("pre-authorized_code", request.getPreAuthorizedCode())
+ .add("tx_code", request.getTxCode())
+ .add("authorizationGrant", RequestUtil.getAuthorizationGrantLog(request.getAuthorizationGrant()))
+ .add("client_authentication", RequestUtil.getClientAuthenticationLog(request.getClientAuthentication()))
+ .add("client_id", request.getClientID() != null ? request.getClientID().getValue() : null)
+ .add("customParameters", request.getCustomParameters())
+ .add("endpointURI", getEndpointURI(request))
+ .add("existingGrant", RequestUtil.getRefreshTokenLog(request.getExistingGrant()))
+ .add("resources", request.getResources())
+ .add("scope", request.getScope())
+ .add("authorization_details", details)
+ .toString();
}
-}
\ No newline at end of file
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/navigate/PotentialCredentialsLookupFunction.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/navigate/PotentialCredentialsLookupFunction.java
new file mode 100644
index 0000000..1dda7e2
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/context/navigate/PotentialCredentialsLookupFunction.java
@@ -0,0 +1,45 @@
+/*
+ * 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.messaging.context.navigate;
+
+import javax.annotation.Nullable;
+
+import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
+import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
+/** A function that returns potential credentials claims set from token context. Null if not able to locate it. */
+public class PotentialCredentialsLookupFunction
+ implements ContextDataLookupFunction<ProfileRequestContext, ClaimsSet> {
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public ClaimsSet apply(@Nullable final ProfileRequestContext input) {
+ if (input == null || input.getInboundMessageContext() == null) {
+ return null;
+ }
+ final TokenContext ctx = input.ensureInboundMessageContext().getSubcontext(TokenContext.class);
+ if (ctx == null) {
+ return null;
+ }
+ return ctx.getPotentialCredentials();
+ }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequest.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequest.java
index 374370d..a5f32dc 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequest.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequest.java
@@ -18,6 +18,7 @@ package org.geant.shibboleth.plugin.openidvci.messaging.impl;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -31,6 +32,7 @@ import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
import com.nimbusds.oauth2.sdk.AuthorizationGrant;
import com.nimbusds.oauth2.sdk.OAuth2Error;
import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.TokenRequest;
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
@@ -38,6 +40,7 @@ import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.pkce.CodeVerifier;
+import com.nimbusds.oauth2.sdk.token.RefreshToken;
import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils;
import com.nimbusds.oauth2.sdk.util.StringUtils;
@@ -111,7 +114,33 @@ public class OpenIDVCITokenRequest extends TokenRequest {
@Nonnull final String grantType, @Nullable final String preAuthorizedCode, @Nullable final String code,
@Nullable final String txCode, @Nullable final String codeVerifier,
@Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails) {
- super(uri, clientAuth, toAuthorizationGrant(grantType, preAuthorizedCode, code, txCode, codeVerifier));
+ this(uri, clientAuth, grantType, preAuthorizedCode, code, txCode, codeVerifier, null, null,
+ authorizationDetails);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param uri The URI of the endpoint (HTTP or HTTPS) for which
+ * the request is intended, {@code null} if not
+ * specified.
+ * @param clientAuth The client authentication, {@code null} if none.
+ * @param grantType Grant type.
+ * @param preAuthorizedCode The pre-authorized code
+ * @param code Authorization code
+ * @param txCode The tx-code in pre-authorized flow
+ * @param codeVerifier The PKCE code verifier
+ * @param scope The requested scope, {@code null} if not specified.
+ * @param resources The resource URIs, {@code null} if not specified.
+ * @param authorizationDetails Authorization details of the request
+ */
+ public OpenIDVCITokenRequest(@Nullable final URI uri, @Nullable final ClientAuthentication clientAuth,
+ @Nonnull final String grantType, @Nullable final String preAuthorizedCode, @Nullable final String code,
+ @Nullable final String txCode, @Nullable final String codeVerifier, @Nullable final Scope scope,
+ @Nullable final List<URI> resources,
+ @Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails) {
+ super(uri, clientAuth, toAuthorizationGrant(grantType, preAuthorizedCode, code, txCode, codeVerifier),
+ scope, resources, (Map<String, List<String>>) null);
this.grantType = grantType;
this.preAuthorizedCode = preAuthorizedCode;
this.code = code;
@@ -141,8 +170,34 @@ public class OpenIDVCITokenRequest extends TokenRequest {
@Nullable final String preAuthorizedCode, @Nullable final String code, @Nullable final String txCode,
@Nullable final String codeVerifier,
@Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails) {
- super(uri, (ClientID) clientID, toAuthorizationGrant(grantType, preAuthorizedCode, code, txCode,
- codeVerifier));
+ this(uri, clientID, grantType, preAuthorizedCode, code, txCode, codeVerifier, null, null,
+ authorizationDetails);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param uri The URI of the endpoint (HTTP or HTTPS) for which
+ * the request is intended, {@code null} if not
+ * specified.
+ * @param clientID The client identifier, {@code null} if not
+ * specified.
+ * @param grantType Grant type.
+ * @param preAuthorizedCode The pre-authorized code
+ * @param code Authorization code
+ * @param txCode The tx-code in pre-authorized flow
+ * @param codeVerifier The PKCE code verifier
+ * @param scope The requested scope, {@code null} if not specified.
+ * @param resources The resource URIs, {@code null} if not specified.
+ * @param authorizationDetails Authorization details of the request
+ */
+ public OpenIDVCITokenRequest(@Nullable final URI uri, @Nullable final ClientID clientID,
+ @Nonnull final String grantType,
+ @Nullable final String preAuthorizedCode, @Nullable final String code, @Nullable final String txCode,
+ @Nullable final String codeVerifier, @Nullable final Scope scope, @Nullable final List<URI> resources,
+ @Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails) {
+ super(uri, clientID, toAuthorizationGrant(grantType, preAuthorizedCode, code, txCode, codeVerifier),
+ scope, resources, (RefreshToken) null, (Map<String, List<String>>) null);
this.grantType = grantType;
this.preAuthorizedCode = preAuthorizedCode;
this.code = code;
@@ -150,6 +205,55 @@ public class OpenIDVCITokenRequest extends TokenRequest {
this.codeVerifier = codeVerifier;
this.authorizationDetails = authorizationDetails;
}
+
+ /**
+ * Constructor of a request of a grant other than the authorization code and the pre-authorized code.
+ *
+ * @param uri The URI of the endpoint, {@code null} if not specified.
+ * @param clientAuth The client authentication.
+ * @param grant The authorization grant.
+ * @param scope The requested scope, {@code null} if not specified.
+ * @param resources The resource URIs, {@code null} if not specified.
+ * @param customParams Custom parameters, {@code null} if none.
+ * @param authorizationDetails Authorization details of the request
+ */
+ private OpenIDVCITokenRequest(@Nullable final URI uri, @Nonnull final ClientAuthentication clientAuth,
+ @Nonnull final AuthorizationGrant grant, @Nullable final Scope scope, @Nullable final List<URI> resources,
+ @Nullable final Map<String, List<String>> customParams,
+ @Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails) {
+ super(uri, clientAuth, grant, scope, resources, customParams);
+ this.grantType = grant.getType().getValue();
+ this.preAuthorizedCode = null;
+ this.code = null;
+ this.txCode = null;
+ this.codeVerifier = null;
+ this.authorizationDetails = authorizationDetails;
+ }
+
+ /**
+ * Constructor of a request of a grant other than the authorization code and the pre-authorized code.
+ *
+ * @param uri The URI of the endpoint, {@code null} if not specified.
+ * @param clientID The client identifier, {@code null} if not specified.
+ * @param grant The authorization grant.
+ * @param scope The requested scope, {@code null} if not specified.
+ * @param resources The resource URIs, {@code null} if not specified.
+ * @param existingGrant Existing refresh token, {@code null} if none.
+ * @param customParams Custom parameters, {@code null} if none.
+ * @param authorizationDetails Authorization details of the request
+ */
+ private OpenIDVCITokenRequest(@Nullable final URI uri, @Nullable final ClientID clientID,
+ @Nonnull final AuthorizationGrant grant, @Nullable final Scope scope, @Nullable final List<URI> resources,
+ @Nullable final RefreshToken existingGrant, @Nullable final Map<String, List<String>> customParams,
+ @Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails) {
+ super(uri, clientID, grant, scope, resources, existingGrant, customParams);
+ this.grantType = grant.getType().getValue();
+ this.preAuthorizedCode = null;
+ this.code = null;
+ this.txCode = null;
+ this.codeVerifier = null;
+ this.authorizationDetails = authorizationDetails;
+ }
// Checkstyle: ParameterNumber ON
/**
@@ -278,6 +382,7 @@ public class OpenIDVCITokenRequest extends TokenRequest {
}
}
+// Checkstyle: CyclomaticComplexity|MethodLength|ReturnCount OFF
/**
* Parses request from http request.
*
@@ -303,11 +408,6 @@ public class OpenIDVCITokenRequest extends TokenRequest {
throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg));
}
}
- final String grantType = MultivaluedMapUtils.getFirstValue(params, "grant_type");
- final String preAuthorizedCode = MultivaluedMapUtils.getFirstValue(params, "pre-authorized_code");
- final String code = MultivaluedMapUtils.getFirstValue(params, "code");
- final String txCode = MultivaluedMapUtils.getFirstValue(params, "tx_code");
- final String codeVerifier = MultivaluedMapUtils.getFirstValue(params, "code_verifier");
final List<OpenIDVCIAuthorizationDetail> authorizationDetails;
try {
authorizationDetails = OpenIDVCIAuthorizationDetail.parse(httpRequest);
@@ -315,6 +415,16 @@ public class OpenIDVCITokenRequest extends TokenRequest {
throw new ParseException(e.getMessage(),
OAuth2Error.INVALID_REQUEST.appendDescription(": " + e.getMessage()));
}
+ final String grantType = MultivaluedMapUtils.getFirstValue(params, "grant_type");
+ if (!GRANT_TYPE_VALUE_PRE_AUTH.equals(grantType) && !GRANT_TYPE_VALUE_CODE.equals(grantType)) {
+ return wrap(TokenRequest.parse(httpRequest), authorizationDetails, httpRequest);
+ }
+ final Scope scope = Scope.parse(MultivaluedMapUtils.getFirstValue(params, "scope"));
+ final List<URI> resources = parseResources(params);
+ final String preAuthorizedCode = MultivaluedMapUtils.getFirstValue(params, "pre-authorized_code");
+ final String code = MultivaluedMapUtils.getFirstValue(params, "code");
+ final String txCode = MultivaluedMapUtils.getFirstValue(params, "tx_code");
+ final String codeVerifier = MultivaluedMapUtils.getFirstValue(params, "code_verifier");
final URI uri;
try {
uri = httpRequest.getURL().toURI();
@@ -323,7 +433,7 @@ public class OpenIDVCITokenRequest extends TokenRequest {
}
if (clientAuth != null) {
return new OpenIDVCITokenRequest(uri, clientAuth, grantType, preAuthorizedCode, code, txCode, codeVerifier,
- authorizationDetails);
+ scope, resources, authorizationDetails);
}
String clientIDString = MultivaluedMapUtils.getFirstValue(params, "client_id");
if (StringUtils.isBlank(clientIDString)) {
@@ -331,10 +441,69 @@ public class OpenIDVCITokenRequest extends TokenRequest {
}
if (StringUtils.isBlank(clientIDString)) {
return new OpenIDVCITokenRequest(uri, (ClientID) null, grantType, preAuthorizedCode, code, txCode,
- codeVerifier, authorizationDetails);
+ codeVerifier, scope, resources, authorizationDetails);
}
return new OpenIDVCITokenRequest(uri, new ClientID(clientIDString), grantType, preAuthorizedCode, code, txCode,
- codeVerifier, authorizationDetails);
+ codeVerifier, scope, resources, authorizationDetails);
+ }
+// Checkstyle: CyclomaticComplexity|MethodLength|ReturnCount ON
+
+ /**
+ * Wrap a token request of a grant other than the authorization code and the pre-authorized code.
+ *
+ * @param request request to wrap
+ * @param authorizationDetails authorization details of the request
+ * @param httpRequest the parsed http request
+ * @return wrapped request
+ */
+ @Nonnull
+ private static OpenIDVCITokenRequest wrap(@Nonnull final TokenRequest request,
+ @Nullable final List<OpenIDVCIAuthorizationDetail> authorizationDetails,
+ @Nonnull final HTTPRequest httpRequest) {
+ final ClientAuthentication clientAuth = request.getClientAuthentication();
+ if (clientAuth != null) {
+ return new OpenIDVCITokenRequest(request.getEndpointURI(), clientAuth, request.getAuthorizationGrant(),
+ request.getScope(), request.getResources(), request.getCustomParameters(), authorizationDetails);
+ }
+ ClientID clientID = request.getClientID();
+ if (clientID == null) {
+ final String attested = attestedClientID(httpRequest);
+ clientID = StringUtils.isBlank(attested) ? null : new ClientID(attested);
+ }
+ return new OpenIDVCITokenRequest(request.getEndpointURI(), clientID,
+ request.getAuthorizationGrant(), request.getScope(), request.getResources(), request.getExistingGrant(),
+ request.getCustomParameters(), authorizationDetails);
+ }
+
+ /**
+ * Parse the 'resource' parameters of a request.
+ *
+ * @param params parameters of the request
+ * @return resource URIs, or null if there are none
+ * @throws ParseException if a resource is not an absolute URI without a fragment
+ */
+ @Nullable
+ private static List<URI> parseResources(@Nonnull final Map<String, List<String>> params) throws ParseException {
+ final List<String> values = params.get("resource");
+ if (values == null || values.isEmpty()) {
+ return null;
+ }
+ final List<URI> resources = new ArrayList<>();
+ for (final String value : values) {
+ final URI resource;
+ try {
+ resource = new URI(value);
+ } catch (final URISyntaxException e) {
+ throw new ParseException("Illegal resource parameter: " + value,
+ OAuth2Error.INVALID_TARGET.appendDescription(": " + value));
+ }
+ if (!resource.isAbsolute() || resource.getFragment() != null) {
+ throw new ParseException("Illegal resource parameter: " + value,
+ OAuth2Error.INVALID_TARGET.appendDescription(": " + value));
+ }
+ resources.add(resource);
+ }
+ return resources;
}
}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfiguration.java
index 4c5f834..a543ae3 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfiguration.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfiguration.java
@@ -16,103 +16,23 @@
package org.geant.shibboleth.plugin.openidvci.profile.config.impl;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import java.util.List;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.OpenIDVCITokenRequest;
import org.geant.shibboleth.plugin.openidvci.profile.config.OpenIDVCIConfiguration;
-import org.opensaml.profile.context.ProfileRequestContext;
import com.nimbusds.oauth2.sdk.GrantType;
-import net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenConfiguration;
-import net.shibboleth.shared.annotation.constraint.NonnullElements;
-import net.shibboleth.shared.annotation.constraint.NotLive;
-import net.shibboleth.shared.annotation.constraint.Unmodifiable;
-import net.shibboleth.shared.collection.CollectionSupport;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.logic.FunctionSupport;
-import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.oidc.profile.oauth2.config.impl.DefaultOAuth2TokenConfiguration;
/** Profile configuration for the Token endpoint. */
-public class DefaultOpenIDVCITokenConfiguration extends AbstractOpenIDVCIConfiguration
- implements OAuth2TokenConfiguration {
-
- /** Lookup function to supply the enabled grant types. */
- @Nonnull
- private Function<ProfileRequestContext, Set<String>> grantTypesLookupStrategy;
+public class DefaultOpenIDVCITokenConfiguration extends DefaultOAuth2TokenConfiguration {
/** Constructor. */
public DefaultOpenIDVCITokenConfiguration() {
super(OpenIDVCIConfiguration.PROFILE_ID_TOKEN);
- grantTypesLookupStrategy = FunctionSupport.constant(CollectionSupport.setOf(
- GrantType.AUTHORIZATION_CODE.getValue(), OpenIDVCITokenRequest.GRANT_TYPE_VALUE_PRE_AUTH));
- setRefreshTokensEnabled(false);
- }
-
- /** {@inheritDoc} */
- @Override
- @Nonnull
- @NonnullElements
- @NotLive
- @Unmodifiable
- public Set<String> getGrantTypes(@Nullable final ProfileRequestContext profileRequestContext) {
- final Collection<String> types = grantTypesLookupStrategy.apply(profileRequestContext);
-
- return types != null ? CollectionSupport.copyToSet(types) : CollectionSupport.emptySet();
- }
-
- /**
- * Set the enabled grant types.
- *
- * @param types enabled grant types
- */
- public void setGrantTypes(@Nonnull @NonnullElements final Collection<String> types) {
- Constraint.isNotNull(types, "Grant types cannot be null");
-
- grantTypesLookupStrategy =
- FunctionSupport.constant(Set.copyOf(StringSupport.normalizeStringCollection(types)));
- }
-
- /**
- * Set the lookup strategy for the enabled grant types.
- *
- * @param strategy lookup strategy
- */
- public void setGrantTypesLookupStrategy(@Nonnull final Function<ProfileRequestContext, Set<String>> strategy) {
- grantTypesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isEnforceRefreshTokenRotation(@Nullable final ProfileRequestContext profileRequestContext) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- @Nullable
- public BiFunction<ProfileRequestContext, Map<String, Object>, Map<String, Object>>
- getRefreshTokenClaimsSetManipulationStrategy(@Nullable final ProfileRequestContext profileRequestContext) {
- return null;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isIssueIdTokenViaRefreshToken(@Nullable final ProfileRequestContext profileRequestContext) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isLimitInitialAccessTokenToSelf(@Nullable final ProfileRequestContext profileRequestContext) {
- return false;
+ setGrantTypes(List.of(GrantType.AUTHORIZATION_CODE.getValue(), GrantType.REFRESH_TOKEN.getValue(),
+ OpenIDVCITokenRequest.GRANT_TYPE_VALUE_PRE_AUTH));
}
}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessage.java
index b7a1d18..ddd600b 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessage.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessage.java
@@ -14,6 +14,11 @@
* limitations under the License.
*/
+/*
+ * Derived from net.shibboleth.idp.plugin.oidc.op.profile.impl.FormOutboundTokenResponseMessage
+ * of the Shibboleth OpenID Connect Provider plugin, Apache License 2.0, modified by GÉANT.
+ */
+
package org.geant.shibboleth.plugin.openidvci.profile.impl;
import java.util.HashMap;
@@ -21,33 +26,52 @@ import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.AbstractOpenIDVCITokenResponseAction;
-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 org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jwt.JWT;
import com.nimbusds.oauth2.sdk.AccessTokenResponse;
+import com.nimbusds.oauth2.sdk.TokenResponse;
+import com.nimbusds.oauth2.sdk.token.AccessToken;
import com.nimbusds.oauth2.sdk.token.Tokens;
+import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
+import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
-import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.shared.primitive.LoggerFactory;
-/** Action forming the outbound token response message. */
+/**
+ * Action that forms outbound message based on token request and response context. Formed message is set to
+ * {@link ProfileRequestContext#getOutboundMessageContext()}.
+ *
+ * <p>This is both OIDC and OAuth aware, based on the presence of an ID token in the context. The authorization
+ * details of {@link TokenContext#getResponseAuthorizationDetails()} are added as 'authorization_details'.</p>
+ */
public class FormOutboundTokenResponseMessage extends AbstractOpenIDVCITokenResponseAction {
+ /** Name of the authorization details parameter. */
+ @Nonnull
+ private static final String AUTHORIZATION_DETAILS = "authorization_details";
+
/** Class logger. */
@Nonnull
- private Logger log = LoggerFactory.getLogger(FormOutboundTokenResponseMessage.class);
+ private final Logger log = LoggerFactory.getLogger(FormOutboundTokenResponseMessage.class);
+
+ /** access token for response. */
+ @Nullable
+ private AccessToken accessToken;
- /** Token context. */
- @NonnullBeforeExec
- private TokenContext tokenContext;
+ /** ID token for response. */
+ @Nullable
+ private JWT idToken;
/** {@inheritDoc} */
@Override
@@ -55,34 +79,39 @@ public class FormOutboundTokenResponseMessage extends AbstractOpenIDVCITokenResp
if (!super.doPreExecute(profileRequestContext)) {
return false;
}
-
- tokenContext = profileRequestContext.getInboundMessageContext().getSubcontext(TokenContext.class);
- if (tokenContext == null) {
- log.error("{} No token context", getLogPrefix());
+ final OIDCAuthenticationResponseContext oidcResponseContext = getOidcResponseContext();
+ assert oidcResponseContext != null;
+ accessToken = oidcResponseContext.getAccessToken();
+ if (accessToken == null) {
+ log.error("{} unable to provide required access token", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
return false;
}
+ idToken = oidcResponseContext.getProcessedToken();
return true;
}
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- if (profileRequestContext.getInboundMessageContext() == null
- || !(profileRequestContext.getInboundMessageContext().getMessage() instanceof OpenIDVCITokenRequest)) {
- log.error("{} no inbound OpenIDVCITokenRequest available ", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return;
- }
- Map<String, Object> params = null;
- if (tokenContext.getResponseAuthorizationDetails() != null) {
- params = new HashMap<>();
- params.put("authorization_details", new ObjectMapper()
- .convertValue(tokenContext.getResponseAuthorizationDetails(), new TypeReference<List<Object>>() {
+ final OIDCAuthenticationResponseContext oidcResponseContext = getOidcResponseContext();
+ assert oidcResponseContext != null;
+ final Map<String, Object> params = new HashMap<>();
+ final TokenContext tokenContext = profileRequestContext.ensureInboundMessageContext()
+ .getSubcontext(TokenContext.class);
+ if (tokenContext != null && tokenContext.getResponseAuthorizationDetails() != null) {
+ params.put(AUTHORIZATION_DETAILS, new ObjectMapper().convertValue(
+ tokenContext.getResponseAuthorizationDetails(), new TypeReference<List<Object>>() {
}));
}
- profileRequestContext.ensureOutboundMessageContext().setMessage(
- new AccessTokenResponse(new Tokens(getOidcResponseContext().getAccessToken(), null), params));
- return;
+ final TokenResponse resp;
+ if (idToken != null) {
+ resp = new OIDCTokenResponse(
+ new OIDCTokens(idToken, accessToken, oidcResponseContext.getRefreshToken()), params);
+ } else {
+ resp = new AccessTokenResponse(new Tokens(accessToken, oidcResponseContext.getRefreshToken()), params);
+ }
+ profileRequestContext.ensureOutboundMessageContext().setMessage(resp);
}
-}
\ No newline at end of file
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/InitializePotentialCredentials.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/InitializePotentialCredentials.java
new file mode 100644
index 0000000..2389b72
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/InitializePotentialCredentials.java
@@ -0,0 +1,65 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
+import org.opensaml.profile.action.AbstractProfileAction;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Action that sets an empty claims set to {@link TokenContext#setPotentialCredentials(ClaimsSet)}.
+ *
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_MSG_CTX}
+ */
+public class InitializePotentialCredentials extends AbstractProfileAction {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(InitializePotentialCredentials.class);
+
+ /** {@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_MSG_CTX);
+ return false;
+ }
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ profileRequestContext.ensureInboundMessageContext().ensureSubcontext(TokenContext.class)
+ .setPotentialCredentials(new ClaimsSet());
+ }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContext.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContext.java
index 5e24716..53d5e1e 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContext.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContext.java
@@ -16,39 +16,95 @@
package org.geant.shibboleth.plugin.openidvci.profile.impl;
+import java.util.function.Function;
+
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
import org.geant.shibboleth.plugin.openidvci.messaging.impl.AbstractOpenIDVCITokenResponseAction;
+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.profile.IdPEventIds;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * Action that adds the audience of the Credential endpoint to {@link OIDCAuthenticationResponseContext}.
+ * Action that adds the Credential Issuer Identifier to the audience in {@link OIDCAuthenticationResponseContext}
+ * when {@link TokenContext#getPotentialCredentials()} is not empty.
*
* @event {@link EventIds#PROCEED_EVENT_ID}
* @event {@link EventIds#INVALID_MSG_CTX}
+ * @event {@link IdPEventIds#INVALID_PROFILE_CONFIG}
*/
public class SetCredentialsAudienceToResponseContext extends AbstractOpenIDVCITokenResponseAction {
- /** Audience of the Credential endpoint. */
- @Nonnull
- public static final String AUDIENCE = "credentials";
-
/** Class logger. */
@Nonnull
private Logger log = LoggerFactory.getLogger(SetCredentialsAudienceToResponseContext.class);
+ /** Strategy used to locate the Credential Issuer Identifier. */
+ @Nullable
+ private Function<ProfileRequestContext, String> audienceLookupStrategy;
+
+ /** Credential Issuer Identifier of the request. */
+ @Nullable
+ private String audience;
+
+ /**
+ * Set the strategy used to locate the Credential Issuer Identifier.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAudienceLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+ checkSetterPreconditions();
+ audienceLookupStrategy = Constraint.isNotNull(strategy, "Audience lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+ if (audienceLookupStrategy == null) {
+ throw new ComponentInitializationException("Audience lookup strategy cannot be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+ final TokenContext tokenContext = profileRequestContext.ensureInboundMessageContext()
+ .getSubcontext(TokenContext.class);
+ if (tokenContext == null || tokenContext.getPotentialCredentials() == null
+ || tokenContext.getPotentialCredentials().toJSONObject().isEmpty()) {
+ log.debug("{} No potential credentials, nothing to do", getLogPrefix());
+ return false;
+ }
+ assert audienceLookupStrategy != null;
+ audience = audienceLookupStrategy.apply(profileRequestContext);
+ if (audience == null) {
+ log.error("{} No Credential Issuer Identifier", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+ return false;
+ }
+ return true;
+ }
+
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final OIDCAuthenticationResponseContext oidcResponseContext = getOidcResponseContext();
assert oidcResponseContext != null;
- if (!oidcResponseContext.getAudience().contains(AUDIENCE)) {
- oidcResponseContext.getAudience().add(AUDIENCE);
+ if (!oidcResponseContext.getAudience().contains(audience)) {
+ oidcResponseContext.getAudience().add(audience);
}
log.debug("{} Access token audience {}", getLogPrefix(), oidcResponseContext.getAudience());
}
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/UnwrapPreAuthorizedCode.java
similarity index 70%
rename from openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/UnwrapGrant.java
rename to openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/UnwrapPreAuthorizedCode.java
index 00476d4..4eff8c4 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/UnwrapPreAuthorizedCode.java
@@ -42,14 +42,10 @@ import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
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;
@@ -62,37 +58,23 @@ import net.shibboleth.shared.security.DataSealer;
import net.shibboleth.shared.security.DataSealerException;
/**
- * Action that unwraps an authorization grant or pre-authorized grant.
+ * Action that unwraps a pre-authorized grant.
*
* <p>
- * Operation is valid if it is successfully unwrapped, parsed as a code or
- * 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
- * {@link OIDCAuthenticationResponseContext#setAuthorizationGrantClaimsSet(TokenClaimsSet)}.
- * </p>
- *
- * <p>
- * The credential offer object from pre-authorised grant is stored to response
- * context via {@link TokenContext#setCredentialOfferObject}.
+ * Operation is valid if it is successfully unwrapped, parsed as a pre-authorized
+ * code and is unexpired. Pre-authorized grant may also be located from storage.
* </p>
*
* <p>
- * The potential credentials from pre-authorised grant is stored to response
- * context via {@link TokenContext#setPotentialCredentials}.
+ * The credential offer object and the potential credentials of the grant are
+ * stored to {@link TokenContext}.
* </p>
- *
*/
-public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
+public class UnwrapPreAuthorizedCode extends AbstractOpenIDVCITokenResponseAction {
/** Class logger. */
@Nonnull
- private Logger log = LoggerFactory.getLogger(UnwrapGrant.class);
+ private Logger log = LoggerFactory.getLogger(UnwrapPreAuthorizedCode.class);
/** Data sealer for unwrapping authorization code. */
@Nonnull
@@ -111,7 +93,7 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
*
* @param sealer sealer to decrypt/hmac authorize code.
*/
- public UnwrapGrant(@Nonnull @ParameterName(name = "sealer") final DataSealer sealer) {
+ public UnwrapPreAuthorizedCode(@Nonnull @ParameterName(name = "sealer") final DataSealer sealer) {
dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
final APIRequestClientIDLookupFunction lookup = new APIRequestClientIDLookupFunction();
lookup.setDataSealer(sealer);
@@ -154,40 +136,7 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final AuthorizationGrant grant = getTokenRequest().getAuthorizationGrant();
log.debug("{} Unwrapping grant type: {}", getLogPrefix(), grant.getType());
- if (GrantType.AUTHORIZATION_CODE.equals(grant.getType())) {
- TokenClaimsSet tokenClaimsSet = null;
- 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, true);
- final OIDCAuthenticationResponseContext oidcResponseContext = getOidcResponseContext();
- assert oidcResponseContext != null;
- oidcResponseContext.setAuthorizationGrantClaimsSet(tokenClaimsSet);
- final TokenContext tokenContext = profileRequestContext.getInboundMessageContext()
- .ensureSubcontext(TokenContext.class);
- tokenContext.setPotentialCredentials(tokenClaimsSet.getUserinfoDeliveryClaims());
- return;
- } else if (PreAuthorizedCodeGrant.GRANT_TYPE.equals(grant.getType())) {
+ if (PreAuthorizedCodeGrant.GRANT_TYPE.equals(grant.getType())) {
final String code = getOpenIDVCITokenRequest().getPreAuthorizedCode();
log.info("{} Unwrapping pre-authorization code", getLogPrefix());
final Exception e;
@@ -201,7 +150,7 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
return;
}
log.debug("{} pre-authorized grant unwrapped {}", getLogPrefix(), credentialOffer.serialize());
- validateTokenClaimsSet(profileRequestContext, credentialOffer, false);
+ validateTokenClaimsSet(profileRequestContext, credentialOffer);
final TokenContext tokenContext = profileRequestContext.getInboundMessageContext()
.ensureSubcontext(TokenContext.class);
tokenContext.setCredentialOfferObject(CredentialOfferObject.parse(credentialOffer.getSubject()));
@@ -252,10 +201,9 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
*
* @param profileRequestContext profile request context
* @param tokenClaimsSet claims of the unwrapped grant
- * @param clientMatch whether the grant was issued to this client
*/
private void validateTokenClaimsSet(@Nonnull final ProfileRequestContext profileRequestContext,
- final TokenClaimsSet tokenClaimsSet, final boolean clientMatch) {
+ final TokenClaimsSet tokenClaimsSet) {
if (tokenClaimsSet == null) {
log.warn("{} Grant type not supported", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
@@ -264,20 +212,6 @@ public class UnwrapGrant extends AbstractOpenIDVCITokenResponseAction {
if (!tokenClaimsSet.isTimeValid()) {
log.warn("{} Token is expired or not yet valid", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
- return;
- }
- if (!clientMatch) {
- // pre-authorized grants are for any.
- return;
- }
- final ClientID clientId = tokenClaimsSet.getClientID();
- assert clientId != null;
- final ClientID requestClientId = clientIDLookupStrategy.apply(profileRequestContext);
- if (!clientId.equals(requestClientId)) {
- log.warn("{} Token issued to client {}, invalid for {}", getLogPrefix(), clientId.getValue(),
- requestClientId);
- ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
- return;
}
}
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/did/document/document-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/did/document/document-beans.xml
index 2fb61f1..df29dce 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/did/document/document-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/did/document/document-beans.xml
@@ -19,12 +19,12 @@
<bean id="InitializeUnverifiedRelyingPartyContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext" scope="prototype" />
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundDidDocumentResponseMessage"
scope="prototype"
p:deploymentIssuer="#{getObject('shibboleth.oidc.issuer')}" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="500" p:defaultCode="server_error"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-beans.xml
index 9462320..88c9752 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-beans.xml
@@ -22,14 +22,14 @@
<bean id="InitializeUnverifiedRelyingPartyContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext" scope="prototype" />
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundMetadataDocumentResponseMessage"
scope="prototype"
p:metadataResolver-ref="#{'%{openidvci.authorizationServer.resolver:openidvci.DefaultAuthorizationServerMetadataResolver}'.trim()}"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
p:cacheControl="%{openidvci.authorizationServer.cacheControl:max-age=3600}" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="500" p:defaultCode="server_error"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/jwt-vc-issuer/jwt-vc-issuer-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/jwt-vc-issuer/jwt-vc-issuer-beans.xml
index 1499d35..34ed1ae 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/jwt-vc-issuer/jwt-vc-issuer-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/jwt-vc-issuer/jwt-vc-issuer-beans.xml
@@ -22,14 +22,14 @@
<bean id="InitializeUnverifiedRelyingPartyContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext" scope="prototype" />
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundMetadataDocumentResponseMessage"
scope="prototype"
p:metadataResolver-ref="#{'%{openidvci.jwtVcIssuer.resolver:openidvci.DefaultJWTVCIssuerMetadataResolver}'.trim()}"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
p:cacheControl="%{openidvci.jwtVcIssuer.cacheControl:max-age=3600}" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="500" p:defaultCode="server_error"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/assignments/assignments-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/assignments/assignments-beans.xml
index 6fa0fc2..29afba5 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/assignments/assignments-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/assignments/assignments-beans.xml
@@ -16,7 +16,7 @@
<bean id="openidvci.loggingId" class="java.lang.String"
c:_0="%{openidvci.logging.status-list.assignments:OAuth.StatusList.Assignments}"/>
- <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <bean id="OpenIDVCIDecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.statuslist.decoding.impl.StatusListAssignmentsRequestDecoder"
scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
@@ -37,12 +37,12 @@
p:retention="%{openidvci.status-list.assignment.retention:P7D}"
p:storage-ref="#{'%{openidvci.status-list.assignment.StorageService:shibboleth.StorageService}'.trim()}" />
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.statuslist.profile.impl.FormOutboundStatusListAssignmentsResponseMessage"
scope="prototype"
p:statusListAssignmentStore-ref="openidvci.status-list.AssignmentStore" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="400" p:defaultCode="invalid_request"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/list/list-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/list/list-beans.xml
index 4813571..5927f0b 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/list/list-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/list/list-beans.xml
@@ -66,7 +66,7 @@
</property>
</bean>
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.statuslist.profile.impl.FormOutboundStatusListResponseMessage"
scope="prototype" />
@@ -92,7 +92,7 @@
scope="prototype" init-method=""
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="400" p:defaultCode="invalid_request"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/revoke/revoke-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/revoke/revoke-beans.xml
index d9cfcc0..a845a06 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/revoke/revoke-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/status-list/revoke/revoke-beans.xml
@@ -16,7 +16,7 @@
<bean id="openidvci.loggingId" class="java.lang.String"
c:_0="%{openidvci.logging.status-list.revoke:OAuth.StatusList.Revoke}"/>
- <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <bean id="OpenIDVCIDecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.statuslist.decoding.impl.StatusListRevokeRequestDecoder"
scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
@@ -41,11 +41,11 @@
scope="prototype"
p:statusListStore-ref="openidvci.status-list.Store" />
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.statuslist.profile.impl.FormOutboundStatusListRevokeResponseMessage"
scope="prototype" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="400" p:defaultCode="invalid_request"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-flow.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-flow.xml
index 30fa6eb..8d0410e 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-flow.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-flow.xml
@@ -9,7 +9,7 @@
<on-entry>
<evaluate expression="flowRequestContext.getFlowScope().get('transitionAfterDecode') != null ? flowRequestContext.getFlowScope().get('transitionAfterDecode') : 'DoMetadataLookup'" result="flowScope.transitionTarget"/>
</on-entry>
- <evaluate expression="DecodeMessage"/>
+ <evaluate expression="OpenIDVCIDecodeMessage"/>
<evaluate expression="PostDecodePopulateAuditContext"/>
<evaluate expression="'proceed'" />
<transition on="proceed" to="#{transitionTarget}" />
@@ -53,7 +53,7 @@
</subflow-state>
<action-state id="BuildResponseMessage">
- <evaluate expression="FormOutboundMessage"/>
+ <evaluate expression="OpenIDVCIFormOutboundMessage"/>
<evaluate expression="'proceed'"/>
<transition on="proceed" to="PopulateOutboundInterceptContext"/>
</action-state>
@@ -63,7 +63,7 @@
<evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.profile.context.SpringRequestContext)).setRequestContext(flowRequestContext)"/>
<evaluate expression="LogEvent"/>
</on-entry>
- <evaluate expression="BuildErrorResponseFromEvent"/>
+ <evaluate expression="OpenIDVCIBuildErrorResponseFromEvent"/>
<evaluate expression="'proceed'"/>
<transition on="proceed" to="PopulateOutboundInterceptContext"/>
</action-state>
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 bb6f225..cf060cf 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
@@ -15,7 +15,7 @@
<bean id="openidvci.loggingId" class="java.lang.String"
c:_0="%{openidvci.logging.credential-offer:OpenID.VCI.CredentialOffer}"/>
- <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <bean id="OpenIDVCIDecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.CredentialOfferRequestDecoder"
scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"/>
@@ -33,11 +33,11 @@
scope="prototype" p:credentialOfferCache-ref="openidvci.CredentialOfferCache"
c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"/>
- <bean id="FormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundCredentialOfferResponseMessage"
+ <bean id="OpenIDVCIFormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundCredentialOfferResponseMessage"
p:issuerLookupStrategy-ref="shibboleth.ResponderIdLookup.Simple"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" scope="prototype"/>
- <bean id="BuildErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent"
class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent" scope="prototype"
p:defaultStatusCode="400" p:defaultCode="invalid_request"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
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 96d494a..aeed6a9 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
@@ -15,7 +15,7 @@
<bean id="openidvci.loggingId" class="java.lang.String"
c:_0="%{openidvci.logging.credentials:OpenID.VCI.Credentials}"/>
- <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <bean id="OpenIDVCIDecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
<bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCICredentialsRequestDecoder"
scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
@@ -191,7 +191,7 @@
</property>
</bean>
- <bean id="FormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundCredentialsResponseMessage"
+ <bean id="OpenIDVCIFormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundCredentialsResponseMessage"
scope="prototype" />
<!-- Error vocabulary of the Credential Endpoint, OpenID4VCI 1.0 section 8.4. -->
@@ -229,7 +229,7 @@
</property>
</bean>
- <bean id="BuildErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.BuildCredentialErrorResponseFromEvent" scope="prototype"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
p:mappedErrors="#{getObject('openidvci.credentials.MappedErrors')}"
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/issuer-metadata/issuer-metadata-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/issuer-metadata/issuer-metadata-beans.xml
index d95603b..bc3d407 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/issuer-metadata/issuer-metadata-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/issuer-metadata/issuer-metadata-beans.xml
@@ -38,14 +38,14 @@
</property>
</bean>
- <bean id="FormOutboundMessage"
+ <bean id="OpenIDVCIFormOutboundMessage"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundIssuerMetadataResponseMessage"
scope="prototype"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
p:metadataResolver-ref="#{'%{openidvci.issuerMetadata.resolver:openidvci.DefaultCredentialIssuerMetadataResolver}'.trim()}"
p:signedMetadataLifetime="#{'%{openidvci.issuerMetadata.signedLifetime:}'.trim().isEmpty() ? null : T(java.time.Duration).parse('%{openidvci.issuerMetadata.signedLifetime:}'.trim())}" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="500" p:defaultCode="server_error"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
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
index f9a9562..5dbf64e 100644
--- 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
@@ -21,10 +21,10 @@
<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"
+ <bean id="OpenIDVCIFormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundNonceResponseMessage"
scope="prototype" p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
- <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
scope="prototype" p:defaultStatusCode="500" p:defaultCode="server_error"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
<property name="eventContextLookupStrategy">
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 f597646..36bce61 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,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Derived from META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
- of the Shibboleth OpenID Connect Provider plugin, Apache License 2.0, modified by GÉANT.
+ Beans of the token flow. The beans of META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
+ of the Shibboleth OpenID Connect Provider plugin are imported; this file has the beans of this
+ plugin. Bean definitions derived from that file, Apache License 2.0, modified by GÉANT.
-->
<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"
@@ -11,393 +12,98 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize" default-destroy-method="destroy">
- <!-- REPLACED shibboleth.oidc.profileId, legacyProfileId and loggingId. -->
+ <import resource="classpath:/META-INF/net/shibboleth/idp/flows/oidc/abstract-api/oidc-abstract-api-beans.xml" />
+ <import resource="classpath:/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml" />
+
+ <!-- Beans named by openid/vci/abstract-api. -->
+
<bean id="openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/token"/>
<bean id="openidvci.loggingId" class="java.lang.String"
c:_0="%{openidvci.logging.token:OpenID.VCI.Token}"/>
- <bean id="shibboleth.oidc.MetadataEnforcedDPoP" parent="shibboleth.Conditions.Expression"
- c:expression="#input.ensureInboundMessageContext().getSubcontext(T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext)) != null and #input.ensureInboundMessageContext().getSubcontext(T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext)).getClientInformation() != null and #input.ensureInboundMessageContext().getSubcontext(T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext)).getClientInformation().getMetadata().toJSONObject().get('dpop_bound_access_tokens') != [...]
-
- <util:constant id="shibboleth.metrics.ProfileCounter"
- static-field="net.shibboleth.oidc.profile.oauth2.config.impl.DefaultOAuth2TokenConfiguration.PROFILE_COUNTER" />
-
- <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+ <!-- In place of DecodeMessage, with OpenIDVCITokenRequestDecoder in place of OIDCTokenRequestDecoder. -->
+ <bean id="OpenIDVCIDecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
<constructor-arg>
- <!-- REPLACED OIDCTokenRequestDecoder. -->
<bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCITokenRequestDecoder"
- scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
+ scope="prototype" p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
+ p:removeIpAddressFromEndpointUri="%{idp.oidc.logging.removeIpAddressFromProtocolMessage:false}"
+ p:customRequestParser="#{getObject('%{openidvci.requestParser.TokenRequest:}'.trim())}" />
</constructor-arg>
</bean>
- <!-- REPLACED TokenRequestClientIDLookupFunction. -->
- <bean id="shibboleth.ClientIDLookupStrategy" class="org.geant.shibboleth.plugin.openidvci.profile.context.navigate.APIRequestClientIDLookupFunction"
- p:credentialOfferCache-ref="openidvci.CredentialOfferCache"
- p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}" />
-
- <bean id="openidvci.ProfileRequestClientIDLookupStrategy" parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.ClientIDLookupStrategy"
- c:f-ref="shibboleth.MessageContextLookup.Inbound" />
-
- <!-- REPLACED UnwrapGrant. -->
- <bean id="OpenIDVCIUnwrapGrant" class="org.geant.shibboleth.plugin.openidvci.profile.impl.UnwrapGrant" scope="prototype"
- c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
- p:clientIDLookupStrategy-ref="openidvci.ProfileRequestClientIDLookupStrategy"
- p:credentialOfferCache-ref="openidvci.CredentialOfferCache"/>
-
- <bean id="ResolveAttributesForClientPredicate"
- class="net.shibboleth.profile.config.logic.ResolveAttributesPredicate" />
+ <!-- In place of FormOutboundMessage. -->
+ <bean id="OpenIDVCIFormOutboundMessage"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundTokenResponseMessage" scope="prototype" />
- <bean id="ResolveAttributesForAudiencePredicate"
- class="net.shibboleth.profile.config.logic.ResolveAttributesPredicate"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
-
- <bean id="InitializeOutboundMessageContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeOutboundResponseMessageContext"
- scope="prototype" />
-
- <bean id="ValidateClientIDAgainstPolicy"
- class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateClientIDAgainstPolicy"
- p:clientIDLookupStrategy-ref="shibboleth.ClientIDLookupStrategy"
- scope="prototype"
- p:unregisteredClientPolicyEnforcer="#{getObject('shibboleth.oidc.UnregisteredClientPolicyEnforcer') ?: getObject('shibboleth.oidc.DefaultUnregisteredClientPolicyEnforcer')}"/>
-
- <bean id="ValidateGrantType" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateGrantType"
- scope="prototype" />
-
- <!-- Condition signaling that request was NOT for client_credentials grant. -->
- <bean id="NotClientCredentialsGrantCondition" parent="shibboleth.Conditions.NOT">
- <constructor-arg>
- <bean class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
- p:grantTypes="#{T(com.nimbusds.oauth2.sdk.GrantType).CLIENT_CREDENTIALS}" />
- </constructor-arg>
- </bean>
-
- <!-- Condition signaling that request was for authorizaton_code grant. -->
- <bean id="AuthorizationCodeGrantCondition"
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
- p:grantTypes="#{T(com.nimbusds.oauth2.sdk.GrantType).AUTHORIZATION_CODE}" />
-
- <!-- Condition signaling that request was for refresh_token grant. -->
- <bean id="RefreshTokenGrantCondition"
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
- p:grantTypes="#{T(com.nimbusds.oauth2.sdk.GrantType).REFRESH_TOKEN}" />
-
- <!-- Traditional third-party grant handling. -->
-
- <bean id="ValidateGrant" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateGrant" scope="prototype"
- p:replayCache-ref="shibboleth.ReplayCache"
- p:revocationCache-ref="shibboleth.oidc.RevocationCache"
- p:tokenRevocationCondition="#{getObject('%{idp.oauth2.revocationCondition:shibboleth.BiConditions.FALSE}')}">
- <property name="chainRevocationLifetimeLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultChainRevocationLifetimeLookupStrategy"
- p:clockSkew="%{idp.policy.clockSkew:PT5M}" p:useActiveProfileOnly="false" />
+ <!-- In place of BuildErrorResponseFromEvent, with the error map of this plugin. -->
+ <bean id="OpenIDVCIBuildErrorResponseFromEvent"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.BuildTokenErrorResponseFromEvent" scope="prototype"
+ p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+ p:mappedErrors="#{getObject('shibboleth.oidc.token.MappedErrors') ?: getObject('openidvci.token.MappedErrors')}">
+ <property name="eventContextLookupStrategy">
+ <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
</property>
</bean>
- <!-- REPLACED WIRING. Code verifier lookup of this plugin. -->
- <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="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateRedirectURI"
- scope="prototype"
- p:activationCondition-ref="AuthorizationCodeGrantCondition"
- p:redirectURILookupStrategy-ref="shibboleth.TokenRequestRedirectURILookupStrategy"
- p:validRedirectURIsLookupStrategy-ref="shibboleth.TokenRequestValidRequestUrisLookupStrategy"
- p:requireRequestedValue="false"
- p:unregisteredClientPolicyEnforcer="#{getObject('shibboleth.oidc.UnregisteredClientPolicyEnforcer') ?: getObject('shibboleth.oidc.DefaultUnregisteredClientPolicyEnforcer')}"/>
-
- <bean id="shibboleth.TokenRequestRedirectURILookupStrategy"
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.TokenRequestRedirectURILookupFunction" />
-
- <bean id="shibboleth.TokenRequestValidRequestUrisLookupStrategy"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestValidRequestURIsLookupFunction" />
-
- <bean id="SetRequestedClaimsToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedClaimsToResponseContext" scope="prototype"
- p:requestedClaimsLookupStrategy-ref="shibboleth.TokenRequestRequestedClaimsLookupFunction"
- p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
-
- <bean id="shibboleth.TokenRequestRequestedClaimsLookupFunction"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestRequestedClaimsLookupFunction" />
-
- <bean id="SetAuthenticationContextClassReferenceFromAuthzCodeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationContextClassReferenceFromAuthzCodeToResponseContext"
- scope="prototype" />
-
- <bean id="SetAuthenticationTimeFromAuthzCodeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationTimeToResponseContext" scope="prototype"
- p:authTimeLookupStrategy-ref="shibboleth.TokenRequestAuthTimeLookupFunction" />
-
- <bean id="shibboleth.TokenRequestAuthTimeLookupFunction"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestAuthTimeLookupFunction" />
-
- <bean id="SetTokenDeliveryAttributesFromTokenToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetTokenDeliveryAttributesFromTokenToResponseContext"
- scope="prototype" />
-
- <bean id="SetConsentToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetConsentFromTokenToResponseContext" scope="prototype" />
+ <bean id="InitializeAuthenticationContext"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.InitializeAuthenticationContext" scope="prototype" />
- <bean id="InitializeSubjectContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeSubjectContext" scope="prototype" />
-
- <bean id="SetSubjectFromAuthzCodeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSubjectToResponseContext" scope="prototype" />
-
- <bean id="SetSectorIdentifierForAttributeResolution"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSectorIdentifierForAttributeResolution" scope="prototype" />
-
- <!-- client_credentials grant handling. -->
-
- <bean id="SetAuthenticationContextClassReferenceToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationContextClassReferenceToResponseContext"
- scope="prototype" />
-
- <bean id="SetAuthenticationTimeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetAuthenticationTimeToResponseContext" scope="prototype" />
+ <!--
+ REPLACED, KEEPING THE BEAN ID.
+ APIRequestClientIDLookupFunction in place of TokenRequestClientIDLookupFunction.
+ -->
+ <bean id="shibboleth.ClientIDLookupStrategy"
+ class="org.geant.shibboleth.plugin.openidvci.profile.context.navigate.APIRequestClientIDLookupFunction"
+ p:credentialOfferCache-ref="openidvci.CredentialOfferCache"
+ p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}" />
- <bean id="SetSubjectFromSubjectContextToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSubjectToResponseContext" scope="prototype">
- <property name="subjectLookupStrategy">
- <bean parent="shibboleth.Functions.Compose">
- <constructor-arg>
- <bean class="net.shibboleth.idp.authn.context.navigate.SubjectContextPrincipalLookupFunction" />
- </constructor-arg>
- <constructor-arg>
- <ref bean="shibboleth.ChildLookup.SubjectContext"/>
- </constructor-arg>
- </bean>
- </property>
- </bean>
+ <!-- Beans of this flow in place of beans of oidc/token. -->
- <bean id="SetSessionIdToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSessionIdToResponseContext" scope="prototype"
- p:sessionIdLookupStrategy-ref="SessionIdGenerationStrategy" />
-
- <bean id="SetSessionIdFromAuthzCodeToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetSessionIdToResponseContext" scope="prototype" />
-
- <!-- Common grant handling. -->
-
- <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateScope" scope="prototype"
- p:requestedScopeLookupStrategy-ref="TokenRequestScopeLookupStrategy"
- p:allowedScopeLookupStrategy="#{getObject('shibboleth.oidc.AllowedScopeStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedScopeStrategy')}" />
-
- <bean id="ValidateAudience"
- class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateAudience" scope="prototype"
- p:allowedAudienceLookupStrategy="#{getObject('shibboleth.oidc.AllowedAudienceStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedAudienceStrategy')}">
- <property name="selfAudienceCondition">
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <ref bean="BuildOIDCTokensCondition" />
- <ref bean="NotClientCredentialsGrantCondition" />
- </list>
- </constructor-arg>
- </bean>
+ <!-- In place of UnwrapGrant, with the client id lookup of this plugin and not for the pre-authorized code. -->
+ <bean id="OpenIDVCIUnwrapGrant" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.UnwrapGrant"
+ scope="prototype"
+ c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
+ p:refreshTokenDeserializers-ref="#{'%{idp.oauth2.refreshToken.deserializers:shibboleth.oidc.DefaultRefreshTokenDeserializers}'.trim()}"
+ p:clientIDLookupStrategy-ref="shibboleth.ClientIDLookupStrategy">
+ <property name="activationCondition">
+ <bean parent="shibboleth.Conditions.NOT" c:_0-ref="OpenIDVCIPreAuthorizedCodeGrantCondition" />
</property>
</bean>
- <bean id="TokenRequestScopeLookupStrategy"
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.TokenRequestScopeLookupFunction" />
-
- <bean id="BuildOIDCTokensCondition"
- class="net.shibboleth.idp.plugin.oidc.op.profile.logic.IssueIDTokenCondition" />
+ <!-- In place of ValidatePKCE, with the code verifier lookup of this plugin. -->
+ <bean id="OpenIDVCIValidatePKCE" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidatePKCE"
+ scope="prototype" p:codeVerifierLookupStrategy-ref="RequestCodeVerifierLookupFunction"/>
- <bean id="IssueIDTokenCondition" parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <ref bean="BuildOIDCTokensCondition" />
- <bean parent="shibboleth.Conditions.OR">
- <constructor-arg>
- <list>
- <ref bean="AuthorizationCodeGrantCondition" />
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <ref bean="RefreshTokenGrantCondition" />
- <bean class="net.shibboleth.oidc.profile.config.logic.IssueIdTokenViaRefreshTokenPredicate" />
- </list>
- </constructor-arg>
- </bean>
- </list>
- </constructor-arg>
- </bean>
- </list>
- </constructor-arg>
- </bean>
+ <bean id="RequestCodeVerifierLookupFunction"
+ class="org.geant.shibboleth.plugin.openidvci.messaging.context.navigate.RequestCodeVerifierLookupFunction" />
<!--
- Do a metadata lookup for the primary audience of the token for encryption purposes.
- Contexts are stored under the outbound MessageContext, including the new RelyingPartyContext.
+ In place of ValidateGrant in TraditionalGrantProcessing, with the client instance key condition of this plugin
+ added to the token revocation condition.
-->
-
- <bean id="AudienceOIDCMetadataLookup" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
- scope="prototype" c:executionDirection="OUTBOUND">
- <constructor-arg name="messageHandler">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.impl.OIDCMetadataLookupHandler" scope="prototype">
- <property name="clientInformationResolver">
- <ref bean="shibboleth.ClientInformationResolver" />
- </property>
- <property name="clientIDLookupStrategy">
- <ref bean="AudienceClientIDLookupStrategy" />
- </property>
- </bean>
- </constructor-arg>
- </bean>
-
- <bean id="AudienceClientIDLookupStrategy"
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.AudienceClientIDLookupFunction" />
-
- <bean id="InitializeAudienceRelyingPartyContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeRelyingPartyContext" scope="prototype"
- p:relyingPartyContextCreationStrategy-ref="AudienceRelyingPartyCreationStrategy"
- p:oidcMetadataContextLookupStrategy-ref="LookupOutboundOIDCMetadataContext"
- p:clientIDLookupStrategy-ref="AudienceClientIDLookupStrategy"
- p:inbound="false" />
-
- <bean id="LookupOutboundOIDCMetadataContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCMetadataContextLookupFunction"
- p:inbound="false" />
-
- <bean id="AudienceRelyingPartyCreationStrategy" parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.ChildLookupOrCreate.RelyingPartyContext"
- c:f-ref="shibboleth.MessageContextLookup.Outbound" />
-
- <bean id="AudienceSAMLProtocolAndRole"
- class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
- c:executionDirection="OUTBOUND"
- p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
- <constructor-arg name="messageHandler">
- <bean class="org.opensaml.saml.common.binding.impl.SAMLProtocolAndRoleHandler" scope="prototype"
- p:protocol="http://openid.net/specs/openid-connect-core-1_0.html"
- p:role-ref="shibboleth.MetadataLookup.Role"
- p:entityContextClass="org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext"/>
- </constructor-arg>
- </bean>
-
- <bean id="SetAudienceEntityIdToSAMLPeerEntityContext"
- class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
- c:executionDirection="OUTBOUND"
- p:errorEvent="#{T(org.opensaml.profile.action.EventIds).INVALID_MSG_CTX}"
- p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
- <constructor-arg name="messageHandler">
- <bean class="net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.impl.SetEntityIdToSAMLPeerEntityContext"
- scope="prototype"
- p:clientIDLookupStrategy-ref="AudienceClientIDLookupStrategy"
- p:entityContextClass="org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext" />
- </constructor-arg>
- </bean>
-
- <bean id="AudienceSAMLMetadataLookup"
- class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
- c:executionDirection="OUTBOUND"
- p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
- <constructor-arg name="messageHandler">
- <bean class="org.opensaml.saml.common.binding.impl.SAMLMetadataLookupHandler" scope="prototype"
- p:entityContextClass="org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext">
- <property name="roleDescriptorResolver">
- <bean class="org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver"
- c:mdResolver-ref="shibboleth.MetadataResolver" />
- </property>
- </bean>
- </constructor-arg>
- </bean>
-
- <bean id="PopulateAudienceOIDCMetadataContext"
- class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
- c:executionDirection="OUTBOUND"
- p:activationCondition-ref="%{idp.oidc.metadata.saml:shibboleth.Conditions.TRUE}">
- <constructor-arg name="messageHandler">
- <bean class="net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.impl.PopulateOIDCMetadataContext"
- scope="prototype" />
- </constructor-arg>
- </bean>
-
- <bean id="InitializeAudienceRelyingPartyContextFromSAMLPeer"
- class="net.shibboleth.idp.saml.profile.impl.InitializeRelyingPartyContextFromSAMLPeer" scope="prototype"
- p:relyingPartyContextCreationStrategy-ref="AudienceRelyingPartyCreationStrategy"
- p:peerEntityContextLookupStrategy-ref="LookupOutboundPeerEntityContext" />
-
- <bean id="LookupOutboundPeerEntityContext" parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.ChildLookup.SAMLPeerEntityContext"
- c:f-ref="shibboleth.MessageContextLookup.Outbound"/>
-
- <bean id="SelectAudienceRelyingPartyConfiguration"
- class="net.shibboleth.idp.profile.impl.SelectRelyingPartyConfiguration" scope="prototype"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy"
- p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyResolverService" />
-
- <bean id="SelectAudienceProfileConfiguration"
- class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy"
- p:profileId="#{T(net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenAudienceConfiguration).PROFILE_ID}" />
-
- <bean id="ResolveAttributesForAudience" class="net.shibboleth.idp.profile.impl.ResolveAttributes" scope="prototype"
- c:resolverService-ref="shibboleth.AttributeResolverService"
- p:maskFailures="%{idp.service.attribute.resolver.maskFailures:true}"
- p:issuerLookupStrategy-ref="AudienceIssuerLookupFunction" />
-
- <bean id="FilterAttributesForAudience" class="net.shibboleth.idp.profile.impl.FilterAttributes" scope="prototype"
- c:filterService-ref="shibboleth.AttributeFilterService"
- p:maskFailures="%{idp.service.attribute.filter.maskFailures:true}"
- p:issuerLookupStrategy-ref="AudienceIssuerLookupFunction"
- p:proxiedRequesterContextLookupStrategy-ref="AudienceProxiedRequesterLookupFunction"
- p:proxiedRequesterMetadataContextLookupStrategy-ref="LookupOutboundSAMLEntityContext" />
-
- <bean id="AudienceIssuerLookupFunction"
- class="net.shibboleth.profile.context.navigate.IssuerLookupFunction"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
-
- <bean id="AudienceProxiedRequesterLookupFunction" parent="shibboleth.Functions.Compose">
- <constructor-arg name="g">
- <bean class="org.opensaml.messaging.context.navigate.ChildContextLookup"
- c:type="#{ T(org.opensaml.profile.context.ProxiedRequesterContext) }" />
- </constructor-arg>
- <constructor-arg name="f">
- <ref bean="shibboleth.MessageContextLookup.Outbound" />
- </constructor-arg>
- </bean>
-
- <bean id="LookupOutboundSAMLEntityContext" parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.ChildLookup.SAMLMetadataContext"
- c:f-ref="LookupOutboundPeerEntityContext"/>
-
- <!-- Back to token prep. -->
-
- <!-- OIDC response handling for access/refresh tokens. -->
-
- <bean id="PopulateUserInfoAccessTokenSignatureSigningParameters"
- class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureSigningParameters"
- scope="prototype"
- c:strategy-ref="shibboleth.MessageContextLookup.Inbound">
- <property name="configurationLookupStrategy">
- <bean lazy-init="true"
- class="net.shibboleth.oidc.profile.config.navigate.JWTSignatureSigningConfigurationLookupFunction" />
- </property>
- <property name="signatureSigningParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationSignatureSigningParametersResolver">
- <constructor-arg name="signatureAlgorithmLookupStrategy">
+ <bean id="OpenIDVCIValidateGrant" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateGrant"
+ scope="prototype"
+ p:replayCache-ref="shibboleth.ReplayCache"
+ p:revocationCache-ref="shibboleth.oidc.RevocationCache">
+ <property name="tokenRevocationCondition">
+ <bean parent="shibboleth.BiConditions.OR"
+ c:_0="#{getObject('%{idp.oauth2.revocationCondition:shibboleth.BiConditions.FALSE}')}">
+ <constructor-arg index="1">
<bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_signed_response_alg" />
+ class="org.geant.shibboleth.plugin.openidvci.profile.logic.ClientInstanceKeyRevocationCondition"
+ c:strategy-ref="openidvci.ClientInstanceKeyThumbprintLookup" />
</constructor-arg>
- <constructor-arg name="defaultAlgorithmValue" value="RS256" />
</bean>
</property>
- <property name="securityParametersContextLookupStrategy">
- <bean parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
- c:f-ref="shibboleth.ChildLookup.RelyingParty" />
+ <property name="chainRevocationLifetimeLookupStrategy">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultChainRevocationLifetimeLookupStrategy"
+ p:clockSkew="%{idp.policy.clockSkew:PT5M}" p:useActiveProfileOnly="false" />
</property>
</bean>
- <!-- REPLACED WIRING. Client id lookup of this plugin. -->
- <bean id="BuildOIDCAccessToken"
+ <!-- In place of BuildOIDCAccessToken, with the client id lookup of this plugin. -->
+ <bean id="OpenIDVCIBuildOIDCAccessToken"
class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildAccessToken" scope="prototype"
p:dataSealer="#{getObject('%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim())}"
p:xmlSafeIdentifier="%{idp.oidc.xmlSafeIdentifiers:true}"
@@ -405,469 +111,87 @@
p:clientIDLookupStrategy-ref="openidvci.ProfileRequestClientIDLookupStrategy"
p:objectMapper-ref="#{'%{idp.oidc.logging.objectMapper:shibboleth.oidc.JSONObjectMapper}'.trim()}" />
- <bean id="SignOIDCAccessToken" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
- scope="prototype" c:executionDirection="OUTBOUND">
- <constructor-arg name="messageHandler">
- <bean id="SignOIDCAccessTokenHandler"
- class="net.shibboleth.oidc.security.impl.SignJWTHandler" scope="prototype" p:logName="Access Token"
- p:typeHeader="at+jwt">
- <property name="securityParametersLookupStrategy">
- <bean parent="shibboleth.Functions.Compose">
- <constructor-arg name="g">
- <bean parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
- c:f-ref="shibboleth.ChildLookup.RelyingParty" />
- </constructor-arg>
- <constructor-arg name="f">
- <bean parent="shibboleth.Functions.Expression" c:expression="#input.getParent()" />
- </constructor-arg>
- </bean>
- </property>
- <property name="claimsToSignLookupStrategy">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.JWTClaimsSetFromJWTAccessTokenLookupFunction" />
- </property>
- <property name="jwtUpdateConsumer">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.JWTAccessTokenUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
- </bean>
-
- <bean id="SetOAuthAccessTokenToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.SetAccessTokenToResponseContext"
- scope="prototype" />
-
- <bean id="SetRefreshTokenToResponseContext"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRefreshTokenToResponseContext" scope="prototype"
- c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
- p:revocationCache-ref="shibboleth.oidc.RevocationCache"
- p:activationCondition-ref="#{'%{idp.oauth2.refreshToken.activation:DefaultRefreshTokenActivationCondition}'.trim()}"
- p:refreshTokenSerializationStrategies-ref="#{'%{idp.oauth2.refreshToken.serializationStrategies:shibboleth.oidc.DefaultRefreshTokenSerializationStrategies}'.trim()}"
- p:xmlSafeIdentifier="%{idp.oidc.xmlSafeIdentifiers:true}"
- p:identifierGeneratorLookupStrategy-ref="shibboleth.oidc.DefaultIdentifierGenerationStrategy">
- <property name="tokenRevocationLifetimeLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultTokenRevocationLifetimeLookupStrategy"
- p:clockSkew="%{idp.policy.clockSkew:PT5M}" />
- </property>
- </bean>
-
- <util:map id="shibboleth.oidc.DefaultRefreshTokenSerializationStrategies">
- <entry key="JWT">
- <bean factory-bean="DefaultJwtRefreshTokenSerializerFactory" factory-method="getBean" />
- </entry>
- </util:map>
-
- <bean id="DefaultJwtRefreshTokenSerializerFactory"
- parent="shibboleth.oidc.RefreshTokenSerializerFactory"
- c:id="DefaultJwtRefreshTokenSerializationFunction"/>
-
- <bean id="DefaultJwtRefreshTokenSerializationFunction"
- class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultJwtRefreshTokenSerializationFunction"
- scope="prototype"
- p:dataSealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
- p:objectMapper-ref="#{'%{idp.oidc.logging.objectMapper:shibboleth.oidc.JSONObjectMapper}'.trim()}">
- <property name="signingParametersHandler">
- <bean class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureSigningParametersHandler"
- scope="prototype">
- <property name="configurationLookupStrategy">
- <bean parent="shibboleth.Functions.Compose">
- <constructor-arg name="f">
- <bean class="org.opensaml.messaging.context.navigate.ParentContextLookup"
- c:type="org.opensaml.profile.context.ProfileRequestContext" />
- </constructor-arg>
- <constructor-arg name="g">
- <bean lazy-init="true"
- class="net.shibboleth.oidc.profile.config.navigate.JWTSignatureSigningConfigurationLookupFunction" />
- </constructor-arg>
- </bean>
- </property>
- <property name="signatureSigningParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationSignatureSigningParametersResolver">
- <constructor-arg name="signatureAlgorithmLookupStrategy">
- <bean class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_signed_response_alg" />
- </constructor-arg>
- <constructor-arg name="defaultAlgorithmValue" value="RS256" />
- </bean>
- </property>
- </bean>
- </property>
- <property name="audienceLookupStrategy">
- <bean parent="shibboleth.Functions.Expression"
- c:expression="#custom.get().getRequestURL().toString()"
- p:customObject-ref="shibboleth.HttpServletRequestSupplier" />
- </property>
- <property name="typeHeaderLookupStrategy">
- <bean parent="shibboleth.BiFunctions.Expression" c:expression="#null" />
- </property>
- </bean>
-
-
- <bean id="DefaultRefreshTokenActivationCondition" parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <bean class="net.shibboleth.oidc.profile.config.logic.RefreshTokensEnabledPredicate" />
- <ref bean="NotClientCredentialsGrantCondition" />
- <bean parent="shibboleth.Conditions.OR">
- <constructor-arg>
- <list>
- <bean parent="shibboleth.Conditions.NOT">
- <constructor-arg>
- <ref bean="BuildOIDCTokensCondition" />
- </constructor-arg>
- </bean>
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <ref bean="BuildOIDCTokensCondition" />
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.OfflineAccessScopeCondition" />
- </list>
- </constructor-arg>
- </bean>
- </list>
- </constructor-arg>
- </bean>
- </list>
- </constructor-arg>
- </bean>
-
- <!-- ID token actions. -->
-
- <bean id="PopulateIDTokenSignatureSigningParameters"
- class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureSigningParameters"
- scope="prototype" p:noResultIsError="true"
- c:strategy-ref="shibboleth.MessageContextLookup.Inbound">
- <property name="configurationLookupStrategy">
- <bean lazy-init="true"
- class="net.shibboleth.oidc.profile.config.navigate.JWTSignatureSigningConfigurationLookupFunction" />
- </property>
- <property name="signatureSigningParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationSignatureSigningParametersResolver">
- <constructor-arg name="signatureAlgorithmLookupStrategy">
- <bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_signed_response_alg" />
- </constructor-arg>
- <constructor-arg name="defaultAlgorithmValue" value="RS256" />
- </bean>
- </property>
- <property name="securityParametersContextLookupStrategy">
- <bean parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
- c:f-ref="shibboleth.MessageContextLookup.Outbound" />
- </property>
- </bean>
-
- <bean id="PopulateIDTokenEncryptionParameters"
- class="net.shibboleth.oidc.profile.impl.PopulateJWTEncryptionParameters" scope="prototype"
- p:forFriendlyName="ID Token">
- <property name="clientMetadataContextLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCMetadataContextLookupFunction"
- p:inbound="true" />
- </property>
- <property name="configurationLookupStrategy">
- <bean lazy-init="true"
- class="net.shibboleth.oidc.profile.config.navigate.JWTEncryptionConfigurationLookupFunction" />
- </property>
- <property name="encryptionParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.DefaultEncryptionParametersResolver">
- <property name="keyTransportEncryptionAlgorithmsLookupStrategy">
- <bean
- class="net.shibboleth.oidc.security.jose.impl.ClientInformationKeyTransportEncryptionAlgorithmsLookupStrategy">
- <constructor-arg>
- <bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_encrypted_response_alg" />
- </constructor-arg>
- </bean>
- </property>
- <property name="dataEncryptionAlgorithmsLookupStrategy">
- <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationDataEncryptionAlgorithmsLookupStrategy">
- <constructor-arg>
- <bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_encrypted_response_enc" />
- </constructor-arg>
- </bean>
- </property>
- </bean>
- </property>
- </bean>
-
- <bean id="AddIDTokenShell"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddIDTokenShell" scope="prototype" />
-
- <bean id="AddAttributeClaimsToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAttributesToClaimsSet" scope="prototype"
- p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
- p:reservedClaimNames="#{getObject('shibboleth.oidc.IDTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultIDTokenReservedClaimNames')}" />
+ <bean id="openidvci.ProfileRequestClientIDLookupStrategy" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ClientIDLookupStrategy"
+ c:f-ref="shibboleth.MessageContextLookup.Inbound" />
- <bean id="AddTokenDeliveryAttributesToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTokenDeliveryAttributesToClaimsSet" scope="prototype"
- p:targetIDToken="true" />
+ <!-- Beans of oidc/abstract, not a parent of this flow. -->
- <bean id="AddAuthTimeToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAuthTimeToIDToken" scope="prototype" />
+ <bean id="ResolveAttributes" class="net.shibboleth.idp.profile.impl.ResolveAttributes" scope="prototype"
+ c:resolverService-ref="shibboleth.AttributeResolverService"
+ p:maskFailures="%{idp.service.attribute.resolver.maskFailures:true}" />
- <bean id="AddAcrToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAcrToIDToken" scope="prototype" />
+ <bean id="FilterAttributes" class="net.shibboleth.idp.profile.impl.FilterAttributes" scope="prototype"
+ c:filterService-ref="shibboleth.AttributeFilterService"
+ p:maskFailures="%{idp.service.attribute.filter.maskFailures:true}" />
- <bean id="AddNonceToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddNonceToIDToken" scope="prototype"
- p:requestNonceLookupStrategy-ref="shibboleth.TokenRequestNonceLookupStrategy" />
+ <!-- The pre-authorized code grant. -->
- <bean id="shibboleth.TokenRequestNonceLookupStrategy"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestNonceLookupFunction" />
+ <bean id="OpenIDVCIPreAuthorizedCodeGrantCondition"
+ class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
+ p:grantTypes="#{T(org.geant.shibboleth.plugin.openidvci.messaging.impl.PreAuthorizedCodeGrant).GRANT_TYPE}" />
- <bean id="AddAccessTokenHashToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAccessTokenHashToIDToken" scope="prototype">
- <property name="securityParametersLookupStrategy">
- <bean parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
- c:f-ref="shibboleth.MessageContextLookup.Outbound" />
- </property>
- </bean>
+ <bean id="OpenIDVCIUnwrapPreAuthorizedCode"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.UnwrapPreAuthorizedCode" scope="prototype"
+ c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
+ p:clientIDLookupStrategy-ref="openidvci.ProfileRequestClientIDLookupStrategy"
+ p:credentialOfferCache-ref="openidvci.CredentialOfferCache"
+ p:activationCondition-ref="OpenIDVCIPreAuthorizedCodeGrantCondition" />
- <bean id="ManipulateClaimsForIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ManipulateClaimsForIDToken" scope="prototype"
- p:objectMapper-ref="#{'%{idp.oidc.logging.objectMapper:shibboleth.oidc.JSONObjectMapper}'.trim()}" />
+ <bean id="OpenIDVCIValidatePreAuthorizedCode"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidatePreAuthorizedCode" scope="prototype"
+ p:replayCache-ref="shibboleth.ReplayCache"/>
- <bean id="SignIDToken" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
- scope="prototype" c:executionDirection="OUTBOUND">
- <constructor-arg name="messageHandler">
- <bean id="SignIDTokenHandler"
- class="net.shibboleth.oidc.security.impl.SignJWTHandler" scope="prototype" p:logName="ID Token">
- <property name="claimsToSignLookupStrategy">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.JWTClaimsSetFromIDTokenLookupFunction" />
- </property>
- <property name="jwtUpdateConsumer">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.ProcessedTokenUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
- </bean>
+ <bean id="OpenIDVCIConsumeCredentialOffer"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.ConsumeCredentialOffer" scope="prototype"
+ p:credentialOfferCache-ref="openidvci.CredentialOfferCache" />
- <bean id="EncryptIDToken" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
- scope="prototype" c:executionDirection="OUTBOUND">
- <constructor-arg name="messageHandler">
- <bean id="EncryptIDTokenHandler"
- class="net.shibboleth.oidc.security.impl.EncryptJWTHandler" scope="prototype"
- p:logName="ID Token">
- <property name="payloadToEncryptLookupStrategy">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.PayloadFromProcessedTokenLookupFunction" />
- </property>
- <property name="jwtUpdateConsumer">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.ProcessedTokenUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
- </bean>
+ <bean id="OpenIDVCIValidateTxCode" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidateTxCode"
+ scope="prototype"/>
- <!-- REPLACED FormOutboundTokenResponseMessage. -->
- <bean id="FormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundTokenResponseMessage"
+ <bean id="OpenIDVCISetDPoPProofThumbprintToResponseContext"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.SetDPoPProofThumbprintToResponseContext"
scope="prototype" />
- <bean id="BuildErrorResponseFromEvent"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.BuildTokenErrorResponseFromEvent" scope="prototype"
- p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
- p:mappedErrors="#{getObject('shibboleth.oidc.token.MappedErrors') ?: getObject('openidvci.token.MappedErrors')}">
- <property name="eventContextLookupStrategy">
- <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
- </property>
- </bean>
-
- <!-- Third-party token actions. -->
+ <!-- The credentials of a grant. -->
- <bean id="PopulateThirdPartyAccessTokenSignatureSigningParameters"
- class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureSigningParameters"
- scope="prototype" p:noResultIsError="true"
- p:securityParametersContextLookupStrategy-ref="AudienceSecurityParametersCreationStrategy"
- c:strategy-ref="shibboleth.MessageContextLookup.Outbound">
- <property name="configurationLookupStrategy">
- <bean lazy-init="true"
- class="net.shibboleth.oidc.profile.config.navigate.JWTSignatureSigningConfigurationLookupFunction" />
- </property>
- <property name="signatureSigningParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationSignatureSigningParametersResolver">
- <constructor-arg name="signatureAlgorithmLookupStrategy">
- <bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_signed_response_alg" />
- </constructor-arg>
- <constructor-arg name="defaultAlgorithmValue" value="RS256" />
- </bean>
- </property>
- </bean>
-
- <bean id="AudienceSecurityParametersCreationStrategy" parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
- c:f-ref="AudienceRelyingPartyCreationStrategy" />
-
- <bean id="AudienceSecurityParametersCreationViaMessageContextStrategy" parent="shibboleth.Functions.Compose">
- <constructor-arg name="g" ref="AudienceSecurityParametersCreationStrategy" />
- <constructor-arg name="f">
- <bean parent="shibboleth.Functions.Expression" c:expression="#input.getParent()" />
- </constructor-arg>
- </bean>
-
- <bean id="PopulateThirdPartyAccessTokenEncryptionParameters"
- class="net.shibboleth.oidc.profile.impl.PopulateJWTEncryptionParameters" scope="prototype"
- p:encryptionOptionalPredicate-ref="AudienceEncryptionOptionalPredicate"
- p:securityParametersContextLookupStrategy-ref="AudienceSecurityParametersCreationStrategy"
- p:forFriendlyName="JWT Access Token">
- <property name="clientMetadataContextLookupStrategy">
- <bean class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCMetadataContextLookupFunction"
- p:inbound="false" />
- </property>
- <property name="configurationLookupStrategy">
- <bean lazy-init="true"
- class="net.shibboleth.oidc.profile.config.navigate.JWTEncryptionConfigurationLookupFunction" />
- </property>
- <property name="encryptionParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.DefaultEncryptionParametersResolver">
- <property name="keyTransportEncryptionAlgorithmsLookupStrategy">
- <bean
- class="net.shibboleth.oidc.security.jose.impl.ClientInformationKeyTransportEncryptionAlgorithmsLookupStrategy">
- <constructor-arg>
- <bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_encrypted_response_alg"/>
- </constructor-arg>
- </bean>
- </property>
- <property name="dataEncryptionAlgorithmsLookupStrategy">
- <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationDataEncryptionAlgorithmsLookupStrategy">
- <constructor-arg>
- <bean
- class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
- c:keyName="id_token_encrypted_response_enc"/>
- </constructor-arg>
- </bean>
- </property>
- </bean>
- </property>
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.NOT" c:_0-ref="BuildOIDCTokensCondition" />
- </property>
- </bean>
-
- <bean id="AudienceEncryptionOptionalPredicate"
- class="net.shibboleth.oidc.profile.config.logic.EncryptionOptionalPredicate"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
-
- <bean id="AudienceEncryptionContextCreationStrategy" parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.ChildLookupOrCreate.EncryptionParameters"
- c:f-ref="AudienceRelyingPartyCreationStrategy" />
+ <bean id="OpenIDVCIInitializePotentialCredentials"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.InitializePotentialCredentials" scope="prototype" />
- <bean id="AddAttributeClaimsToAccessToken"
+ <bean id="OpenIDVCIAddAttributeClaimsToPotentialCredentials"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAttributesToClaimsSet" scope="prototype"
- p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
- p:responseClaimsSetLookupStrategy-ref="AccessTokenClaimsSetLookupFunction"
- p:reservedClaimNames="#{getObject('shibboleth.oidc.AccessTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultAccessTokenReservedClaimNames')}" />
-
- <bean id="AccessTokenClaimsSetLookupFunction"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.AccessTokenClaimsSetLookupFunction"
- p:autoCreate="true" />
-
- <bean id="BuildAccessToken"
- class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildAccessToken" scope="prototype"
- p:dataSealer="#{getObject('%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim())}"
- p:issuerLookupStrategy-ref="AudienceIssuerLookupFunction"
- p:accessTokenTypeLookupStrategy-ref="AccessTokenTypeLookupFunction"
- p:accessTokenLifetimeLookupStrategy-ref="AccessTokenLifetimeLookupFunction"
- p:xmlSafeIdentifier="%{idp.oidc.xmlSafeIdentifiers:true}"
- p:identifierGeneratorLookupStrategy-ref="shibboleth.oidc.DefaultIdentifierGenerationStrategy"
- p:objectMapper-ref="#{'%{idp.oidc.logging.objectMapper:shibboleth.oidc.JSONObjectMapper}'.trim()}" />
-
- <bean id="AccessTokenTypeLookupFunction"
- class="net.shibboleth.oidc.profile.config.navigate.AccessTokenTypeLookupFunction"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
-
- <bean id="AccessTokenLifetimeLookupFunction"
- class="net.shibboleth.oidc.profile.config.navigate.AccessTokenLifetimeLookupFunction"
- p:relyingPartyContextLookupStrategy-ref="AudienceRelyingPartyCreationStrategy" />
-
- <bean id="SignAccessToken" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
- scope="prototype" c:executionDirection="OUTBOUND">
- <constructor-arg name="messageHandler">
- <bean id="SignAccessTokenHandler"
- class="net.shibboleth.oidc.security.impl.SignJWTHandler" scope="prototype" p:logName="Access Token"
- p:securityParametersLookupStrategy-ref="AudienceSecurityParametersCreationViaMessageContextStrategy"
- p:typeHeader="at+jwt">
- <property name="claimsToSignLookupStrategy">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.JWTClaimsSetFromJWTAccessTokenLookupFunction" />
- </property>
- <property name="jwtUpdateConsumer">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.JWTAccessTokenUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
- </bean>
-
- <bean id="EncryptAccessToken" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
- scope="prototype" c:executionDirection="OUTBOUND">
- <constructor-arg name="messageHandler">
- <bean id="EncryptAccessTokenHandler"
- class="net.shibboleth.oidc.security.impl.EncryptJWTHandler" scope="prototype"
- p:securityParametersLookupStrategy-ref="AudienceSecurityParametersCreationViaMessageContextStrategy"
- p:logName="Access Token">
- <property name="payloadToEncryptLookupStrategy">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.PayloadFromJWTAccessTokenLookupFunction" />
- </property>
- <property name="jwtUpdateConsumer">
- <bean
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.JWTAccessTokenUpdateStrategy" />
- </property>
- </bean>
- </constructor-arg>
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.NOT" c:_0-ref="BuildOIDCTokensCondition" />
- </property>
- </bean>
-
- <bean id="PostResponsePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
- p:fieldExtractors="#{getObject('shibboleth.oidc.TokenPostResponseAuditExtractors') ?: getObject('shibboleth.oidc.DefaultTokenPostResponseAuditExtractors')}" />
-
- <!-- ADDED. Actions and condition of the pre-authorized code grant. -->
-
- <bean id="OpenIDVCIValidateTxCode" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidateTxCode"
- scope="prototype"/>
+ p:responseClaimsSetLookupStrategy-ref="OpenIDVCIPotentialCredentialsLookupStrategy"
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
- <bean id="OpenIDVCIValidatePreAuthorizedCode" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ValidatePreAuthorizedCode"
- scope="prototype" p:replayCache-ref="shibboleth.ReplayCache"/>
+ <bean id="OpenIDVCIAddTokenDeliveryAttributesToPotentialCredentials"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTokenDeliveryAttributesToClaimsSet" scope="prototype"
+ p:responseClaimsSetLookupStrategy-ref="OpenIDVCIPotentialCredentialsLookupStrategy" />
- <bean id="OpenIDVCISetAuthorizationDetailsToResponseContext" class="org.geant.shibboleth.plugin.openidvci.profile.impl.SetAuthorizationDetailsToResponseContext"
- scope="prototype"/>
+ <bean id="OpenIDVCIPotentialCredentialsLookupStrategy"
+ class="org.geant.shibboleth.plugin.openidvci.messaging.context.navigate.PotentialCredentialsLookupFunction" />
<bean id="OpenIDVCIFilterPotentialCredentials"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.FilterPotentialCredentials" scope="prototype"
p:credentialConfigurationsResolver-ref="openidvci.CredentialConfigurationsResolver" />
- <bean id="OpenIDVCIConsumeCredentialOffer" class="org.geant.shibboleth.plugin.openidvci.profile.impl.ConsumeCredentialOffer"
- scope="prototype" p:credentialOfferCache-ref="openidvci.CredentialOfferCache" />
-
- <bean id="OpenIDVCISetDPoPProofThumbprintToResponseContext"
- class="org.geant.shibboleth.plugin.openidvci.profile.impl.SetDPoPProofThumbprintToResponseContext"
- scope="prototype" />
+ <bean id="OpenIDVCISetAuthorizationDetailsToResponseContext"
+ class="org.geant.shibboleth.plugin.openidvci.profile.impl.SetAuthorizationDetailsToResponseContext"
+ scope="prototype"/>
<bean id="OpenIDVCISetCredentialsAudienceToResponseContext"
class="org.geant.shibboleth.plugin.openidvci.profile.impl.SetCredentialsAudienceToResponseContext"
- scope="prototype" />
+ scope="prototype"
+ p:audienceLookupStrategy-ref="OpenIDVCICredentialIssuerIdentifierLookup" />
- <!-- REPLACED InitializeAuthenticationContext of oidc/abstract-api. -->
- <bean id="InitializeAuthenticationContext" class="org.geant.shibboleth.plugin.openidvci.profile.impl.InitializeAuthenticationContext"
- scope="prototype" />
+ <bean id="OpenIDVCICredentialIssuerIdentifierLookup"
+ class="org.geant.shibboleth.plugin.openidvci.metadata.impl.CredentialIssuerIdentifierLookupFunction"
+ c:resolver-ref="#{'%{openidvci.issuerMetadata.resolver:openidvci.DefaultCredentialIssuerMetadataResolver}'.trim()}" />
- <!-- ADDED. Error map of this plugin, extending the map of the OP. -->
+ <bean id="OpenIDVCICredentialIssuerAudienceCondition" parent="shibboleth.Conditions.Expression"
+ c:expression="#input.ensureOutboundMessageContext().ensureSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getAudience().isEmpty() or (#custom.apply(#input) != null and T(java.util.List).of(#custom.apply(#input)).containsAll(#input.ensureOutboundMessageContext().ensureSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getAudience()))"
+ p:customObject-ref="OpenIDVCICredentialIssuerIdentifierLookup" />
+
+ <!-- Error map of this plugin, extending the map of the OP. -->
<bean id="openidvci.token.MappedErrors" parent="shibboleth.oidc.DefaultApiMappedErrors"
class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
@@ -893,9 +217,4 @@
</property>
</bean>
- <!-- Condition signaling that the request was for the pre-authorized code grant. -->
- <bean id="OpenIDVCIPreAuthorizedCodeGrantCondition"
- class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
- p:grantTypes="#{T(org.geant.shibboleth.plugin.openidvci.messaging.impl.PreAuthorizedCodeGrant).GRANT_TYPE}" />
-
</beans>
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 b178bfb..4abedbe 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
@@ -7,29 +7,44 @@
Idea is to merge OP token and this flow to one at some point in future.
ADDED
- OpenIDVCIPreAuthorizedCodeGrantCondition selects the pre-authorized code grant
- OpenIDVCIValidateTxCode transaction code of a pre-authorized offer
+ OpenIDVCIUnwrapPreAuthorizedCode unwraps or locates the pre-authorized code
OpenIDVCIValidatePreAuthorizedCode one time use of a pre-authorized code
- OpenIDVCISetAuthorizationDetailsToResponseContext credential authorization details
OpenIDVCIConsumeCredentialOffer retires a stored offer before the transaction code is read
+ OpenIDVCIValidateTxCode transaction code of a pre-authorized offer
OpenIDVCISetDPoPProofThumbprintToResponseContext DPoP key the pre-authorized access token is bound to
- OpenIDVCISetCredentialsAudienceToResponseContext audience of the Credential endpoint in the access token of both grants
- OpenIDVCIFilterPotentialCredentials credentials of the code grant limited to the granted scope and authorization_details
- OpenIDVCIBranchOnPreAuthorizedCodeGrant state takes that grant aside
+ OpenIDVCIInitializePotentialCredentials empty credentials of a grant other than the pre-authorized code
+ OpenIDVCIAddAttributeClaimsToPotentialCredentials resolved attributes of the grant as credentials
+ OpenIDVCIAddTokenDeliveryAttributesToPotentialCredentials token delivery claims of the grant as credentials
+ OpenIDVCIFilterPotentialCredentials credentials limited to the granted scope and authorization_details
+ OpenIDVCISetAuthorizationDetailsToResponseContext credential authorization details
+ OpenIDVCISetCredentialsAudienceToResponseContext Credential Issuer Identifier as audience in the access token
+ of a grant with credentials, in BuildTokensForUserInfoAccess,
+ BuildTokensForThirdPartyAccess and the pre-authorized branch
+ OpenIDVCIBranchOnPreAuthorizedCodeGrant state takes the pre-authorized code grant aside
OpenIDVCIPreAuthzGrantProcessing state the pre-authorized code grant branch
- OpenIDVCIBuildTokensForCredentialsAccess state the opaque access token of both grants
+ OpenIDVCIBuildTokensForCredentialsAccess state the opaque access token of the pre-authorized code grant
+ OpenIDVCIBuildPotentialCredentials state the credentials of a grant other than client_credentials
+ OpenIDVCIBuildResponse state the decision of BuildResponse, the Credential Issuer Identifier
+ as audience counted as empty
REPLACED
the parent of the flow openid/vci/abstract-api in place of oidc/abstract-api
- the bean import the classpath form the other flows of this plugin use
- UnwrapGrant -> OpenIDVCIUnwrapGrant also reads the credential offer cache
-
- REPLACED, KEEPING THE ORIGINAL BEAN ID
- DecodeMessage, FormOutboundMessage, InitializeAuthenticationContext
- Named by states of openid/vci/abstract-api. Marked in token-beans.xml.
-
- REMOVED
- the transition from TraditionalGrantProcessing to CheckTraditionalGrantForAudience
+ the bean import token-beans.xml of this flow, importing the beans of oidc/abstract-api
+ and oidc/token
+ UnwrapGrant -> OpenIDVCIUnwrapGrant client id lookup of this plugin, not for the
+ pre-authorized code
+ ValidateGrant -> OpenIDVCIValidateGrant in TraditionalGrantProcessing, client instance key
+ condition added to the token revocation condition
+ ValidatePKCE -> OpenIDVCIValidatePKCE code verifier lookup of this plugin
+ BuildOIDCAccessToken -> OpenIDVCIBuildOIDCAccessToken client id lookup of this plugin
+ the targets of BuildResponse OpenIDVCIBuildPotentialCredentials, and OpenIDVCIBuildResponse for
+ client_credentials, in place of BuildTokensForUserInfoAccess and
+ BuildTokensForThirdPartyAccess
+
+ BEANS NAMED BY THE PARENT FLOWS
+ OpenIDVCIDecodeMessage, OpenIDVCIFormOutboundMessage, OpenIDVCIBuildErrorResponseFromEvent and
+ InitializeAuthenticationContext of openid/vci/abstract-api; shibboleth.ClientIDLookupStrategy of
+ oidc/metadata-lookup, replaced keeping the bean id. In token-beans.xml.
-->
<flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -51,6 +66,8 @@
<action-state id="PostDecodeMessage">
<!-- REPLACED UnwrapGrant. -->
<evaluate expression="OpenIDVCIUnwrapGrant" />
+ <!-- ADDED. -->
+ <evaluate expression="OpenIDVCIUnwrapPreAuthorizedCode" />
<evaluate expression="'proceed'" />
<!-- DoMetadataLookup is expected to proceed to SelectConfiguration -->
@@ -92,8 +109,10 @@
<!-- These steps apply to grants that rely on the authorization endpoint to "prime" the token request. -->
<action-state id="TraditionalGrantProcessing">
- <evaluate expression="ValidateGrant" />
- <evaluate expression="ValidatePKCE" />
+ <!-- REPLACED ValidateGrant. -->
+ <evaluate expression="OpenIDVCIValidateGrant" />
+ <!-- REPLACED ValidatePKCE. -->
+ <evaluate expression="OpenIDVCIValidatePKCE" />
<evaluate expression="ValidateRedirectURI" />
<evaluate expression="SetRequestedClaimsToResponseContext" />
<evaluate expression="SetAuthenticationContextClassReferenceFromAuthzCodeToResponseContext" />
@@ -106,12 +125,9 @@
<evaluate expression="ValidateScope" />
<evaluate expression="ValidateAudience" />
<evaluate expression="SetSessionIdFromAuthzCodeToResponseContext" />
- <!-- ADDED. -->
- <evaluate expression="OpenIDVCIFilterPotentialCredentials" />
<evaluate expression="'proceed'" />
-
- <!-- REPLACED the transition to CheckTraditionalGrantForAudience. -->
- <transition on="proceed" to="OpenIDVCIBuildTokensForCredentialsAccess" />
+
+ <transition on="proceed" to="CheckTraditionalGrantForAudience" />
</action-state>
<!-- For standard grants, audience may or may not be a factor. -->
@@ -136,7 +152,7 @@
<action-state id="OpenIDVCIBuildTokensForCredentialsAccess">
<evaluate expression="OpenIDVCISetAuthorizationDetailsToResponseContext" />
<evaluate expression="OpenIDVCISetCredentialsAudienceToResponseContext" />
- <evaluate expression="BuildOIDCAccessToken" />
+ <evaluate expression="OpenIDVCIBuildOIDCAccessToken" />
<evaluate expression="SetOAuthAccessTokenToResponseContext" />
<evaluate expression="'proceed'" />
@@ -214,9 +230,21 @@
<evaluate expression="ResolveAttributes" />
<evaluate expression="FilterAttributes" />
<evaluate expression="'proceed'" />
-
+
<transition on="proceed" to="DoConsentLookup" />
</action-state>
+
+ <!-- ADDED. Credentials of the grant from the resolved attributes and the token delivery claims. -->
+ <action-state id="OpenIDVCIBuildPotentialCredentials">
+ <evaluate expression="OpenIDVCIInitializePotentialCredentials" />
+ <evaluate expression="OpenIDVCIAddAttributeClaimsToPotentialCredentials" />
+ <evaluate expression="OpenIDVCIAddTokenDeliveryAttributesToPotentialCredentials" />
+ <evaluate expression="OpenIDVCIFilterPotentialCredentials" />
+ <evaluate expression="OpenIDVCISetAuthorizationDetailsToResponseContext" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="OpenIDVCIBuildResponse" />
+ </action-state>
<decision-state id="CheckAttributeResolutionForAudience">
<if test="ResolveAttributesForAudiencePredicate.test(opensamlProfileRequestContext)"
@@ -232,8 +260,16 @@
<transition on="proceed" to="DoConsentLookup" />
</action-state>
+ <!-- REPLACED the targets BuildTokensForUserInfoAccess and BuildTokensForThirdPartyAccess. -->
<decision-state id="BuildResponse">
- <if test="opensamlProfileRequestContext.ensureOutboundMessageContext().ensureSubcontext(T(net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext)).getAudience().isEmpty()"
+ <if test="NotClientCredentialsGrantCondition.test(opensamlProfileRequestContext)"
+ then="OpenIDVCIBuildPotentialCredentials"
+ else="OpenIDVCIBuildResponse" />
+ </decision-state>
+
+ <!-- ADDED. The decision of BuildResponse, the Credential Issuer Identifier as audience counted as empty. -->
+ <decision-state id="OpenIDVCIBuildResponse">
+ <if test="OpenIDVCICredentialIssuerAudienceCondition.test(opensamlProfileRequestContext)"
then="BuildTokensForUserInfoAccess"
else="BuildTokensForThirdPartyAccess" />
</decision-state>
@@ -249,7 +285,10 @@
-->
<action-state id="BuildTokensForUserInfoAccess">
<evaluate expression="PopulateUserInfoAccessTokenSignatureSigningParameters" />
- <evaluate expression="BuildOIDCAccessToken" />
+ <!-- ADDED. -->
+ <evaluate expression="OpenIDVCISetCredentialsAudienceToResponseContext" />
+ <!-- REPLACED BuildOIDCAccessToken. -->
+ <evaluate expression="OpenIDVCIBuildOIDCAccessToken" />
<evaluate expression="SignOIDCAccessToken" />
<evaluate expression="SetOAuthAccessTokenToResponseContext" />
<evaluate expression="SetRefreshTokenToResponseContext" />
@@ -270,6 +309,8 @@
<evaluate expression="PopulateThirdPartyAccessTokenSignatureSigningParameters" />
<evaluate expression="PopulateThirdPartyAccessTokenEncryptionParameters" />
<evaluate expression="AddAttributeClaimsToAccessToken" />
+ <!-- ADDED. -->
+ <evaluate expression="OpenIDVCISetCredentialsAudienceToResponseContext" />
<evaluate expression="BuildAccessToken" />
<evaluate expression="SignAccessToken" />
<evaluate expression="EncryptAccessToken" />
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index 6bc3ab2..a4873ac 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -41,7 +41,36 @@
<bean id="OpenID.VCI.CredentialOffer" parent="AbstractVCIProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.profile.config.impl.DefaultOpenIDVCICredentialOfferConfiguration" />
- <bean id="OpenID.VCI.Token" parent="AbstractVCIProfile" lazy-init="true"
+ <!-- Settings of AbstractOIDCSSOProfile and OAUTH2.Token of the OP plugin, with the DPoP claims validator of this plugin. -->
+ <bean id="AbstractVCITokenProfile" abstract="true"
+ p:securityConfiguration-ref="%{idp.security.oidc.config:shibboleth.oidc.DefaultSecurityConfiguration}"
+ p:issuer="#{getObject('shibboleth.oidc.issuer')}"
+ p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
+ p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}"
+ p:encryptionOptional="%{idp.oidc.encryptionOptional:true}"
+ p:forcePKCE="%{idp.oidc.forcePKCE:false}"
+ p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
+ p:iDTokenLifetime="%{idp.oidc.idToken.defaultLifetime:PT1H}"
+ p:accessTokenType="%{idp.oauth2.accessToken.type:}"
+ p:accessTokenLifetime="%{idp.oidc.accessToken.defaultLifetime:PT10M}"
+ p:refreshTokenType="%{idp.oauth2.refreshToken.type:}"
+ p:refreshTokenTimeout="%{idp.oidc.refreshToken.defaultTimeout:PT2H}"
+ p:refreshTokenChainLifetime="%{idp.oidc.refreshToken.defaultChainLifetime:PT2H}"
+ p:alwaysIncludedAttributes="%{idp.oidc.alwaysIncludedAttributes:}"
+ p:tokenEndpointAuthMethod="%{idp.authn.oidc.rp.client.authenticationMethod:client_secret_basic}"
+ p:useTargetedEndpointAsJWTAudience="%{idp.oauth2.jwtAuth.targetedEndpointAsJWTAudience:true}"
+ p:requireSingleJWTAudience="%{idp.oauth2.jwtAuth.requireSingleJWTAudience:false}"
+ p:clientId="#{%{idp.authn.oidc.rp.provider.discoveryRequired:false} == true ? null : '%{idp.authn.oidc.rp.client.clientId:}'}"
+ p:clientCredential="#{%{idp.authn.oidc.rp.provider.discoveryRequired:false} == true ? {null} : getObject('shibboleth.authn.oidc.rp.DefaultCredential')}"
+ p:unregisteredClientPolicy="#{getObject('shibboleth.oidc.DefaultUnregisteredClientPolicy')}"
+ p:dpopProofClaimsValidator="#{getObject('openidvci.DefaultDPoPProofClaimsValidator')}"
+ p:dpopProofSignatureValidationConfiguration="#{getObject('DPoPSignatureValidationConfiguration')}"
+ p:dpopProofNonceGenerator="#{getObject('DefaultOAuth2DPoPNonceGenerator')}"
+ p:strictScopeValidation="%{idp.oidc.strictScopeValidation:false}"
+ p:enforceRefreshTokenRotation="%{idp.oauth2.enforceRefreshTokenRotation:false}"
+ p:issueIdTokenViaRefreshToken="%{idp.oidc.issueIdTokenViaRefreshToken:true}" />
+
+ <bean id="OpenID.VCI.Token" parent="AbstractVCITokenProfile" lazy-init="true"
class="org.geant.shibboleth.plugin.openidvci.profile.config.impl.DefaultOpenIDVCITokenConfiguration" />
<bean id="OpenID.VCI.Nonce" parent="AbstractVCIProfile" lazy-init="true"
@@ -187,7 +216,9 @@
<bean id="openidvci.CredentialsAudienceClaimsValidator"
class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator">
<property name="audienceLookupStrategy">
- <bean parent="shibboleth.BiFunctions.Expression" c:expression="T(org.geant.shibboleth.plugin.openidvci.profile.impl.SetCredentialsAudienceToResponseContext).AUDIENCE" />
+ <bean parent="shibboleth.BiFunctions.Expression"
+ c:expression="#custom.apply(#input1)"
+ p:customObject-ref="openidvci.CredentialIssuerIdentifierLookup" />
</property>
</bean>
diff --git a/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/conf/openid-vci.properties b/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/conf/openid-vci.properties
index 1e3d64f..c85bcb7 100644
--- a/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/conf/openid-vci.properties
+++ b/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/conf/openid-vci.properties
@@ -25,6 +25,10 @@ openidvci.issuer =
# Lifetime of the c_nonce of the Nonce endpoint
#openidvci.nonce.lifetime = PT5M
+# Bean name of a custom parser of the Token endpoint request, a CustomNimbusRequestParser of the OP
+# plugin returning an OpenIDVCITokenRequest
+#openidvci.requestParser.TokenRequest =
+
# The location for the JSON file of Credential Configurations, published in Credential Issuer
# metadata and used as the instruction on how a credential is formed. Every flow reads them
# from here, through one resolver, so the file is read when it changes and not once per request.
diff --git a/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/static/oauth-authorization-server.json b/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/static/oauth-authorization-server.json
index d396c3f..5743a48 100644
--- a/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/static/oauth-authorization-server.json
+++ b/openid-vci-impl/src/main/resources/org/geant/shibboleth/plugin/openidvci/static/oauth-authorization-server.json
@@ -13,6 +13,7 @@
],
"grant_types_supported":[
"authorization_code",
+ "refresh_token",
"urn:ietf:params:oauth:grant-type:pre-authorized_code"
],
"code_challenge_methods_supported":[
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoderTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoderTest.java
index 8825a1a..a0dfbb7 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoderTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/decoding/impl/OpenIDVCITokenRequestDecoderTest.java
@@ -24,6 +24,8 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.oauth2.sdk.RefreshTokenGrant;
+
import jakarta.servlet.http.HttpServletRequest;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.primitive.NonnullSupplier;
@@ -86,4 +88,28 @@ public class OpenIDVCITokenRequestDecoderTest {
.getClientID().getValue(), "test");
}
-}
\ No newline at end of file
+ @Test
+ public void testRefreshTokenGrant() throws MessageDecodingException {
+ httpRequest.removeParameter("pre-authorized_code");
+ httpRequest.setParameter("grant_type", "refresh_token");
+ httpRequest.addParameter("refresh_token", "abc");
+ decoder.decode();
+ final OpenIDVCITokenRequest request = (OpenIDVCITokenRequest) decoder.getMessageContext().getMessage();
+ Assert.assertTrue(request.getAuthorizationGrant() instanceof RefreshTokenGrant);
+ Assert.assertEquals(request.getClientID().getValue(), "123456");
+ }
+
+ @Test
+ public void testCodeGrantScopeRemovedAndResourcePrefixed() throws MessageDecodingException {
+ httpRequest.removeParameter("pre-authorized_code");
+ httpRequest.setParameter("grant_type", "authorization_code");
+ httpRequest.addParameter("code", "abc");
+ httpRequest.addParameter("scope", "openid");
+ httpRequest.addParameter("resource", "api");
+ decoder.decode();
+ final OpenIDVCITokenRequest request = (OpenIDVCITokenRequest) decoder.getMessageContext().getMessage();
+ Assert.assertNull(request.getScope());
+ Assert.assertEquals(request.getResources().get(0).toString(), "urn:shibboleth.oidc.op.resource:api");
+ }
+
+}
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequestTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequestTest.java
index 18f3d8e..5e6bc57 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequestTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/OpenIDVCITokenRequestTest.java
@@ -24,10 +24,13 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.common.contenttype.ContentType;
import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
import com.nimbusds.oauth2.sdk.GrantType;
import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.RefreshTokenGrant;
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
import com.nimbusds.oauth2.sdk.auth.Secret;
@@ -123,4 +126,62 @@ public class OpenIDVCITokenRequestTest {
Assert.assertEquals(message.getAuthorizationGrant().getType(), GrantType.AUTHORIZATION_CODE);
}
-}
\ No newline at end of file
+ @Test
+ public void parseCodeGrantScopeAndResource() throws ParseException, URISyntaxException {
+ httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
+ httpRequest.setContentType(ContentType.APPLICATION_URLENCODED.toString());
+ httpRequest.setBody("client_id=clientID&grant_type=authorization_code&code=123456"
+ + "&scope=openid%20profile&resource=https%3A%2F%2Fexample.org%2Fapi");
+ message = OpenIDVCITokenRequest.parse(httpRequest);
+ Assert.assertEquals(message.getScope().toString(), "openid profile");
+ Assert.assertEquals(message.getResources().get(0).toString(), "https://example.org/api");
+ }
+
+ @Test(expectedExceptions = ParseException.class)
+ public void parseRelativeResource() throws ParseException, URISyntaxException {
+ httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
+ httpRequest.setContentType(ContentType.APPLICATION_URLENCODED.toString());
+ httpRequest.setBody("client_id=clientID&grant_type=authorization_code&code=123456&resource=api");
+ OpenIDVCITokenRequest.parse(httpRequest);
+ }
+
+ @Test
+ public void parseRefreshTokenGrant() throws ParseException, URISyntaxException {
+ httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
+ httpRequest.setContentType(ContentType.APPLICATION_URLENCODED.toString());
+ httpRequest.setBody("client_id=clientID&grant_type=refresh_token&refresh_token=abc&scope=openid");
+ message = OpenIDVCITokenRequest.parse(httpRequest);
+ Assert.assertTrue(message.getAuthorizationGrant() instanceof RefreshTokenGrant);
+ Assert.assertEquals(message.getGrantType(), GrantType.REFRESH_TOKEN.getValue());
+ Assert.assertEquals(message.getClientID().getValue(), "clientID");
+ Assert.assertEquals(message.getScope().toString(), "openid");
+ }
+
+ @Test
+ public void parseRefreshTokenGrantWithClientAttestation() throws ParseException, URISyntaxException {
+ httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
+ httpRequest.setContentType(ContentType.APPLICATION_URLENCODED.toString());
+ httpRequest.setHeader("OAuth-Client-Attestation",
+ Base64URL.encode("{\"alg\":\"ES256\",\"typ\":\"oauth-client-attestation+jwt\"}") + "."
+ + Base64URL.encode("{\"sub\":\"attestedClient\"}") + "." + Base64URL.encode("signature"));
+ httpRequest.setBody("grant_type=refresh_token&refresh_token=abc");
+ message = OpenIDVCITokenRequest.parse(httpRequest);
+ Assert.assertTrue(message.getAuthorizationGrant() instanceof RefreshTokenGrant);
+ Assert.assertNull(message.getClientAuthentication());
+ Assert.assertEquals(message.getClientID().getValue(), "attestedClient");
+ }
+
+ @Test
+ public void parseClientCredentialsGrant() throws ParseException, URISyntaxException {
+ httpRequest = new HTTPRequest(HTTPRequest.Method.POST, new URI("http://example.com"));
+ httpRequest.setContentType(ContentType.APPLICATION_URLENCODED.toString());
+ httpRequest.setAuthorization(new ClientSecretBasic(new ClientID("clientID"), new Secret("secret"))
+ .toHTTPAuthorizationHeader());
+ httpRequest.setBody("grant_type=client_credentials&scope=read");
+ message = OpenIDVCITokenRequest.parse(httpRequest);
+ Assert.assertTrue(message.getAuthorizationGrant() instanceof ClientCredentialsGrant);
+ Assert.assertEquals(message.getClientAuthentication().getClientID().getValue(), "clientID");
+ Assert.assertEquals(message.getScope().toString(), "read");
+ }
+
+}
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfigurationTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfigurationTest.java
index 1acdfea..90b6ed4 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfigurationTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultOpenIDVCITokenConfigurationTest.java
@@ -25,6 +25,7 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenConfiguration;
+import net.shibboleth.oidc.profile.oauth2.config.impl.DefaultOAuth2TokenConfiguration;
/** Tests for {@link DefaultOpenIDVCITokenConfiguration}. */
public class DefaultOpenIDVCITokenConfigurationTest {
@@ -41,10 +42,15 @@ public class DefaultOpenIDVCITokenConfigurationTest {
Assert.assertTrue(configuration instanceof OAuth2TokenConfiguration);
}
+ @Test
+ public void testIsOAuth2TokenConfigurationOfOP() {
+ Assert.assertTrue(configuration instanceof DefaultOAuth2TokenConfiguration);
+ }
+
@Test
public void testDefaultGrantTypes() {
Assert.assertEquals(configuration.getGrantTypes(null),
- Set.of("authorization_code", OpenIDVCITokenRequest.GRANT_TYPE_VALUE_PRE_AUTH));
+ Set.of("authorization_code", "refresh_token", OpenIDVCITokenRequest.GRANT_TYPE_VALUE_PRE_AUTH));
}
@Test
@@ -60,15 +66,11 @@ public class DefaultOpenIDVCITokenConfigurationTest {
}
@Test
- public void testRefreshTokensDisabled() {
- Assert.assertFalse(configuration.isRefreshTokensEnabled(null));
- }
-
- @Test
- public void testFixedRefreshTokenAndAudienceSettings() {
+ public void testRefreshTokenDefaultsOfOP() {
+ Assert.assertTrue(configuration.isRefreshTokensEnabled(null));
Assert.assertFalse(configuration.isEnforceRefreshTokenRotation(null));
Assert.assertNull(configuration.getRefreshTokenClaimsSetManipulationStrategy(null));
- Assert.assertFalse(configuration.isIssueIdTokenViaRefreshToken(null));
+ Assert.assertTrue(configuration.isIssueIdTokenViaRefreshToken(null));
Assert.assertFalse(configuration.isLimitInitialAccessTokenToSelf(null));
}
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContextTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContextTest.java
index 9d72d12..67ebef0 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContextTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/SetCredentialsAudienceToResponseContextTest.java
@@ -19,6 +19,7 @@ package org.geant.shibboleth.plugin.openidvci.profile.impl;
import java.util.List;
import org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCITokenRequestDecoder;
+import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.profile.context.ProfileRequestContext;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -27,11 +28,15 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
import jakarta.servlet.http.HttpServletRequest;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.primitive.NonnullSupplier;
/**
@@ -39,10 +44,14 @@ import net.shibboleth.shared.primitive.NonnullSupplier;
*/
public class SetCredentialsAudienceToResponseContextTest {
+ private static final String ISSUER = "https://issuer.example.org";
+
private RequestContext requestCtx;
private OIDCAuthenticationResponseContext responseCtx;
+ private TokenContext tokenCtx;
+
@BeforeMethod
protected void setUp() throws Exception {
final MockHttpServletRequest httpRequest = new MockHttpServletRequest();
@@ -67,25 +76,50 @@ public class SetCredentialsAudienceToResponseContextTest {
profileRequestCtx.setOutboundMessageContext(new MessageContext());
responseCtx = profileRequestCtx.getOutboundMessageContext()
.ensureSubcontext(OIDCAuthenticationResponseContext.class);
+ tokenCtx = profileRequestCtx.ensureInboundMessageContext().ensureSubcontext(TokenContext.class);
+ final ClaimsSet credentials = new ClaimsSet();
+ credentials.setClaim("ConfigurationId", "[]");
+ tokenCtx.setPotentialCredentials(credentials);
}
- @Test
- public void testAdded() throws Exception {
+ private SetCredentialsAudienceToResponseContext action(final String issuer) throws Exception {
final SetCredentialsAudienceToResponseContext action = new SetCredentialsAudienceToResponseContext();
+ action.setAudienceLookupStrategy(prc -> issuer);
action.initialize();
- ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
- Assert.assertEquals(responseCtx.getAudience(), List.of(SetCredentialsAudienceToResponseContext.AUDIENCE));
+ return action;
+ }
+
+ @Test
+ public void testAdded() throws Exception {
+ ActionTestingSupport.assertProceedEvent(action(ISSUER).execute(requestCtx));
+ Assert.assertEquals(responseCtx.getAudience(), List.of(ISSUER));
}
@Test
public void testNotDuplicated() throws Exception {
- responseCtx.getAudience().add(SetCredentialsAudienceToResponseContext.AUDIENCE);
+ responseCtx.getAudience().add(ISSUER);
responseCtx.getAudience().add("other");
- final SetCredentialsAudienceToResponseContext action = new SetCredentialsAudienceToResponseContext();
- action.initialize();
+ ActionTestingSupport.assertProceedEvent(action(ISSUER).execute(requestCtx));
+ Assert.assertEquals(responseCtx.getAudience(), List.of(ISSUER, "other"));
+ }
+
+ @Test
+ public void testNoIssuer() throws Exception {
+ ActionTestingSupport.assertEvent(action(null).execute(requestCtx), IdPEventIds.INVALID_PROFILE_CONFIG);
+ Assert.assertTrue(responseCtx.getAudience().isEmpty());
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testNoStrategy() throws Exception {
+ new SetCredentialsAudienceToResponseContext().initialize();
+ }
+
+ @Test
+ public void testNotAddedWithoutCredentials() throws Exception {
+ tokenCtx.setPotentialCredentials(new ClaimsSet());
+ final SetCredentialsAudienceToResponseContext action = action(ISSUER);
ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
- Assert.assertEquals(responseCtx.getAudience(),
- List.of(SetCredentialsAudienceToResponseContext.AUDIENCE, "other"));
+ Assert.assertTrue(responseCtx.getAudience().isEmpty());
}
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list