Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent default identity extractor from being registered #1597

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

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;
Expand All @@ -33,8 +33,7 @@ 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() {
Expand All @@ -43,7 +42,15 @@ public String 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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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";
Expand All @@ -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)));


}
Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}

}
Loading