From 181cd2eedf2ebafab48f2042311c09fd154104d6 Mon Sep 17 00:00:00 2001 From: Paul Latzelsperger <43503240+paullatzelsperger@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:48:30 +0200 Subject: [PATCH 1/2] fix: prevent default identity extractor from being registered (#1597) * fix(dcp): prevent default identity extractor from being registered * fix unit tests --- .../edc/iam/iatp/IatpIdentityExtension.java | 19 +++-- .../iatp/identity/IatpIdentityExtractor.java | 5 +- .../iam/iatp/IatpIdentityExtensionTest.java | 19 +---- .../identity/IatpIdentityExtractorTest.java | 12 +-- .../tests/transfer/IdentityExtractorTest.java | 83 +++++++++++++++++++ 5 files changed, 106 insertions(+), 32 deletions(-) create mode 100644 edc-tests/edc-controlplane/iatp-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/IdentityExtractorTest.java diff --git a/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtension.java b/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtension.java index 7f8213771..f3cbad85f 100644 --- a/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtension.java +++ b/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtension.java @@ -19,11 +19,10 @@ package org.eclipse.tractusx.edc.iam.iatp; +import org.eclipse.edc.iam.identitytrust.spi.DcpParticipantAgentServiceExtension; import org.eclipse.edc.runtime.metamodel.annotation.Extension; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.agent.ParticipantAgentService; +import org.eclipse.edc.runtime.metamodel.annotation.Provider; import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.tractusx.edc.iam.iatp.identity.IatpIdentityExtractor; import static org.eclipse.tractusx.edc.iam.iatp.IatpDefaultScopeExtension.NAME; @@ -33,17 +32,21 @@ public class IatpIdentityExtension implements ServiceExtension { static final String NAME = "Tractusx IATP identity extension"; - @Inject - private ParticipantAgentService participantAgentService; + private final IatpIdentityExtractor iatpIdentityExtractor = new IatpIdentityExtractor(); @Override public String name() { return NAME; } - @Override - public void initialize(ServiceExtensionContext context) { - participantAgentService.register(new IatpIdentityExtractor()); + + /** + * This provider method is mandatory, because it prevents the {@code DefaultDcpParticipantAgentServiceExtension} from being + * registered, which would cause a race condition in the identity extractors + */ + @Provider + public DcpParticipantAgentServiceExtension extractor() { + return iatpIdentityExtractor; } } diff --git a/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractor.java b/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractor.java index 59754f3c1..f3678fb90 100644 --- a/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractor.java +++ b/edc-extensions/iatp/tx-iatp/src/main/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractor.java @@ -19,6 +19,7 @@ package org.eclipse.tractusx.edc.iam.iatp.identity; +import org.eclipse.edc.iam.identitytrust.spi.DcpParticipantAgentServiceExtension; import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.agent.ParticipantAgentServiceExtension; @@ -38,7 +39,7 @@ * Implementation of {@link ParticipantAgentServiceExtension} which extracts the identity of a participant * from the MembershipCredential */ -public class IatpIdentityExtractor implements ParticipantAgentServiceExtension { +public class IatpIdentityExtractor implements DcpParticipantAgentServiceExtension { private static final String VC_CLAIM = "vc"; private static final String IDENTITY_CREDENTIAL = "MembershipCredential"; @@ -56,7 +57,7 @@ public class IatpIdentityExtractor implements ParticipantAgentServiceExtension { .findFirst() .flatMap(this::getIdentifier) .map(identity -> Map.of(PARTICIPANT_IDENTITY, identity)) - .orElseThrow(() -> new EdcException("Failed to fetch %s property from %s credential".formatted(IDENTITY_PROPERTY, IDENTITY_CREDENTIAL))); + .orElseThrow(() -> new EdcException("Required credential type '%s' not present in ClaimToken, cannot extract property '%s'".formatted(IDENTITY_CREDENTIAL, IDENTITY_PROPERTY))); } diff --git a/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtensionTest.java b/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtensionTest.java index 71e45ab12..2d24692c4 100644 --- a/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtensionTest.java +++ b/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/IatpIdentityExtensionTest.java @@ -20,31 +20,18 @@ package org.eclipse.tractusx.edc.iam.iatp; import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; -import org.eclipse.edc.spi.agent.ParticipantAgentService; -import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.tractusx.edc.iam.iatp.identity.IatpIdentityExtractor; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(DependencyInjectionExtension.class) public class IatpIdentityExtensionTest { - private final ParticipantAgentService participantAgentService = mock(); - - @BeforeEach - void setup(ServiceExtensionContext context) { - context.registerService(ParticipantAgentService.class, participantAgentService); - } - @Test - void initialize(ServiceExtensionContext context, IatpIdentityExtension extension) { - extension.initialize(context); - verify(participantAgentService).register(isA(IatpIdentityExtractor.class)); + void initialize(IatpIdentityExtension extension) { + assertThat(extension.extractor()).isInstanceOf(IatpIdentityExtractor.class); } } diff --git a/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractorTest.java b/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractorTest.java index 5e2727dea..8965b7a35 100644 --- a/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractorTest.java +++ b/edc-extensions/iatp/tx-iatp/src/test/java/org/eclipse/tractusx/edc/iam/iatp/identity/IatpIdentityExtractorTest.java @@ -62,21 +62,21 @@ void attributesFor(VerifiableCredential credential) { } @Test - void attributesFor_Fails_WhenCredentialNotFound() { + void attributesFor_fails_WhenCredentialNotFound() { assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim("vc", List.of(vc("FooCredential", Map.of("foo", "bar")))).build())) .isInstanceOf(EdcException.class) - .hasMessageContaining("Failed to fetch"); + .hasMessage("Required credential type 'MembershipCredential' not present in ClaimToken, cannot extract property 'holderIdentifier'"); } @Test - void attributesFor_Fails_whenNoVcClaims() { + void attributesFor_fails_whenNoVcClaims() { assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().build())) .isInstanceOf(EdcException.class) .hasMessageContaining("Failed to fetch credentials from the claim token: ClaimToken did not contain a 'vc' claim"); } @Test - void attributesFor_Fails_whenNullVcClaims() { + void attributesFor_fails_whenNullVcClaims() { assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim("vc", null).build())) .isInstanceOf(EdcException.class) @@ -84,14 +84,14 @@ void attributesFor_Fails_whenNullVcClaims() { } @Test - void attributesFor_Fails_WhenVcClaimIsNotList() { + void attributesFor_fails_WhenVcClaimIsNotList() { assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim("vc", "wrong").build())) .isInstanceOf(EdcException.class) .hasMessageContaining("Failed to fetch credentials from the claim token: ClaimToken contains a 'vc' claim, but the type is incorrect. Expected java.util.List, got java.lang.String."); } @Test - void attributesFor_Fails_WhenVcClaimsIsEmptyList() { + void attributesFor_fails_WhenVcClaimsIsEmptyList() { assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim("vc", List.of()).build())) .isInstanceOf(EdcException.class) .hasMessageContaining("Failed to fetch credentials from the claim token: ClaimToken contains a 'vc' claim but it did not contain any VerifiableCredentials."); diff --git a/edc-tests/edc-controlplane/iatp-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/IdentityExtractorTest.java b/edc-tests/edc-controlplane/iatp-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/IdentityExtractorTest.java new file mode 100644 index 000000000..40e565d92 --- /dev/null +++ b/edc-tests/edc-controlplane/iatp-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/IdentityExtractorTest.java @@ -0,0 +1,83 @@ +/******************************************************************************** + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +package org.eclipse.tractusx.edc.tests.transfer; + +import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialSubject; +import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer; +import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential; +import org.eclipse.edc.junit.annotations.EndToEndTest; +import org.eclipse.edc.junit.extensions.RuntimeExtension; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.agent.ParticipantAgentService; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.eclipse.tractusx.edc.tests.transfer.iatp.runtime.Runtimes.iatpRuntime; + +/** + * This test asserts that the ParticipantAgent's identity is determined by the "credentialSubject.holderIdentifier" property. + * Due to how the extractors are used and registered, this must be tested using a fully-fledged runtime. + */ +@EndToEndTest +public class IdentityExtractorTest implements IatpParticipants { + + @RegisterExtension + protected static final RuntimeExtension CONSUMER_RUNTIME = iatpRuntime(CONSUMER.getName(), CONSUMER.iatpConfiguration(PROVIDER), CONSUMER.getKeyPair()); + + @Test + void verifyCorrectParticipantAgentId(ParticipantAgentService participantAgentService) { + var claimtoken = ClaimToken.Builder.newInstance() + .claim("vc", List.of(createCredential().build())) + .build(); + var agent = participantAgentService.createFor(claimtoken); + + assertThat(agent.getIdentity()).isEqualTo("the-holder"); + } + + @Test + void verifyAgentId_whenNoMembershipCredential(ParticipantAgentService participantAgentService) { + var claimtoken = ClaimToken.Builder.newInstance() + .claim("vc", List.of(createCredential().types(List.of("VerifiableCredential")).build())) + .build(); + assertThatThrownBy(() -> participantAgentService.createFor(claimtoken)).isInstanceOf(EdcException.class) + .hasMessage("Required credential type 'MembershipCredential' not present in ClaimToken, cannot extract property 'holderIdentifier'"); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private VerifiableCredential.Builder createCredential() { + return VerifiableCredential.Builder.newInstance() + .types(List.of("VerifiableCredential", "MembershipCredential")) + .id("test-id") + .issuanceDate(Instant.now()) + .issuer(new Issuer("test-issuer", Map.of())) + .credentialSubject(CredentialSubject.Builder.newInstance() + .id("test-id") + .claim("holderIdentifier", "the-holder") + .build()); + } + +} From 6f773cdb71e71484206ccf991e9caf2cf814afe1 Mon Sep 17 00:00:00 2001 From: Paul Latzelsperger Date: Tue, 1 Oct 2024 10:06:06 +0200 Subject: [PATCH 2/2] DEPENDENCIES, helm docs --- DEPENDENCIES | 2 +- charts/tractusx-connector-azure-vault/README.md | 4 ++-- charts/tractusx-connector-memory/README.md | 4 ++-- charts/tractusx-connector/README.md | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index bb6a61f24..bc02578a6 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -34,7 +34,7 @@ maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.17.1, Apache maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.13.5, Apache-2.0, approved, #2133 maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.14.1, Apache-2.0 AND MIT, approved, #4303 maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.16.2, Apache-2.0 AND MIT, approved, #11602 -maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.17.1, , approved, #13665 +maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.17.1, Apache-2.0 AND MIT, approved, #13665 maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.11.0, Apache-2.0, approved, CQ23093 maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.13.4.2, Apache-2.0, approved, #2134 maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.13.5, Apache-2.0, approved, #2134 diff --git a/charts/tractusx-connector-azure-vault/README.md b/charts/tractusx-connector-azure-vault/README.md index 56d6d0ba1..71ba59452 100644 --- a/charts/tractusx-connector-azure-vault/README.md +++ b/charts/tractusx-connector-azure-vault/README.md @@ -1,6 +1,6 @@ # tractusx-connector-azure-vault -![Version: 0.7.5](https://img.shields.io/badge/Version-0.7.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.5](https://img.shields.io/badge/AppVersion-0.7.5-informational?style=flat-square) +![Version: 0.7.6](https://img.shields.io/badge/Version-0.7.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.6](https://img.shields.io/badge/AppVersion-0.7.6-informational?style=flat-square) A Helm chart for Tractus-X Eclipse Data Space Connector. The connector deployment consists of two runtime consists of a Control Plane and a Data Plane. Note that _no_ external dependencies such as a PostgreSQL database and Azure KeyVault are included. @@ -44,7 +44,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0.7.5 \ +helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0.7.6 \ -f /tractusx-connector-azure-vault-test.yaml \ --set vault.azure.name=$AZURE_VAULT_NAME \ --set vault.azure.client=$AZURE_CLIENT_ID \ diff --git a/charts/tractusx-connector-memory/README.md b/charts/tractusx-connector-memory/README.md index 09c3fdde9..5bd9c6c37 100644 --- a/charts/tractusx-connector-memory/README.md +++ b/charts/tractusx-connector-memory/README.md @@ -1,6 +1,6 @@ # tractusx-connector-memory -![Version: 0.7.5](https://img.shields.io/badge/Version-0.7.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.5](https://img.shields.io/badge/AppVersion-0.7.5-informational?style=flat-square) +![Version: 0.7.6](https://img.shields.io/badge/Version-0.7.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.6](https://img.shields.io/badge/AppVersion-0.7.6-informational?style=flat-square) A Helm chart for Tractus-X Eclipse Data Space Connector based on memory. Please only use this for development or testing purposes, never in production workloads! @@ -41,7 +41,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector-memory --version 0.7.5 \ +helm install my-release tractusx-edc/tractusx-connector-memory --version 0.7.6 \ -f /tractusx-connector-memory-test.yaml \ --set vault.secrets="client-secret:$YOUR_CLIENT_SECRET" ``` diff --git a/charts/tractusx-connector/README.md b/charts/tractusx-connector/README.md index 5e081fd7a..fc833dcaf 100644 --- a/charts/tractusx-connector/README.md +++ b/charts/tractusx-connector/README.md @@ -1,6 +1,6 @@ # tractusx-connector -![Version: 0.7.5](https://img.shields.io/badge/Version-0.7.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.5](https://img.shields.io/badge/AppVersion-0.7.5-informational?style=flat-square) +![Version: 0.7.6](https://img.shields.io/badge/Version-0.7.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.6](https://img.shields.io/badge/AppVersion-0.7.6-informational?style=flat-square) A Helm chart for Tractus-X Eclipse Data Space Connector. The connector deployment consists of two runtime consists of a Control Plane and a Data Plane. Note that _no_ external dependencies such as a PostgreSQL database and HashiCorp Vault are included. @@ -44,7 +44,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector --version 0.7.5 \ +helm install my-release tractusx-edc/tractusx-connector --version 0.7.6 \ -f /tractusx-connector-test.yaml ```