[java-idp-plugin-vci] 02/02: Review authorization-server flow: OP conventions, RFC 8414 metadata validation

Codeberg noreply at shibboleth.net
Thu Oct 29 06:49:06 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-idp-plugin-vci.

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

commit a88aab03e5fb3b83dcdbe9ac0949f7d83e2f02af
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Thu Oct 29 08:48:53 2026 +0200

    Review authorization-server flow: OP conventions, RFC 8414 metadata validation
---
 README.md                                          |  19 ++-
 ...esystemAuthorizationServerMetadataResolver.java | 140 +++++++++++++++++++++
 .../impl/DefaultMetadataDocumentConfiguration.java |   6 +
 .../META-INF/net.shibboleth.idp/postconfig.xml     |   2 +-
 .../authorization-server-beans.xml                 |  15 ++-
 .../authorization-server-flow.xml                  |   6 +-
 .../plugin/openidvci/conf/openid-vci.properties    |   3 +
 ...temAuthorizationServerMetadataResolverTest.java | 121 ++++++++++++++++++
 .../DefaultMetadataDocumentConfigurationTest.java  |   8 ++
 9 files changed, 304 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index feb2030..6cdfecc 100644
--- a/README.md
+++ b/README.md
@@ -4440,10 +4440,9 @@ Endpoint `/idp/profile/openid/vci/issuer-metadata`, profile ID `http://geant.org
 | `issuerMetadataSignatureSigningConfiguration` | SignatureSigningConfiguration | **openidvci.issuerMetadata.SigningConfiguration** | Signing of the metadata. Published unsigned until **openidvci.issuerMetadata.SigningCredentials** exists. Signed metadata is served for `Accept: application/jwt`. |
 | `outboundInterceptorFlows` | List<String> | | Interceptor flows run before the response is sent, also for an error response. |
 
-**OAuth.JWTVCIssuer** (`/idp/profile/oauth/jwt-vc-issuer`) has two settings,
-`inboundInterceptorFlows`, interceptor flows run before the document is formed, and
-`outboundInterceptorFlows` as above. **OAuth.AuthorizationServer**
-(`/idp/profile/oauth/authorization-server`) has one setting, `outboundInterceptorFlows`.
+**OAuth.JWTVCIssuer** (`/idp/profile/oauth/jwt-vc-issuer`) and **OAuth.AuthorizationServer**
+(`/idp/profile/oauth/authorization-server`) have two settings, `inboundInterceptorFlows`,
+interceptor flows run before the document is formed, and `outboundInterceptorFlows` as above.
 
 #### DID.Document
 
@@ -4726,6 +4725,7 @@ The file comes with the plugin and is loaded automatically.
 | `openidvci.authorizationServer.templated` | Boolean | `true` | Whether the file is Velocity. |
 | `openidvci.authorizationServer.resolver` | Bean ID | **openidvci.DefaultAuthorizationServerMetadataResolver** | Resolver of the document. |
 | `openidvci.authorizationServer.minRefreshDelay`, `…maxRefreshDelay` | Duration | `PT5M`, `PT4H` | Bounds of re-reading the file. |
+| `openidvci.authorizationServer.cacheControl` | String | `max-age=3600` | Cache-Control of the response. |
 
 #### Signing keys
 
@@ -4797,13 +4797,20 @@ The templates are Velocity, `$issuer`, `$baseUrl` and `$host` are filled in from
 When `idp.oidc.issuer` has a path, the JWT VC issuer metadata is at `/.well-known/jwt-vc-issuer`
 followed by that path, `https://issuer.example.org/tenant` has it at
 `/.well-known/jwt-vc-issuer/tenant`, and the rewrite pattern is that.
+The authorization server metadata is likewise at `/.well-known/oauth-authorization-server`
+followed by that path, `/.well-known/oauth-authorization-server/tenant`.
 The JWT VC issuer metadata names one issuer. A credential with a url other than
 `idp.oidc.issuer` as its issuer is verified by `x5c`, or needs the `issuer` of the template
 changed to that url.
 `credential_configurations_supported` is added from *metadata/verifiable-credentials.json*. The
 Credential Issuer metadata endpoint answers `500 server_error` when `credential_endpoint` or
-`credential_configurations_supported` is missing. `batch_credential_issuance.batch_size` is the
-most proofs a credential request may carry, it overrides `batchSize` of the profile.
+`credential_configurations_supported` is missing. The authorization server metadata endpoint
+answers `500 server_error` when `issuer`, `token_endpoint` or `grant_types_supported` is
+missing, when `authorization_code` is listed without `authorization_endpoint`, when
+`response_types_supported` is missing and a grant type other than the pre-authorized code is
+listed, when `implicit` is listed, or when an endpoint is not an https url.
+`batch_credential_issuance.batch_size` is the most proofs a credential request may carry, it
+overrides `batchSize` of the profile.
 `token_endpoint` is the token endpoint of this plugin. The OP's
 `/.well-known/openid-configuration` has the OP's own token endpoint.
 `dpop_signing_alg_values_supported` should be in step with `idp.oauth2.dpop.proofAlgorithms` of
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemAuthorizationServerMetadataResolver.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemAuthorizationServerMetadataResolver.java
new file mode 100644
index 0000000..bf909e2
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemAuthorizationServerMetadataResolver.java
@@ -0,0 +1,140 @@
+/*
+ * 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.metadata.impl;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.geant.shibboleth.plugin.openidvci.metadata.MetadataDocument;
+import org.springframework.core.io.Resource;
+
+import com.nimbusds.oauth2.sdk.GrantType;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.as.AuthorizationServerMetadata;
+
+import net.minidev.json.JSONObject;
+
+/**
+ * OAuth 2.0 Authorization Server Metadata read from a file, as in
+ * <a href="https://www.rfc-editor.org/rfc/rfc8414#section-2">RFC 8414</a>.
+ */
+public class FilesystemAuthorizationServerMetadataResolver extends FilesystemMetadataDocumentResolver {
+
+    /** Member listing the response types. */
+    @Nonnull
+    public static final String RESPONSE_TYPES_SUPPORTED = "response_types_supported";
+
+    /** Member listing the grant types. */
+    @Nonnull
+    public static final String GRANT_TYPES_SUPPORTED = "grant_types_supported";
+
+    /** Member of the authorization endpoint. */
+    @Nonnull
+    public static final String AUTHORIZATION_ENDPOINT = "authorization_endpoint";
+
+    /** Member of the token endpoint. */
+    @Nonnull
+    public static final String TOKEN_ENDPOINT = "token_endpoint";
+
+    /** Member referencing the JWK Set. */
+    @Nonnull
+    public static final String JWKS_URI = "jwks_uri";
+
+    /** Pre-authorized code grant type of OpenID4VCI. */
+    @Nonnull
+    public static final String PRE_AUTHORIZED_CODE = "urn:ietf:params:oauth:grant-type:pre-authorized_code";
+
+    /** Suffix of the endpoint members. */
+    @Nonnull
+    public static final String ENDPOINT_SUFFIX = "_endpoint";
+
+    /**
+     * Constructor.
+     *
+     * @param metadata the metadata file
+     *
+     * @throws IOException if the metadata cannot be loaded
+     */
+    public FilesystemAuthorizationServerMetadataResolver(@Nonnull final Resource metadata) throws IOException {
+        super(metadata);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull
+    protected MetadataDocument fromMembers(@Nonnull final Map<String, Object> members) throws ParseException {
+
+        final MetadataDocument document = super.fromMembers(members);
+        final Map<String, Object> documentMembers = document.getMembers();
+        AuthorizationServerMetadata.parse(new JSONObject(documentMembers).toJSONString());
+
+        if (!(documentMembers.get(GRANT_TYPES_SUPPORTED) instanceof List<?> grantTypes)) {
+            throw new ParseException("Authorization Server Metadata has no '" + GRANT_TYPES_SUPPORTED + "'");
+        }
+        if (!List.of(PRE_AUTHORIZED_CODE).equals(grantTypes)
+                && !documentMembers.containsKey(RESPONSE_TYPES_SUPPORTED)) {
+            throw new ParseException("Authorization Server Metadata has no '" + RESPONSE_TYPES_SUPPORTED + "'");
+        }
+        if (grantTypes.contains(GrantType.IMPLICIT.getValue())) {
+            throw new ParseException("Authorization Server Metadata lists the unsupported grant type '"
+                    + GrantType.IMPLICIT.getValue() + "'");
+        }
+        if (grantTypes.contains(GrantType.AUTHORIZATION_CODE.getValue())
+                && !documentMembers.containsKey(AUTHORIZATION_ENDPOINT)) {
+            throw new ParseException("Authorization Server Metadata has no '" + AUTHORIZATION_ENDPOINT + "'");
+        }
+        if (!documentMembers.containsKey(TOKEN_ENDPOINT)) {
+            throw new ParseException("Authorization Server Metadata has no '" + TOKEN_ENDPOINT + "'");
+        }
+        for (final Map.Entry<String, Object> member : documentMembers.entrySet()) {
+            if (member.getKey().endsWith(ENDPOINT_SUFFIX) || JWKS_URI.equals(member.getKey())) {
+                validateHttpsUrl(member.getKey(), member.getValue());
+            }
+        }
+        return document;
+    }
+
+    /**
+     * Check the value is an https url with a host.
+     *
+     * @param name  name of the member
+     * @param value value of the member
+     * @throws ParseException if the value is not such a url
+     */
+    private static void validateHttpsUrl(@Nonnull final String name, @Nullable final Object value)
+            throws ParseException {
+
+        if (!(value instanceof String url)) {
+            throw new ParseException("'" + name + "' is not a string");
+        }
+        try {
+            final URI parsed = new URI(url);
+            if (!"https".equals(parsed.getScheme()) || parsed.getHost() == null) {
+                throw new ParseException("'" + name + "' " + url + " is not an https url with a host");
+            }
+        } catch (final URISyntaxException e) {
+            throw new ParseException("'" + name + "' " + url + " is not a url", e);
+        }
+    }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfiguration.java
index b768fc4..7c52e15 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfiguration.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfiguration.java
@@ -42,6 +42,12 @@ public class DefaultMetadataDocumentConfiguration extends AbstractInterceptorAwa
     public static final String PROFILE_ID_AUTHORIZATION_SERVER =
             "http://geant.org/ns/profiles/oauth/authorization-server";
 
+    /** Authorization server metadata profile counter name. */
+    @Nonnull
+    @NotEmpty
+    public static final String PROFILE_COUNTER_AUTHORIZATION_SERVER =
+            "net.shibboleth.idp.profiles.oauth.authorization-server";
+
     /** ID for the did:web document profile configuration. */
     @Nonnull
     @NotEmpty
diff --git a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 62058ba..d6fa8df 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -172,7 +172,7 @@
 
     <!-- Authorization server metadata, published at /.well-known/oauth-authorization-server. -->
     <bean id="openidvci.DefaultAuthorizationServerMetadataResolver" lazy-init="true"
-        class="org.geant.shibboleth.plugin.openidvci.metadata.impl.FilesystemMetadataDocumentResolver"
+        class="org.geant.shibboleth.plugin.openidvci.metadata.impl.FilesystemAuthorizationServerMetadataResolver"
         depends-on="shibboleth.LoggingService"
         p:id="openidvci.DefaultAuthorizationServerMetadataResolver"
         p:minRefreshDelay="%{openidvci.authorizationServer.minRefreshDelay:PT5M}"
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 2445724..9462320 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
@@ -11,10 +11,14 @@
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
        default-init-method="initialize" default-destroy-method="destroy">
 
-  <bean id="openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/oauth/authorization-server"/>
+  <bean id="openidvci.profileId" class="java.lang.String"
+        c:_0="#{T(org.geant.shibboleth.plugin.openidvci.profile.config.impl.DefaultMetadataDocumentConfiguration).PROFILE_ID_AUTHORIZATION_SERVER}"/>
   <bean id="openidvci.loggingId" class="java.lang.String"
         c:_0="%{openidvci.logging.authorization-server:OAuth.AuthorizationServer}"/>
 
+  <util:constant id="shibboleth.metrics.ProfileCounter"
+        static-field="org.geant.shibboleth.plugin.openidvci.profile.config.impl.DefaultMetadataDocumentConfiguration.PROFILE_COUNTER_AUTHORIZATION_SERVER"/>
+
   <bean id="InitializeUnverifiedRelyingPartyContext"
         class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext" scope="prototype" />
 
@@ -22,7 +26,8 @@
         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:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:cacheControl="%{openidvci.authorizationServer.cacheControl:max-age=3600}" />
 
   <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent"
         scope="prototype" p:defaultStatusCode="500" p:defaultCode="server_error"
@@ -30,12 +35,6 @@
     <property name="eventContextLookupStrategy">
       <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
     </property>
-    <property name="mappedErrors">
-      <map value-type="com.nimbusds.oauth2.sdk.ErrorObject">
-        <entry key="#{T(org.opensaml.profile.action.EventIds).IO_ERROR}"
-               value="#{T(com.nimbusds.oauth2.sdk.OAuth2Error).SERVER_ERROR}" />
-      </map>
-    </property>
   </bean>
 
 </beans>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-flow.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-flow.xml
index 984ad55..ba025ac 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-flow.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-flow.xml
@@ -5,6 +5,9 @@
       parent="openid/vci/abstract-api">
 
   <action-state id="InitializeMandatoryContexts">
+    <on-entry>
+      <set name="flowScope.transitionAfterInboundIntercept" value="'BuildResponseMessage'"/>
+    </on-entry>
     <evaluate expression="InitializeProfileRequestContext" />
     <evaluate expression="PopulateMetricContext" />
     <evaluate expression="FlowStartPopulateAuditContext" />
@@ -12,9 +15,10 @@
     <evaluate expression="InitializeUnverifiedRelyingPartyContext" />
     <evaluate expression="SelectRelyingPartyConfiguration" />
     <evaluate expression="SelectProfileConfiguration" />
+    <evaluate expression="PopulateInboundInterceptContext" />
     <evaluate expression="'proceed'" />
 
-    <transition on="proceed" to="BuildResponseMessage" />
+    <transition on="proceed" to="CheckInboundInterceptContext" />
   </action-state>
 
   <bean-import resource="classpath:/META-INF/net/shibboleth/idp/flows/oauth/authorization-server/authorization-server-beans.xml" />
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 fa7c9c6..1e3d64f 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
@@ -104,11 +104,14 @@ openidvci.status-list.index.permutationKey = change_this_to_secret
 # /.well-known/oauth-authorization-server. A wallet reads that document to find the endpoints of
 # the authorization server this deployment is.
 #openidvci.authorizationServer.template = %{idp.home}/static/oauth-authorization-server.json
+# The template is Velocity as above. Set false if the document contains literal '$' or '#'.
 #openidvci.authorizationServer.templated = true
 #openidvci.authorizationServer.resolver = openidvci.DefaultAuthorizationServerMetadataResolver
 # Bounds on the next file refresh of the document
 #openidvci.authorizationServer.minRefreshDelay = PT5M
 #openidvci.authorizationServer.maxRefreshDelay = PT4H
+# Cache-Control of the response
+#openidvci.authorizationServer.cacheControl = max-age=3600
 
 # Settings for stating this deployment as a Credential Issuer in OpenID Federation. Active
 # only when conf/openid-vci-oidfed.xml is imported into conf/global.xml. Set to false to
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemAuthorizationServerMetadataResolverTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemAuthorizationServerMetadataResolverTest.java
new file mode 100644
index 0000000..8f8cb51
--- /dev/null
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemAuthorizationServerMetadataResolverTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.metadata.impl;
+
+import java.nio.charset.StandardCharsets;
+
+import org.geant.shibboleth.plugin.openidvci.metadata.MetadataDocument;
+import org.springframework.core.io.ClassPathResource;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import net.shibboleth.shared.component.ComponentInitializationException;
+
+/**
+ * Unit tests for {@link FilesystemAuthorizationServerMetadataResolver}.
+ */
+public class FilesystemAuthorizationServerMetadataResolverTest {
+
+    private static final String TEMPLATE =
+            "org/geant/shibboleth/plugin/openidvci/static/oauth-authorization-server.json";
+
+    private static final String ISSUER = "\"issuer\":\"https://example.org\"";
+
+    private static final String AUTHORIZATION_ENDPOINT =
+            ",\"authorization_endpoint\":\"https://example.org/authorize\"";
+
+    private static final String TOKEN_ENDPOINT = ",\"token_endpoint\":\"https://example.org/token\"";
+
+    private static final String RESPONSE_TYPES = ",\"response_types_supported\":[\"code\"]";
+
+    private static final String GRANT_TYPES = ",\"grant_types_supported\":[\"authorization_code\","
+            + "\"urn:ietf:params:oauth:grant-type:pre-authorized_code\"]";
+
+    private static final String REQUIRED = ISSUER + AUTHORIZATION_ENDPOINT + TOKEN_ENDPOINT + RESPONSE_TYPES
+            + GRANT_TYPES;
+
+    private FilesystemAuthorizationServerMetadataResolver resolverOf(final String content, final boolean templated)
+            throws Exception {
+        final FilesystemAuthorizationServerMetadataResolver resolver =
+                new FilesystemAuthorizationServerMetadataResolver(
+                        FilesystemMetadataDocumentResolverTest.fileOf(content));
+        resolver.setId("test");
+        if (templated) {
+            resolver.setVelocityEngine(FilesystemMetadataDocumentResolverTest.velocityEngine());
+            resolver.setIssuer("https://issuer.example.org");
+        }
+        resolver.initialize();
+        return resolver;
+    }
+
+    @Test
+    public void testShippedTemplate() throws Exception {
+        final String template =
+                new String(new ClassPathResource(TEMPLATE).getInputStream().readAllBytes(), StandardCharsets.UTF_8);
+        final MetadataDocument document = resolverOf(template, true).resolveSingle(null);
+
+        Assert.assertNotNull(document);
+        Assert.assertEquals(document.getIssuer().getValue(), "https://issuer.example.org");
+        Assert.assertEquals(document.getMembers().get(FilesystemAuthorizationServerMetadataResolver.TOKEN_ENDPOINT),
+                "https://issuer.example.org/idp/profile/openid/vci/token");
+    }
+
+    @Test
+    public void testExtraMembersKept() throws Exception {
+        final MetadataDocument document = resolverOf("{" + REQUIRED
+                + ",\"client_attestation_pop_signing_alg_values_supported\":[\"ES256\"]"
+                + ",\"authorization_details_types_supported\":[\"openid_credential\"]}", false).resolveSingle(null);
+
+        Assert.assertNotNull(document);
+        Assert.assertTrue(document.getMembers().containsKey("client_attestation_pop_signing_alg_values_supported"));
+        Assert.assertTrue(document.getMembers().containsKey("authorization_details_types_supported"));
+    }
+
+    @Test
+    public void testPreAuthorizedOnlyNeedsNoAuthorizationEndpointNorResponseTypes() throws Exception {
+        final MetadataDocument document = resolverOf("{" + ISSUER + TOKEN_ENDPOINT
+                + ",\"grant_types_supported\":[\"urn:ietf:params:oauth:grant-type:pre-authorized_code\"]}", false)
+                .resolveSingle(null);
+
+        Assert.assertNotNull(document);
+    }
+
+    @DataProvider
+    public Object[][] invalidDocuments() {
+        return new Object[][] {
+            {"{" + ISSUER + TOKEN_ENDPOINT + RESPONSE_TYPES + GRANT_TYPES + "}"},
+            {"{" + ISSUER + AUTHORIZATION_ENDPOINT + RESPONSE_TYPES + GRANT_TYPES + "}"},
+            {"{" + ISSUER + AUTHORIZATION_ENDPOINT + TOKEN_ENDPOINT + GRANT_TYPES + "}"},
+            {"{" + ISSUER + AUTHORIZATION_ENDPOINT + TOKEN_ENDPOINT + RESPONSE_TYPES + "}"},
+            {"{" + ISSUER + AUTHORIZATION_ENDPOINT + TOKEN_ENDPOINT + RESPONSE_TYPES
+                    + ",\"grant_types_supported\":[\"authorization_code\",\"implicit\"]}"},
+            {"{" + ISSUER + AUTHORIZATION_ENDPOINT + TOKEN_ENDPOINT + GRANT_TYPES
+                    + ",\"response_types_supported\":\"code\"}"},
+            {"{" + REQUIRED + ",\"pushed_authorization_request_endpoint\":\"http://example.org/par\"}"},
+            {"{" + REQUIRED + ",\"pushed_authorization_request_endpoint\":\"/idp/profile/oauth2/par\"}"},
+            {"{" + REQUIRED + ",\"jwks_uri\":\"https://exa mple.org/keyset\"}"},
+            {"{" + REQUIRED + ",\"jwks_uri\":[\"https://example.org/keyset\"]}"},
+        };
+    }
+
+    @Test(dataProvider = "invalidDocuments")
+    public void testInvalid(final String content) {
+        Assert.assertThrows(ComponentInitializationException.class, () -> resolverOf(content, false));
+    }
+
+}
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfigurationTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfigurationTest.java
index 7fa7185..a911591 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfigurationTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/config/impl/DefaultMetadataDocumentConfigurationTest.java
@@ -47,6 +47,14 @@ public class DefaultMetadataDocumentConfigurationTest {
                 DefaultMetadataDocumentConfiguration.PROFILE_ID_DID_DOCUMENT).size(), 3);
     }
 
+    @Test
+    public void testCountersAreDistinct() {
+        Assert.assertEquals(DefaultMetadataDocumentConfiguration.PROFILE_COUNTER_AUTHORIZATION_SERVER,
+                "net.shibboleth.idp.profiles.oauth.authorization-server");
+        Assert.assertNotEquals(DefaultMetadataDocumentConfiguration.PROFILE_COUNTER_AUTHORIZATION_SERVER,
+                DefaultMetadataDocumentConfiguration.PROFILE_COUNTER_JWT_VC_ISSUER);
+    }
+
     @Test
     public void testDidDocumentId() {
         Assert.assertEquals(new DefaultDidDocumentConfiguration().getId(),

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


More information about the commits mailing list