[java-idp-plugin-vci] branch dev/REVISSFLOW updated: Credential Issuer metadata, check issuer, endpoints and authorization_servers at load. Common url checks. Warn if nonce_endpoint is missing (should not, we have it) but key binding is there

Codeberg noreply at shibboleth.net
Fri Nov 6 13:13:24 UTC 2026


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

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

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

The following commit(s) were added to refs/heads/dev/REVISSFLOW by this push:
     new 208cbdc  Credential Issuer metadata, check issuer, endpoints and authorization_servers at load. Common url checks. Warn if nonce_endpoint is missing (should not, we have it) but key binding is there
208cbdc is described below

commit 208cbdceccf1b6588e4076ae407f496348dd64af
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Fri Nov 6 15:13:04 2026 +0200

    Credential Issuer metadata, check issuer, endpoints and authorization_servers at load. Common url checks. Warn if nonce_endpoint is missing (should not, we have it) but key binding is there
---
 README.md                                          | 12 ++-
 .../metadata/CredentialIssuerMetadata.java         |  1 +
 .../openidvci/metadata/MetadataDocument.java       | 33 +-------
 .../openidvci/metadata/MetadataUrlSupport.java     | 88 ++++++++++++++++++++++
 .../metadata/CredentialIssuerMetadataTest.java     | 30 ++++++++
 ...FilesystemCredentialIssuerMetadataResolver.java | 39 ++++++++++
 ...esystemAuthorizationServerMetadataResolver.java | 29 +------
 ...FilesystemCredentialIssuerMetadataResolver.java | 35 ++++++++-
 ...systemCredentialIssuerMetadataResolverTest.java | 64 +++++++++++++---
 9 files changed, 258 insertions(+), 73 deletions(-)

diff --git a/README.md b/README.md
index dd4f8c1..62cadc8 100644
--- a/README.md
+++ b/README.md
@@ -5065,8 +5065,16 @@ The authorization server metadata URL includes the same path. In this example, i
 The JWT VC issuer metadata names one issuer. A credential whose issuer is a URL other than `idp.oidc.issuer` must be verified using `x5c`.
 Otherwise, change the `issuer` value in the template to match that URL.
 The plugin adds `credential_configurations_supported` from *metadata/verifiable-credentials.json*.
-The Credential Issuer metadata endpoint returns `500 server_error` if either
-`credential_endpoint` or `credential_configurations_supported` is missing.
+The Credential Issuer metadata endpoint returns `500 server_error` if any of the following
+conditions apply:
+
+- `credential_endpoint` or `credential_configurations_supported` is missing.
+- `credential_issuer` is not an HTTPS URL with a host, or has a query, a fragment or a dot-segment.
+- An endpoint is not an HTTPS URL with a host.
+- `authorization_servers` is not a non-empty array of such issuer URLs.
+
+If a configuration lists `cryptographic_binding_methods_supported` and the metadata has no
+`nonce_endpoint`, the IdP logs a warning. HAIP requires the nonce endpoint in that case.
 `batch_credential_issuance.batch_size` in the Credential Issuer metadata sets the maximum number
 of proofs a credential request may contain. It overrides the profile’s `batchSize` setting.
 
diff --git a/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadata.java b/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadata.java
index b1d1c84..f998987 100644
--- a/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadata.java
+++ b/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadata.java
@@ -155,6 +155,7 @@ public final class CredentialIssuerMetadata {
             throw new ParseException(
                     "Credential Issuer metadata must have a non empty '" + CREDENTIAL_ISSUER + "' member");
         }
+        MetadataUrlSupport.validateIssuer((String) issuer);
         return new CredentialIssuerMetadata(Collections.unmodifiableMap(new LinkedHashMap<>(members)),
                 new Issuer((String) issuer), parseBatchSize(members));
     }
diff --git a/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataDocument.java b/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataDocument.java
index e39018b..57e1e4a 100644
--- a/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataDocument.java
+++ b/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataDocument.java
@@ -16,8 +16,6 @@
 
 package org.geant.shibboleth.plugin.openidvci.metadata;
 
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -93,37 +91,8 @@ public final class MetadataDocument {
         if (!(members.get(ISSUER) instanceof String value) || value.isEmpty()) {
             throw new ParseException("Metadata document must have a non empty '" + ISSUER + "' member");
         }
-        validateIssuer(value);
+        MetadataUrlSupport.validateIssuer(value);
         return new MetadataDocument(Collections.unmodifiableMap(new LinkedHashMap<>(members)), new Issuer(value));
     }
 
-    /**
-     * Check the issuer is an https url with a host, no query, no fragment and no dot-segments.
-     *
-     * @param value issuer
-     * @throws ParseException if the issuer is not such a url
-     */
-    private static void validateIssuer(@Nonnull final String value) throws ParseException {
-
-        final URI uri;
-        try {
-            uri = new URI(value);
-        } catch (final URISyntaxException e) {
-            throw new ParseException("Issuer '" + value + "' is not a url", e);
-        }
-        if (!"https".equals(uri.getScheme()) || uri.getHost() == null) {
-            throw new ParseException("Issuer '" + value + "' is not an https url with a host");
-        }
-        if (uri.getRawQuery() != null || uri.getRawFragment() != null) {
-            throw new ParseException("Issuer '" + value + "' has a query or a fragment");
-        }
-        if (uri.getRawPath() != null) {
-            for (final String segment : uri.getRawPath().split("/", -1)) {
-                if (".".equals(segment) || "..".equals(segment)) {
-                    throw new ParseException("Issuer '" + value + "' has a dot-segment in its path");
-                }
-            }
-        }
-    }
-
 }
diff --git a/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataUrlSupport.java b/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataUrlSupport.java
new file mode 100644
index 0000000..f34e63e
--- /dev/null
+++ b/openid-vci-api/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/MetadataUrlSupport.java
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+
+/**
+ * Checks of the urls published in metadata documents.
+ */
+public final class MetadataUrlSupport {
+
+    /** Constructor. */
+    private MetadataUrlSupport() {
+    }
+
+    /**
+     * Check the issuer is an https url with a host, no query, no fragment and no dot-segments.
+     *
+     * @param value issuer
+     * @throws ParseException if the issuer is not such a url
+     */
+    public static void validateIssuer(@Nonnull final String value) throws ParseException {
+
+        final URI uri;
+        try {
+            uri = new URI(value);
+        } catch (final URISyntaxException e) {
+            throw new ParseException("Issuer '" + value + "' is not a url", e);
+        }
+        if (!"https".equals(uri.getScheme()) || uri.getHost() == null) {
+            throw new ParseException("Issuer '" + value + "' is not an https url with a host");
+        }
+        if (uri.getRawQuery() != null || uri.getRawFragment() != null) {
+            throw new ParseException("Issuer '" + value + "' has a query or a fragment");
+        }
+        if (uri.getRawPath() != null) {
+            for (final String segment : uri.getRawPath().split("/", -1)) {
+                if (".".equals(segment) || "..".equals(segment)) {
+                    throw new ParseException("Issuer '" + value + "' has a dot-segment in its path");
+                }
+            }
+        }
+    }
+
+    /**
+     * Check the value of a member 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
+     */
+    public 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-api/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadataTest.java b/openid-vci-api/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadataTest.java
index 2d5985a..1f730f6 100644
--- a/openid-vci-api/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadataTest.java
+++ b/openid-vci-api/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/CredentialIssuerMetadataTest.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.testng.Assert;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import com.nimbusds.oauth2.sdk.ParseException;
@@ -96,6 +97,35 @@ public class CredentialIssuerMetadataTest {
         Assert.assertThrows(ParseException.class, () -> CredentialIssuerMetadata.parse(members));
     }
 
+    @DataProvider
+    public Object[][] invalidIssuers() {
+        return new Object[][] {
+            {"http://example.org"},
+            {"example.org"},
+            {"https://example.org?tenant=a"},
+            {"https://example.org#a"},
+            {"https://example.org/a/../b"},
+            {"$baseUrl"},
+        };
+    }
+
+    @Test(dataProvider = "invalidIssuers")
+    public void testInvalidCredentialIssuer(final String issuer) {
+        final Map<String, Object> members = members();
+        members.put(CredentialIssuerMetadata.CREDENTIAL_ISSUER, issuer);
+
+        Assert.assertThrows(ParseException.class, () -> CredentialIssuerMetadata.parse(members));
+    }
+
+    @Test
+    public void testCredentialIssuerWithPath() throws ParseException {
+        final Map<String, Object> members = members();
+        members.put(CredentialIssuerMetadata.CREDENTIAL_ISSUER, "https://example.org/tenant");
+
+        Assert.assertEquals(CredentialIssuerMetadata.parse(members).getCredentialIssuer().getValue(),
+                "https://example.org/tenant");
+    }
+
     @Test
     public void testEmptyCredentialIssuer() {
         final Map<String, Object> members = members();
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolver.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolver.java
index ec8df37..269577a 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolver.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolver.java
@@ -45,6 +45,14 @@ import net.shibboleth.shared.resolver.ResolverException;
  */
 public class DynamicFilesystemCredentialIssuerMetadataResolver extends FilesystemCredentialIssuerMetadataResolver {
 
+    /** Name of the member naming the nonce endpoint. */
+    @Nonnull
+    private static final String NONCE_ENDPOINT = "nonce_endpoint";
+
+    /** Name of the member listing the key binding methods of a Credential Configuration. */
+    @Nonnull
+    private static final String BINDING_METHODS = "cryptographic_binding_methods_supported";
+
     /** Class logger. */
     @Nonnull
     private final Logger log = LoggerFactory.getLogger(DynamicFilesystemCredentialIssuerMetadataResolver.class);
@@ -53,6 +61,10 @@ public class DynamicFilesystemCredentialIssuerMetadataResolver extends Filesyste
     @Nonnull
     private Map<String, ? extends CredentialIssuerMetadataValueResolver> dynamicResolvers = new HashMap<>();
 
+    /** Update time of the document last checked for profile rules. */
+    @Nullable
+    private volatile Instant checkedUpdate;
+
     /**
      * Constructor.
      *
@@ -98,6 +110,7 @@ public class DynamicFilesystemCredentialIssuerMetadataResolver extends Filesyste
                 }
             }
 
+            checkProfileRules(members);
             try {
                 result.add(CredentialIssuerMetadata.parse(members));
             } catch (final ParseException e) {
@@ -107,6 +120,32 @@ public class DynamicFilesystemCredentialIssuerMetadataResolver extends Filesyste
         return result;
     }
 
+    /**
+     * Warn once per change of the document when it misses a member HAIP requires.
+     *
+     * @param members members of the document, dynamic ones included
+     */
+    private void checkProfileRules(@Nonnull final Map<String, Object> members) {
+        final Instant updated = getMetadataUpdateTime();
+        if (updated == null || updated.equals(checkedUpdate)) {
+            return;
+        }
+        checkedUpdate = updated;
+
+        final Object configurations = members.get(CredentialIssuerMetadata.CREDENTIAL_CONFIGURATIONS_SUPPORTED);
+        if (members.containsKey(NONCE_ENDPOINT) || !(configurations instanceof Map<?, ?> all)) {
+            return;
+        }
+        for (final Object configuration : all.values()) {
+            if (configuration instanceof Map<?, ?> map
+                    && map.get(BINDING_METHODS) instanceof List<?> methods && !methods.isEmpty()) {
+                log.warn("{} Credential Configurations use key binding but the metadata has no '{}', HAIP requires it",
+                        getLogPrefix(), NONCE_ENDPOINT);
+                return;
+            }
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     protected Instant getMetadataUpdateTime() {
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
index bf909e2..991e440 100644
--- 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
@@ -17,15 +17,13 @@
 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.geant.shibboleth.plugin.openidvci.metadata.MetadataUrlSupport;
 import org.springframework.core.io.Resource;
 
 import com.nimbusds.oauth2.sdk.GrantType;
@@ -108,33 +106,10 @@ public class FilesystemAuthorizationServerMetadataResolver extends FilesystemMet
         }
         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());
+                MetadataUrlSupport.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/metadata/impl/FilesystemCredentialIssuerMetadataResolver.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemCredentialIssuerMetadataResolver.java
index a2f78dd..29a633f 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemCredentialIssuerMetadataResolver.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/FilesystemCredentialIssuerMetadataResolver.java
@@ -16,11 +16,13 @@
 package org.geant.shibboleth.plugin.openidvci.metadata.impl;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
 
 import org.geant.shibboleth.plugin.openidvci.metadata.CredentialIssuerMetadata;
+import org.geant.shibboleth.plugin.openidvci.metadata.MetadataUrlSupport;
 import org.geant.shibboleth.plugin.openidvci.metadata.resolver.CredentialIssuerMetadataResolver;
 import org.springframework.core.io.Resource;
 
@@ -35,6 +37,14 @@ public class FilesystemCredentialIssuerMetadataResolver
         extends AbstractTemplatedFileMetadataResolver<CredentialIssuerMetadata>
         implements CredentialIssuerMetadataResolver {
 
+    /** Name of the member listing the authorization servers. */
+    @Nonnull
+    public static final String AUTHORIZATION_SERVERS = "authorization_servers";
+
+    /** Suffix of the members naming an endpoint. */
+    @Nonnull
+    private static final String ENDPOINT_SUFFIX = "_endpoint";
+
     /**
      * Constructor.
      *
@@ -50,7 +60,30 @@ public class FilesystemCredentialIssuerMetadataResolver
     @Override
     @Nonnull
     protected CredentialIssuerMetadata fromMembers(@Nonnull final Map<String, Object> members) throws ParseException {
-        return CredentialIssuerMetadata.parse(members);
+        final CredentialIssuerMetadata metadata = CredentialIssuerMetadata.parse(members);
+
+        if (!members.containsKey(CredentialIssuerMetadata.CREDENTIAL_ENDPOINT)) {
+            throw new ParseException("Credential Issuer metadata has no '"
+                    + CredentialIssuerMetadata.CREDENTIAL_ENDPOINT + "'");
+        }
+        for (final Map.Entry<String, Object> member : members.entrySet()) {
+            if (member.getKey().endsWith(ENDPOINT_SUFFIX)) {
+                MetadataUrlSupport.validateHttpsUrl(member.getKey(), member.getValue());
+            }
+        }
+        final Object servers = members.get(AUTHORIZATION_SERVERS);
+        if (servers != null) {
+            if (!(servers instanceof List<?> list) || list.isEmpty()) {
+                throw new ParseException("'" + AUTHORIZATION_SERVERS + "' is not a non empty array");
+            }
+            for (final Object server : list) {
+                if (!(server instanceof String value)) {
+                    throw new ParseException("'" + AUTHORIZATION_SERVERS + "' has a member that is not a string");
+                }
+                MetadataUrlSupport.validateIssuer(value);
+            }
+        }
+        return metadata;
     }
 
     /** {@inheritDoc} */
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolverTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolverTest.java
index 2f29f9a..b73d5c3 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolverTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/metadata/impl/DynamicFilesystemCredentialIssuerMetadataResolverTest.java
@@ -30,6 +30,7 @@ import org.geant.shibboleth.plugin.openidvci.metadata.resolver.RefreshableCreden
 import org.opensaml.profile.context.ProfileRequestContext;
 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;
@@ -200,22 +201,63 @@ public class DynamicFilesystemCredentialIssuerMetadataResolverTest {
     }
 
     @Test
-    public void testTemplateIsNotEvaluatedWithoutAnEngine() throws Exception {
-        final CredentialIssuerMetadata metadata = resolverOf("metadata/openid-credential-issuer-template.json", null)
-                .resolveSingle(null);
+    public void testTemplateIsNotEvaluatedWithoutAnEngine() {
+        Assert.assertThrows(ComponentInitializationException.class,
+                () -> resolverOf("metadata/openid-credential-issuer-template.json", null));
+    }
 
-        Assert.assertNotNull(metadata);
-        Assert.assertEquals(metadata.getCredentialIssuer().getValue(), "$baseUrl");
+    @Test
+    public void testUnresolvedReferenceIsRefused() {
+        Assert.assertThrows(ComponentInitializationException.class, () -> templatedResolverOf(
+                "metadata/openid-credential-issuer-unresolved.json", "https://example.org"));
+    }
+
+    @DataProvider
+    public Object[][] invalidDocuments() {
+        return new Object[][] {
+            {"{\"credential_issuer\":\"https://example.org\"}"},
+            {"{\"credential_issuer\":\"https://example.org\","
+                    + "\"credential_endpoint\":\"http://example.org/credentials\"}"},
+            {"{\"credential_issuer\":\"https://example.org\","
+                    + "\"credential_endpoint\":\"/idp/profile/openid/vci/credentials\"}"},
+            {"{\"credential_issuer\":\"https://example.org\","
+                    + "\"credential_endpoint\":\"https://example.org/credentials\","
+                    + "\"nonce_endpoint\":\"http://example.org/nonce\"}"},
+            {"{\"credential_issuer\":\"https://example.org\","
+                    + "\"credential_endpoint\":\"https://example.org/credentials\","
+                    + "\"authorization_servers\":\"https://example.org\"}"},
+            {"{\"credential_issuer\":\"https://example.org\","
+                    + "\"credential_endpoint\":\"https://example.org/credentials\","
+                    + "\"authorization_servers\":[]}"},
+            {"{\"credential_issuer\":\"https://example.org\","
+                    + "\"credential_endpoint\":\"https://example.org/credentials\","
+                    + "\"authorization_servers\":[\"http://as.example.org\"]}"},
+        };
+    }
+
+    @Test(dataProvider = "invalidDocuments")
+    public void testInvalid(final String content) {
+        Assert.assertThrows(ComponentInitializationException.class, () -> {
+            final DynamicFilesystemCredentialIssuerMetadataResolver resolver =
+                    new DynamicFilesystemCredentialIssuerMetadataResolver(
+                            FilesystemMetadataDocumentResolverTest.fileOf(content));
+            resolver.setId("test");
+            resolver.initialize();
+        });
     }
 
     @Test
-    public void testUnresolvedReferenceIsLeftInPlace() throws Exception {
-        final CredentialIssuerMetadata metadata = templatedResolverOf(
-                "metadata/openid-credential-issuer-unresolved.json", "https://example.org").resolveSingle(null);
+    public void testAuthorizationServersAndEndpoints() throws Exception {
+        final DynamicFilesystemCredentialIssuerMetadataResolver resolver =
+                new DynamicFilesystemCredentialIssuerMetadataResolver(FilesystemMetadataDocumentResolverTest.fileOf(
+                        "{\"credential_issuer\":\"https://example.org\","
+                                + "\"credential_endpoint\":\"https://example.org/credentials\","
+                                + "\"nonce_endpoint\":\"https://example.org/nonce\","
+                                + "\"authorization_servers\":[\"https://as.example.org\"]}"));
+        resolver.setId("test");
+        resolver.initialize();
 
-        Assert.assertNotNull(metadata);
-        Assert.assertEquals(metadata.getMembers().get(CredentialIssuerMetadata.CREDENTIAL_ENDPOINT),
-                "$notAVariable/credentials");
+        Assert.assertNotNull(resolver.resolveSingle(null));
     }
 
     @Test

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


More information about the commits mailing list