From 408f402c2800e03be79fd819f0d2d8c6589f7f04 Mon Sep 17 00:00:00 2001 From: Benjamin SCHOLTES Date: Thu, 5 Sep 2024 17:29:08 +0200 Subject: [PATCH] feat: enable defining supported VC types for trusted issuers --- .../DefaultTrustedIssuerRegistry.java | 22 ++++--- .../DefaultTrustedIssuerRegistryTest.java | 34 +++-------- .../TrustedIssuerConfigurationExtension.java | 23 +++++--- ...ustedIssuerConfigurationExtensionTest.java | 23 ++++++-- ...fiableCredentialValidationServiceImpl.java | 6 +- .../rules/HasValidIssuer.java | 22 ++++--- ...leCredentialValidationServiceImplTest.java | 9 +-- .../rules/HasValidIssuerTest.java | 58 ++++++++++++------- .../spi/validation/TrustedIssuerRegistry.java | 23 ++++++-- 9 files changed, 120 insertions(+), 100 deletions(-) diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistry.java b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistry.java index 6e08ba01804..55bfe7dd896 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistry.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistry.java @@ -17,28 +17,26 @@ import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer; import org.eclipse.edc.iam.verifiablecredentials.spi.validation.TrustedIssuerRegistry; -import java.util.Collection; -import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** - * Simple, memory-based implementation of a {@link TrustedIssuerRegistry} + * Simple, memory-based implementation of a {@link TrustedIssuerRegistry}. */ public class DefaultTrustedIssuerRegistry implements TrustedIssuerRegistry { - private final Map store = new HashMap<>(); - @Override - public void addIssuer(Issuer issuer) { - store.put(issuer.id(), issuer); - } + private final Map> store = new ConcurrentHashMap<>(); @Override - public Issuer getById(String id) { - return store.get(id); + public void register(Issuer issuer, String credentialType) { + store.computeIfAbsent(issuer.id(), k -> new HashSet<>()).add(credentialType); } @Override - public Collection getTrustedIssuers() { - return store.values(); + public Set getSupportedTypes(Issuer issuer) { + return store.getOrDefault(issuer.id(), Set.of()); } + } diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistryTest.java b/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistryTest.java index 21e99ea6017..78c3ff8a3fa 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistryTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultTrustedIssuerRegistryTest.java @@ -26,40 +26,20 @@ class DefaultTrustedIssuerRegistryTest { private final DefaultTrustedIssuerRegistry registry = new DefaultTrustedIssuerRegistry(); @Test - void addIssuer() { + void trustedIssuer() { var issuer = new Issuer("test-id", Map.of()); - registry.addIssuer(issuer); - assertThat(registry.getTrustedIssuers()).containsExactly(issuer); - } - - @Test - void addIssuer_exists_shouldReplace() { - var issuer = new Issuer("test-id", Map.of()); - var issuer2 = new Issuer("test-id", Map.of("new-key", "new-val")); - registry.addIssuer(issuer); - registry.addIssuer(issuer2); - assertThat(registry.getTrustedIssuers()).containsExactly(issuer2); - } - @Test - void getById() { - var issuer = new Issuer("test-id", Map.of()); - registry.addIssuer(issuer); - assertThat(registry.getById("test-id")).isEqualTo(issuer); - } + registry.register(issuer, "test-type1"); + registry.register(issuer, "test-type2"); - @Test - void getById_notFound() { - assertThat(registry.getById("nonexistent-id")).isNull(); + assertThat(registry.getSupportedTypes(issuer)).containsExactly("test-type1", "test-type2"); } @Test - void getTrustedIssuers() { + void invalidIssuer() { var issuer = new Issuer("test-id", Map.of()); - var issuer2 = new Issuer("test-id2", Map.of("new-key", "new-val")); - registry.addIssuer(issuer); - registry.addIssuer(issuer2); - assertThat(registry.getTrustedIssuers()).containsExactlyInAnyOrder(issuer2, issuer); + assertThat(registry.getSupportedTypes(issuer)).isEmpty(); } + } \ No newline at end of file diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java index 6f41f84ae34..fcaa47d1893 100644 --- a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java @@ -26,6 +26,7 @@ import org.eclipse.edc.spi.system.configuration.Config; import org.eclipse.edc.spi.types.TypeManager; +import java.util.List; import java.util.Map; import static org.eclipse.edc.iam.identitytrust.issuer.configuration.TrustedIssuerConfigurationExtension.NAME; @@ -39,10 +40,12 @@ public class TrustedIssuerConfigurationExtension implements ServiceExtension { public static final String CONFIG_PREFIX = "edc.iam.trusted-issuer"; public static final String CONFIG_ALIAS = CONFIG_PREFIX + ".."; - @Setting(context = CONFIG_ALIAS, value = "Additional properties of the issuer.") - public static final String PROPERTIES_SUFFIX = "properties"; @Setting(context = CONFIG_ALIAS, value = "ID of the issuer.", required = true) public static final String ID_SUFFIX = "id"; + @Setting(context = CONFIG_ALIAS, value = "Additional properties of the issuer.") + public static final String PROPERTIES_SUFFIX = "properties"; + @Setting(context = CONFIG_ALIAS, value = "List of supported credential types for this issuer.") + public static final String SUPPORTEDTYPES_SUFFIX = "supportedtypes"; protected static final String NAME = "Trusted Issuers Configuration Extensions"; @@ -56,19 +59,23 @@ public class TrustedIssuerConfigurationExtension implements ServiceExtension { @Override public void initialize(ServiceExtensionContext context) { var config = context.getConfig(CONFIG_PREFIX); - var issuers = config.partition().map(this::configureIssuer).toList(); - if (issuers.isEmpty()) { + var configs = config.partition().toList(); + if (configs.isEmpty()) { monitor.warning("The list of trusted issuers is empty"); } - issuers.forEach(issuer -> trustedIssuerRegistry.addIssuer(issuer)); - } - private Issuer configureIssuer(Config config) { + configs.forEach(this::addIssuer); + } + private void addIssuer(Config config) { var id = config.getString(ID_SUFFIX); + var supportedTypesConfig = config.getString(SUPPORTEDTYPES_SUFFIX, "[\"%s\"]".formatted(TrustedIssuerRegistry.WILDCARD)); + var supportedTypes = typeManager.readValue(supportedTypesConfig, new TypeReference>() { + }); var propertiesConfig = config.getString(PROPERTIES_SUFFIX, "{}"); var properties = typeManager.readValue(propertiesConfig, new TypeReference>() { }); - return new Issuer(id, properties); + + supportedTypes.forEach(type -> trustedIssuerRegistry.register(new Issuer(id, properties), type)); } } diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java index 008c68f16e0..35b2095f1f3 100644 --- a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/iam/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java @@ -30,7 +30,9 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -49,13 +51,24 @@ void setup(ServiceExtensionContext context) { } @Test - void initialize(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { - var cfg = ConfigFactory.fromMap(Map.of("issuer1.id", "issuerId1")); + void initialize_issuerWithSupportedTypes(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { + var cfg = ConfigFactory.fromMap(Map.of("issuer1.id", "issuer1", "issuer1.supportedtypes", "[\"type1\", \"type2\"]")); when(context.getConfig("edc.iam.trusted-issuer")).thenReturn(cfg); ext.initialize(context); - verify(trustedIssuerRegistry).addIssuer(argThat(issuer -> issuer.id().equals("issuerId1"))); + verify(trustedIssuerRegistry).register(argThat(issuer -> issuer.id().equals("issuer1")), eq("type1")); + verify(trustedIssuerRegistry).register(argThat(issuer -> issuer.id().equals("issuer1")), eq("type1")); + } + + @Test + void initialize_issuerWithoutSupportedType(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { + var cfg = ConfigFactory.fromMap(Map.of("issuer1.id", "issuer1")); + when(context.getConfig("edc.iam.trusted-issuer")).thenReturn(cfg); + + ext.initialize(context); + + verify(trustedIssuerRegistry).register(argThat(issuer -> issuer.id().equals("issuer1")), eq(TrustedIssuerRegistry.WILDCARD)); } @Test @@ -79,7 +92,7 @@ void initialize_withProperties(ServiceExtensionContext context, TrustedIssuerCon ext.initialize(context); - verify(trustedIssuerRegistry).addIssuer(argThat(issuer -> issuer.additionalProperties().get("custom").equals("test"))); + verify(trustedIssuerRegistry).register(argThat(issuer -> issuer.additionalProperties().get("custom").equals("test")), eq(TrustedIssuerRegistry.WILDCARD)); } @Test @@ -91,7 +104,7 @@ void initialize_withTwoIssuers(ServiceExtensionContext context, TrustedIssuerCon var issuers = ArgumentCaptor.forClass(Issuer.class); - verify(trustedIssuerRegistry, times(2)).addIssuer(issuers.capture()); + verify(trustedIssuerRegistry, times(2)).register(issuers.capture(), any()); assertThat(issuers.getAllValues()).hasSize(2) .extracting(Issuer::id) diff --git a/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImpl.java b/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImpl.java index 5053d14d103..6a8a9ff5438 100644 --- a/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImpl.java +++ b/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImpl.java @@ -19,7 +19,6 @@ import org.eclipse.edc.iam.verifiablecredentials.rules.IsInValidityPeriod; import org.eclipse.edc.iam.verifiablecredentials.rules.IsNotRevoked; import org.eclipse.edc.iam.verifiablecredentials.spi.VerifiableCredentialValidationService; -import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer; import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry; import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential; import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiablePresentationContainer; @@ -68,7 +67,7 @@ private Result validateVerifiableCredentials(List cr new IsInValidityPeriod(clock), new HasValidSubjectIds(presentationHolder), new IsNotRevoked(revocationServiceRegistry), - new HasValidIssuer(getTrustedIssuerIds()))); + new HasValidIssuer(trustedIssuerRegistry))); filters.addAll(additionalRules); var results = credentials @@ -78,7 +77,4 @@ private Result validateVerifiableCredentials(List cr return results.orElseGet(() -> failure("Could not determine the status of the VC validation")); } - private List getTrustedIssuerIds() { - return trustedIssuerRegistry.getTrustedIssuers().stream().map(Issuer::id).toList(); - } } diff --git a/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuer.java b/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuer.java index a0807a8eb96..2441363977c 100644 --- a/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuer.java +++ b/extensions/common/iam/verifiable-credentials/src/main/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuer.java @@ -16,24 +16,23 @@ import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential; import org.eclipse.edc.iam.verifiablecredentials.spi.validation.CredentialValidationRule; +import org.eclipse.edc.iam.verifiablecredentials.spi.validation.TrustedIssuerRegistry; import org.eclipse.edc.spi.result.Result; -import java.util.Collection; +import java.util.Collections; import static org.eclipse.edc.spi.result.Result.failure; import static org.eclipse.edc.spi.result.Result.success; /** - * A class that implements the {@link CredentialValidationRule} interface and checks if a {@link VerifiableCredential} has a valid issuer. - * Valid issuers are stored in a global list. - *

- * If the issuer object is neither a string nor an object containing an "id" field, a failure is returned. + * A class that implements the {@link CredentialValidationRule} interface and checks if a {@link VerifiableCredential} has a trusted issuer, + * and if the credential type is supported for this issuer. */ public class HasValidIssuer implements CredentialValidationRule { - private final Collection trustedIssuers; + private final TrustedIssuerRegistry trustedIssuerRegistry; - public HasValidIssuer(Collection trustedIssuers) { - this.trustedIssuers = trustedIssuers; + public HasValidIssuer(TrustedIssuerRegistry trustedIssuerRegistry) { + this.trustedIssuerRegistry = trustedIssuerRegistry; } @Override @@ -42,6 +41,11 @@ public Result apply(VerifiableCredential credential) { if (issuer.id() == null) { return failure("Issuer did not contain an 'id' field."); } - return trustedIssuers.contains(issuer.id()) ? success() : failure("Issuer '%s' is not in the list of trusted issuers".formatted(issuer.id())); + + var supportedTypes = trustedIssuerRegistry.getSupportedTypes(issuer); + return !supportedTypes.contains(TrustedIssuerRegistry.WILDCARD) && Collections.disjoint(credential.getType(), supportedTypes) ? + failure("Credential types '%s' are not supported for issuer '%s'".formatted(credential.getType(), issuer.id())) : + success(); } + } diff --git a/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImplTest.java b/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImplTest.java index 858439b2bde..490832f08fe 100644 --- a/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImplTest.java +++ b/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/VerifiableCredentialValidationServiceImplTest.java @@ -53,6 +53,7 @@ class VerifiableCredentialValidationServiceImplTest { @BeforeEach void setUp() { + when(trustedIssuerRegistryMock.getSupportedTypes(TRUSTED_ISSUER)).thenReturn(Set.of(TrustedIssuerRegistry.WILDCARD)); when(revocationServiceRegistry.checkValidity(any())).thenReturn(Result.success()); } @@ -103,7 +104,6 @@ void oneInvalidSubjectId() { @Test void credentialHasInvalidIssuer_issuerIsUrl() { - var consumerDid = "did:web:test-consumer"; var presentation = createPresentationBuilder() .type("VerifiablePresentation") .credentials(List.of(createCredentialBuilder() @@ -116,7 +116,7 @@ void credentialHasInvalidIssuer_issuerIsUrl() { var result = service.validate(List.of(vpContainer)); assertThat(result).isFailed().messages() .hasSizeGreaterThanOrEqualTo(1) - .contains("Issuer 'invalid-issuer' is not in the list of trusted issuers"); + .contains("Credential types '[test-type]' are not supported for issuer 'invalid-issuer'"); } @Test @@ -133,7 +133,6 @@ void verify_singlePresentation_singleCredential() { .build(); var vpContainer = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation); when(verifierMock.verifyPresentation(any())).thenReturn(success()); - when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER)); var result = service.validate(List.of(vpContainer)); assertThat(result).isSucceeded(); } @@ -158,7 +157,6 @@ void verify_singlePresentation_multipleCredentials() { .build(); var vpContainer = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation); when(verifierMock.verifyPresentation(any())).thenReturn(success()); - when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER)); var result = service.validate(List.of(vpContainer)); assertThat(result).isSucceeded(); } @@ -202,8 +200,6 @@ void verify_multiplePresentations_multipleCredentialsEach() { var vpContainer2 = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation2); when(verifierMock.verifyPresentation(any())).thenReturn(success()); - when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER)); - var result = service.validate(List.of(vpContainer1, vpContainer2)); assertThat(result).isSucceeded(); @@ -224,7 +220,6 @@ void verify_revocationCheckFails() { .build(); var vpContainer = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation); when(verifierMock.verifyPresentation(any())).thenReturn(success()); - when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER)); when(revocationServiceRegistry.checkValidity(any())).thenReturn(Result.failure("invalid")); var result = service.validate(List.of(vpContainer)); diff --git a/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuerTest.java b/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuerTest.java index 5856dd427d7..fc9109ed678 100644 --- a/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuerTest.java +++ b/extensions/common/iam/verifiable-credentials/src/test/java/org/eclipse/edc/iam/verifiablecredentials/rules/HasValidIssuerTest.java @@ -15,52 +15,66 @@ package org.eclipse.edc.iam.verifiablecredentials.rules; import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer; +import org.eclipse.edc.iam.verifiablecredentials.spi.validation.TrustedIssuerRegistry; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.List; import java.util.Map; +import java.util.Set; import static org.eclipse.edc.iam.verifiablecredentials.spi.TestFunctions.createCredentialBuilder; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; class HasValidIssuerTest { - @DisplayName("Issuer (string) is in the list of valid issuers") - @Test - void hasValidIssuer_string() { - var vc = createCredentialBuilder() - .issuer(new Issuer("did:web:issuer2", Map.of())) - .build(); - assertThat(new HasValidIssuer(List.of("did:web:issuer1", "did:web:issuer2")).apply(vc)).isSucceeded(); - } + private static final String ISSUER = "did:web:issuer1"; + + private final TrustedIssuerRegistry trustedIssuerRegistry = mock(); + private final HasValidIssuer rule = new HasValidIssuer(trustedIssuerRegistry); - @DisplayName("Issuer (object) is in the list of valid issuers") + @DisplayName("Issuer is trusted for any credential type") @Test - void hasValidIssuer_object() { + void isTrustedForAnyType_shouldReturnSuccess() { + when(trustedIssuerRegistry.getSupportedTypes(new Issuer(ISSUER, Map.of()))).thenReturn(Set.of(TrustedIssuerRegistry.WILDCARD)); + var vc = createCredentialBuilder() - .issuer(new Issuer("did:web:issuer1", Map.of("name", "test issuer company"))) + .issuer(new Issuer(ISSUER, Map.of())) + .types(List.of("type1", "type2")) .build(); - assertThat(new HasValidIssuer(List.of("did:web:issuer1", "did:web:issuer2")).apply(vc)).isSucceeded(); + + assertThat(rule.apply(vc)).isSucceeded(); } - @DisplayName("Issuer (string) is not in the list of valid issuers") + @DisplayName("Issuer is trusted for the provided credential type") @Test - void invalidIssuer_string() { + void isTrustedForType_shouldReturnSuccess() { + when(trustedIssuerRegistry.getSupportedTypes(new Issuer(ISSUER, Map.of()))).thenReturn(Set.of("type3", "type1")); + var vc = createCredentialBuilder() - .issuer(new Issuer("did:web:invalid", Map.of())) + .issuer(new Issuer(ISSUER, Map.of())) + .types(List.of("type1", "type2")) .build(); - assertThat(new HasValidIssuer(List.of("did:web:issuer1", "did:web:issuer2")).apply(vc)).isFailed() - .detail().isEqualTo("Issuer 'did:web:invalid' is not in the list of trusted issuers"); + + assertThat(rule.apply(vc)).isSucceeded(); } - @DisplayName("Issuer (object) is not in the list of valid issuers") + @DisplayName("Issuer is not trusted for the provided credential type") @Test - void invalidIssuer_object() { + void isNotTrustedForType_shouldFail() { + when(trustedIssuerRegistry.getSupportedTypes(new Issuer(ISSUER, Map.of()))).thenReturn(Set.of("type2", "type3")); + var vc = createCredentialBuilder() - .issuer(new Issuer("did:web:invalid", Map.of("id", "did:web:invalid", "name", "test issuer company"))) + .issuer(new Issuer(ISSUER, Map.of())) + .types(List.of("type1")) .build(); - assertThat(new HasValidIssuer(List.of("did:web:issuer1", "did:web:issuer2")).apply(vc)).isFailed() - .detail().isEqualTo("Issuer 'did:web:invalid' is not in the list of trusted issuers"); + + assertThat(rule.apply(vc)) + .isFailed() + .detail() + .isEqualTo("Credential types '[type1]' are not supported for issuer '%s'".formatted(ISSUER)); } + } \ No newline at end of file diff --git a/spi/common/verifiable-credentials-spi/src/main/java/org/eclipse/edc/iam/verifiablecredentials/spi/validation/TrustedIssuerRegistry.java b/spi/common/verifiable-credentials-spi/src/main/java/org/eclipse/edc/iam/verifiablecredentials/spi/validation/TrustedIssuerRegistry.java index cd388cc327a..f2d855d438f 100644 --- a/spi/common/verifiable-credentials-spi/src/main/java/org/eclipse/edc/iam/verifiablecredentials/spi/validation/TrustedIssuerRegistry.java +++ b/spi/common/verifiable-credentials-spi/src/main/java/org/eclipse/edc/iam/verifiablecredentials/spi/validation/TrustedIssuerRegistry.java @@ -16,17 +16,30 @@ import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer; -import java.util.Collection; +import java.util.Set; /** - * A list of trusted VC issuers + * Trusted issuer registry. */ public interface TrustedIssuerRegistry { - void addIssuer(Issuer issuer); + String WILDCARD = "*"; - Issuer getById(String id); + /** + * Register a supported type for a trusted issuer. + * + * @param issuer the issuer + * @param credentialType supported credential type for this issuer + */ + void register(Issuer issuer, String credentialType); + + /** + * Get the supported types for a given issuer. + * + * @param issuer the issuer + * @return set of supported credential types for this issuer. + */ + Set getSupportedTypes(Issuer issuer); - Collection getTrustedIssuers(); }