diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/README.md b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/README.md new file mode 100644 index 00000000000..612df75eab7 --- /dev/null +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/README.md @@ -0,0 +1,13 @@ +# Trusted Issuer Configuration Extension + +This IATP extension makes it possible configure a list of trusted issuers, that will be used matches against the Verifiable Credential issuers. + +## Configuration + +Per issuer the following settings must be configured. As `` any unique string is valid. + +| Key | Description | Mandatory | +|:-----------------------------------------------------|:---------------------------------|-----------| +| edc.iam.trusted-issuer.````.id | ID of the issuer. | X | +| edc.iam.trusted-issuer.````.properties | Additional properties of Issuer. | (X) | + diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/build.gradle.kts b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/build.gradle.kts new file mode 100644 index 00000000000..0b60be2bbad --- /dev/null +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/build.gradle.kts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +plugins { + `java-library` + `maven-publish` +} + +dependencies { + api(project(":spi:common:identity-trust-spi")) + + testImplementation(project(":core:common:junit")) +} + diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java new file mode 100644 index 00000000000..83a46a00462 --- /dev/null +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/java/org/eclipse/edc/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtension.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.identitytrust.issuer.configuration; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.eclipse.edc.identitytrust.TrustedIssuerRegistry; +import org.eclipse.edc.identitytrust.model.Issuer; +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.types.TypeManager; + +import java.util.Map; + +import static org.eclipse.edc.identitytrust.issuer.configuration.TrustedIssuerConfigurationExtension.NAME; + +@Extension(NAME) +public class TrustedIssuerConfigurationExtension implements ServiceExtension { + + public static final String CONFIG_PREFIX = "edc.iam.trusted-issuer"; + public static final String PROPERTIES_SUFFIX = "properties"; + public static final String ID_SUFFIX = "id"; + protected static final String NAME = "Trusted Issuers Configuration Extensions"; + + @Inject + private TrustedIssuerRegistry trustedIssuerRegistry; + @Inject + private TypeManager typeManager; + + @Override + public void initialize(ServiceExtensionContext context) { + var config = context.getConfig(CONFIG_PREFIX); + var issuers = config.partition().map(this::configureIssuer).toList(); + if (issuers.isEmpty()) { + throw new EdcException("The list of trusted issuers is empty"); + } + issuers.forEach(issuer -> trustedIssuerRegistry.addIssuer(issuer)); + } + + private Issuer configureIssuer(Config config) { + + var id = config.getString(ID_SUFFIX); + var propertiesConfig = config.getString(PROPERTIES_SUFFIX, "{}"); + var properties = typeManager.readValue(propertiesConfig, new TypeReference>() { + }); + return new Issuer(id, properties); + } +} diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 00000000000..983933275eb --- /dev/null +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# +# Contributors: +# Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation +# +# + +org.eclipse.edc.identitytrust.issuer.configuration.TrustedIssuerConfigurationExtension \ No newline at end of file diff --git a/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java new file mode 100644 index 00000000000..fefdb31cb96 --- /dev/null +++ b/extensions/common/iam/identity-trust/identity-trust-issuers-configuration/src/test/java/org/eclipse/edc/identitytrust/issuer/configuration/TrustedIssuerConfigurationExtensionTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.identitytrust.issuer.configuration; + +import org.eclipse.edc.identitytrust.TrustedIssuerRegistry; +import org.eclipse.edc.identitytrust.model.Issuer; +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.ConfigFactory; +import org.eclipse.edc.spi.types.TypeManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(DependencyInjectionExtension.class) +public class TrustedIssuerConfigurationExtensionTest { + + private final TrustedIssuerRegistry trustedIssuerRegistry = mock(); + + @BeforeEach + void setup(ServiceExtensionContext context) { + context.registerService(TrustedIssuerRegistry.class, trustedIssuerRegistry); + context.registerService(TypeManager.class, new TypeManager()); + } + + @Test + void initialize(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { + var cfg = ConfigFactory.fromMap(Map.of("issuer1.id", "issuerId1")); + when(context.getConfig("edc.iam.trusted-issuer")).thenReturn(cfg); + + ext.initialize(context); + + verify(trustedIssuerRegistry).addIssuer(argThat(issuer -> issuer.id().equals("issuerId1"))); + } + + @Test + void initialize_failure_WithNoIssuer(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { + var cfg = ConfigFactory.fromMap(Map.of()); + when(context.getConfig("edc.iam.trusted-issuer")).thenReturn(cfg); + + assertThatThrownBy(() -> ext.initialize(context)).isInstanceOf(EdcException.class); + } + + @Test + void initialize_withProperties(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { + var properties = "{\"custom\": \"test\"}"; + var cfg = ConfigFactory.fromMap(Map.of("issuer1.id", "issuerId1", "issuer1.properties", properties)); + when(context.getConfig("edc.iam.trusted-issuer")).thenReturn(cfg); + + ext.initialize(context); + + verify(trustedIssuerRegistry).addIssuer(argThat(issuer -> issuer.additionalProperties().get("custom").equals("test"))); + } + + @Test + void initialize_withTwoIssuers(ServiceExtensionContext context, TrustedIssuerConfigurationExtension ext) { + var cfg = ConfigFactory.fromMap(Map.of("issuer1.id", "issuerId1", "issuer2.id", "issuerId2")); + when(context.getConfig("edc.iam.trusted-issuer")).thenReturn(cfg); + + ext.initialize(context); + + var issuers = ArgumentCaptor.forClass(Issuer.class); + + verify(trustedIssuerRegistry, times(2)).addIssuer(issuers.capture()); + + assertThat(issuers.getAllValues()).hasSize(2) + .extracting(Issuer::id) + .contains("issuerId1", "issuerId2"); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e61fc95d7f7..330465b7f82 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -123,6 +123,7 @@ include(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust include(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust-sts-remote-core") include(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust-sts-api") include(":extensions:common:iam:identity-trust:identity-trust-sts:identity-trust-sts-client-configuration") +include(":extensions:common:iam:identity-trust:identity-trust-issuers-configuration") include(":extensions:common:json-ld") include(":extensions:common:metrics:micrometer-core") @@ -241,4 +242,4 @@ include(":system-tests:sts-api:sts-api-test-runtime") include(":system-tests:telemetry:telemetry-test-runner") include(":system-tests:telemetry:telemetry-test-runtime") -include(":version-catalog") +include(":version-catalog") \ No newline at end of file