Skip to content

Commit 3bc73b7

Browse files
authored
feat: add participant id extraction function to dataspace profile context (#5154)
1 parent 1deef07 commit 3bc73b7

44 files changed

Lines changed: 567 additions & 221 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/common/connector-core/src/main/java/org/eclipse/edc/connector/core/CoreServicesExtension.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*
1010
* Contributors:
1111
* Microsoft Corporation - initial API and implementation
12+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1213
*
1314
*/
1415

@@ -31,22 +32,16 @@
3132
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
3233
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
3334
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
34-
import org.eclipse.edc.runtime.metamodel.annotation.Setting;
3535
import org.eclipse.edc.spi.system.ServiceExtension;
3636
import org.eclipse.edc.spi.system.ServiceExtensionContext;
3737
import org.eclipse.edc.spi.types.TypeManager;
3838
import org.eclipse.edc.validator.spi.DataAddressValidatorRegistry;
3939

40-
import static org.eclipse.edc.participant.spi.ParticipantAgentService.DEFAULT_IDENTITY_CLAIM_KEY;
41-
4240
@Extension(value = CoreServicesExtension.NAME)
4341
public class CoreServicesExtension implements ServiceExtension {
4442

4543
public static final String NAME = "Core Services";
4644

47-
@Setting(description = "The name of the claim key used to determine the participant identity", defaultValue = DEFAULT_IDENTITY_CLAIM_KEY)
48-
public static final String EDC_AGENT_IDENTITY_KEY = "edc.agent.identity.key";
49-
5045
@Inject
5146
private TypeManager typeManager;
5247

@@ -74,9 +69,8 @@ public void prepare() {
7469
}
7570

7671
@Provider
77-
public ParticipantAgentService participantAgentService(ServiceExtensionContext context) {
78-
var identityKey = context.getSetting(EDC_AGENT_IDENTITY_KEY, DEFAULT_IDENTITY_CLAIM_KEY);
79-
return new ParticipantAgentServiceImpl(identityKey);
72+
public ParticipantAgentService participantAgentService() {
73+
return new ParticipantAgentServiceImpl();
8074
}
8175

8276
@Provider

core/common/connector-core/src/main/java/org/eclipse/edc/connector/core/agent/ParticipantAgentServiceImpl.java

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*
1010
* Contributors:
1111
* Microsoft Corporation - initial API and implementation
12+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1213
*
1314
*/
1415

@@ -23,36 +24,22 @@
2324
import java.util.HashMap;
2425
import java.util.List;
2526

26-
import static java.util.Objects.requireNonNull;
27-
import static org.eclipse.edc.participant.spi.ParticipantAgent.PARTICIPANT_IDENTITY;
28-
2927
/**
3028
* Default implementation.
3129
*/
3230
public class ParticipantAgentServiceImpl implements ParticipantAgentService {
33-
private final String identityClaimKey;
34-
private final List<ParticipantAgentServiceExtension> extensions = new ArrayList<>();
3531

36-
public ParticipantAgentServiceImpl() {
37-
identityClaimKey = DEFAULT_IDENTITY_CLAIM_KEY;
38-
}
32+
private final List<ParticipantAgentServiceExtension> extensions = new ArrayList<>();
3933

40-
public ParticipantAgentServiceImpl(String key) {
41-
requireNonNull(key, "key");
42-
this.identityClaimKey = key;
43-
}
34+
public ParticipantAgentServiceImpl() { }
4435

4536
@Override
46-
public ParticipantAgent createFor(ClaimToken token) {
37+
public ParticipantAgent createFor(ClaimToken token, String participantId) {
4738
var attributes = new HashMap<String, String>();
39+
4840
extensions.stream().map(extension -> extension.attributesFor(token)).forEach(attributes::putAll);
49-
if (!attributes.containsKey(PARTICIPANT_IDENTITY)) {
50-
var claim = token.getClaim(identityClaimKey);
51-
if (claim != null) {
52-
attributes.put(PARTICIPANT_IDENTITY, claim.toString());
53-
}
54-
}
55-
return new ParticipantAgent(token.getClaims(), attributes);
41+
42+
return new ParticipantAgent(participantId, token.getClaims(), attributes);
5643
}
5744

5845
@Override

core/common/connector-core/src/test/java/org/eclipse/edc/connector/core/agent/ParticipantAgentServiceImplTest.java

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*
1010
* Contributors:
1111
* Microsoft Corporation - initial API and implementation
12+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1213
*
1314
*/
1415

@@ -21,7 +22,6 @@
2122
import java.util.Map;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
24-
import static org.eclipse.edc.connector.core.agent.ParticipantAgentServiceImpl.DEFAULT_IDENTITY_CLAIM_KEY;
2525
import static org.eclipse.edc.participant.spi.ParticipantAgent.PARTICIPANT_IDENTITY;
2626
import static org.mockito.ArgumentMatchers.isA;
2727
import static org.mockito.Mockito.mock;
@@ -41,61 +41,36 @@ void verifyRegisteredExtensionIsInvoked() {
4141
var participantAgentService = new ParticipantAgentServiceImpl();
4242
participantAgentService.register(extension);
4343

44-
var participantAgent = participantAgentService.createFor(ClaimToken.Builder.newInstance().build());
44+
var participantAgent = participantAgentService.createFor(ClaimToken.Builder.newInstance().build(), "test-participant");
4545

4646
assertThat(participantAgent.getAttributes().containsKey("foo")).isTrue();
4747
verify(extension).attributesFor(isA(ClaimToken.class));
4848
}
49-
50-
@Test
51-
void verifyDefaultIdentityClaim() {
52-
var participantAgentService = new ParticipantAgentServiceImpl();
53-
var agent = participantAgentService.createFor(ClaimToken.Builder.newInstance().claim(DEFAULT_IDENTITY_CLAIM_KEY, "test-participant").build());
54-
55-
assertThat(agent.getIdentity()).isEqualTo("test-participant");
56-
}
57-
49+
5850
@Test
59-
void verifyNoDefaultIdentityClaim() {
51+
void verifyIdentityIsAddedToParticipantAgent() {
6052
var participantAgentService = new ParticipantAgentServiceImpl();
61-
var agent = participantAgentService.createFor(ClaimToken.Builder.newInstance().build());
62-
63-
assertThat(agent.getIdentity()).isNull();
64-
}
65-
66-
@Test
67-
void verifyCustomIdentityClaim() {
68-
var participantAgentService = new ParticipantAgentServiceImpl("custom-key");
69-
var agent = participantAgentService.createFor(ClaimToken.Builder.newInstance().claim("custom-key", "test-participant").build());
70-
71-
assertThat(agent.getIdentity()).isEqualTo("test-participant");
53+
var participantId = "test-participant";
54+
55+
var participantAgent = participantAgentService.createFor(ClaimToken.Builder.newInstance().build(), participantId);
56+
57+
assertThat(participantAgent.getIdentity()).isEqualTo(participantId);
7258
}
7359

7460
@Test
75-
void verifyExtensionCreatesIdentity() {
61+
void verifyGivenIdentityOverridesIdentityCreatedByExtension() {
7662
var participantAgentService = new ParticipantAgentServiceImpl();
63+
var extensionParticipantId = "overridden-participant";
64+
var givenParticipantId = "test-participant";
7765

78-
ParticipantAgentServiceExtension extension = mock(ParticipantAgentServiceExtension.class);
79-
when(extension.attributesFor(isA(ClaimToken.class))).thenReturn(Map.of(PARTICIPANT_IDENTITY, "test-participant"));
66+
var extension = mock(ParticipantAgentServiceExtension.class);
67+
when(extension.attributesFor(isA(ClaimToken.class))).thenReturn(Map.of(PARTICIPANT_IDENTITY, extensionParticipantId));
8068
participantAgentService.register(extension);
8169

82-
var agent = participantAgentService.createFor(ClaimToken.Builder.newInstance().build());
70+
var agent = participantAgentService.createFor(ClaimToken.Builder.newInstance().build(), givenParticipantId);
8371

84-
assertThat(agent.getIdentity()).isEqualTo("test-participant");
72+
assertThat(agent.getIdentity())
73+
.isNotEqualTo(extensionParticipantId)
74+
.isEqualTo(givenParticipantId);
8575
}
86-
87-
@Test
88-
void verifyExtensionOverridesDefaultIdentityClaim() {
89-
var participantAgentService = new ParticipantAgentServiceImpl();
90-
91-
ParticipantAgentServiceExtension extension = mock(ParticipantAgentServiceExtension.class);
92-
when(extension.attributesFor(isA(ClaimToken.class))).thenReturn(Map.of(PARTICIPANT_IDENTITY, "test-participant"));
93-
participantAgentService.register(extension);
94-
95-
var agent = participantAgentService.createFor(ClaimToken.Builder.newInstance().claim(DEFAULT_IDENTITY_CLAIM_KEY, "overriden-identity").build());
96-
97-
assertThat(agent.getIdentity()).isEqualTo("test-participant");
98-
}
99-
100-
10176
}

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
1212
* Cofinity-X - unauthenticated DSP version endpoint
1313
* Cofinity-X - add participantId to DataspaceProfileContext
14+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1415
*
1516
*/
1617

@@ -277,7 +278,7 @@ contractValidationService, protocolTokenValidator(), dataAddressValidator, trans
277278
@Provider
278279
public ProtocolTokenValidator protocolTokenValidator() {
279280
if (protocolTokenValidator == null) {
280-
protocolTokenValidator = new ProtocolTokenValidatorImpl(identityService, policyEngine, monitor, participantAgentService);
281+
protocolTokenValidator = new ProtocolTokenValidatorImpl(identityService, policyEngine, monitor, participantAgentService, dataspaceProfileContextRegistry);
281282
}
282283
return protocolTokenValidator;
283284
}

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/catalog/CatalogProtocolServiceImpl.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Contributors:
1111
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
1212
* Cofinity-X - add participantId to DataspaceProfileContext
13+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1314
*
1415
*/
1516

@@ -19,6 +20,7 @@
1920
import org.eclipse.edc.connector.controlplane.catalog.spi.CatalogRequestMessage;
2021
import org.eclipse.edc.connector.controlplane.catalog.spi.DataServiceRegistry;
2122
import org.eclipse.edc.connector.controlplane.catalog.spi.Dataset;
23+
import org.eclipse.edc.connector.controlplane.catalog.spi.DatasetRequestMessage;
2224
import org.eclipse.edc.connector.controlplane.catalog.spi.DatasetResolver;
2325
import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogProtocolService;
2426
import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolTokenValidator;
@@ -72,7 +74,11 @@ public ServiceResult<Catalog> getCatalog(CatalogRequestMessage message, TokenRep
7274

7375
@Override
7476
public @NotNull ServiceResult<Dataset> getDataset(String datasetId, TokenRepresentation tokenRepresentation, String protocol) {
75-
return transactionContext.execute(() -> protocolTokenValidator.verify(tokenRepresentation, RequestCatalogPolicyContext::new)
77+
var message = DatasetRequestMessage.Builder.newInstance()
78+
.protocol(protocol)
79+
.datasetId(datasetId)
80+
.build();
81+
return transactionContext.execute(() -> protocolTokenValidator.verify(tokenRepresentation, RequestCatalogPolicyContext::new, message)
7682
.map(agent -> datasetResolver.getById(agent, datasetId, protocol))
7783
.compose(dataset -> {
7884
if (dataset == null) {

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/contractnegotiation/ContractNegotiationProtocolServiceImpl.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Contributors:
1111
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
1212
* Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. - implementation for provider offer
13+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1314
*
1415
*/
1516

@@ -23,6 +24,7 @@
2324
import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreementVerificationMessage;
2425
import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractNegotiationEventMessage;
2526
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation;
27+
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationRequestMessage;
2628
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationTerminationMessage;
2729
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractOfferMessage;
2830
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractRequestMessage;
@@ -196,9 +198,14 @@ public ServiceResult<ContractNegotiation> notifyTerminated(ContractNegotiationTe
196198
@Override
197199
@WithSpan
198200
@NotNull
199-
public ServiceResult<ContractNegotiation> findById(String id, TokenRepresentation tokenRepresentation) {
201+
public ServiceResult<ContractNegotiation> findById(String id, TokenRepresentation tokenRepresentation, String protocol) {
202+
var message = ContractNegotiationRequestMessage.Builder.newInstance()
203+
.negotiationId(id)
204+
.protocol(protocol)
205+
.build();
206+
200207
return transactionContext.execute(() -> getNegotiation(id)
201-
.compose(contractNegotiation -> verifyRequest(tokenRepresentation, contractNegotiation.getLastContractOffer().getPolicy(), null)
208+
.compose(contractNegotiation -> verifyRequest(tokenRepresentation, contractNegotiation.getLastContractOffer().getPolicy(), message)
202209
.compose(agent -> validateRequest(agent, contractNegotiation)
203210
.map(it -> contractNegotiation))));
204211
}

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/protocol/ProtocolTokenValidatorImpl.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*
1010
* Contributors:
1111
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
12+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1213
*
1314
*/
1415

@@ -20,6 +21,7 @@
2021
import org.eclipse.edc.policy.context.request.spi.RequestPolicyContext;
2122
import org.eclipse.edc.policy.engine.spi.PolicyEngine;
2223
import org.eclipse.edc.policy.model.Policy;
24+
import org.eclipse.edc.protocol.spi.DataspaceProfileContextRegistry;
2325
import org.eclipse.edc.spi.iam.IdentityService;
2426
import org.eclipse.edc.spi.iam.RequestContext;
2527
import org.eclipse.edc.spi.iam.RequestScope;
@@ -38,15 +40,17 @@ public class ProtocolTokenValidatorImpl implements ProtocolTokenValidator {
3840
private final IdentityService identityService;
3941
private final PolicyEngine policyEngine;
4042
private final ParticipantAgentService agentService;
43+
private final DataspaceProfileContextRegistry dataspaceProfileContextRegistry;
4144

4245
private final Monitor monitor;
4346

4447
public ProtocolTokenValidatorImpl(IdentityService identityService, PolicyEngine policyEngine, Monitor monitor,
45-
ParticipantAgentService agentService) {
48+
ParticipantAgentService agentService, DataspaceProfileContextRegistry dataspaceProfileContextRegistry) {
4649
this.identityService = identityService;
4750
this.monitor = monitor;
4851
this.policyEngine = policyEngine;
4952
this.agentService = agentService;
53+
this.dataspaceProfileContextRegistry = dataspaceProfileContextRegistry;
5054
}
5155

5256
@Override
@@ -66,7 +70,13 @@ public ServiceResult<ParticipantAgent> verify(TokenRepresentation tokenRepresent
6670
}
6771

6872
var claimToken = tokenValidation.getContent();
69-
var participantAgent = agentService.createFor(claimToken);
73+
74+
var idExtractionFunction = dataspaceProfileContextRegistry.getIdExtractionFunction(message.getProtocol());
75+
if (idExtractionFunction == null) {
76+
return ServiceResult.badRequest("Unsupported protocol: " + message.getProtocol());
77+
}
78+
79+
var participantAgent = agentService.createFor(claimToken, idExtractionFunction.apply(claimToken));
7080
return ServiceResult.success(participantAgent);
7181
}
7282

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/transferprocess/TransferProcessProtocolServiceImpl.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Contributors:
1111
* Microsoft Corporation - initial API and implementation
1212
* Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. - initiate provider process
13+
* Cofinity-X - make participant id extraction dependent on dataspace profile context
1314
*
1415
*/
1516

@@ -27,6 +28,7 @@
2728
import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess;
2829
import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates;
2930
import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferCompletionMessage;
31+
import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferProcessRequestMessage;
3032
import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferRemoteMessage;
3133
import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferRequestMessage;
3234
import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferStartMessage;
@@ -137,9 +139,14 @@ public ServiceResult<TransferProcess> notifyTerminated(TransferTerminationMessag
137139
@Override
138140
@WithSpan
139141
@NotNull
140-
public ServiceResult<TransferProcess> findById(String id, TokenRepresentation tokenRepresentation) {
142+
public ServiceResult<TransferProcess> findById(String id, TokenRepresentation tokenRepresentation, String protocol) {
143+
var message = TransferProcessRequestMessage.Builder.newInstance()
144+
.transferProcessId(id)
145+
.protocol(protocol)
146+
.build();
147+
141148
return transactionContext.execute(() -> fetchRequestContext(id, this::findTransferProcessById)
142-
.compose(context -> verifyRequest(tokenRepresentation, context, null))
149+
.compose(context -> verifyRequest(tokenRepresentation, context, message))
143150
.compose(context -> validateCounterParty(context.participantAgent(), context.agreement(), context.transferProcess())));
144151
}
145152

core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/controlplane/services/catalog/CatalogProtocolServiceImplTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ void shouldReturnDataset() {
129129
var participantAgent = createParticipantAgent();
130130
var dataset = createDataset();
131131

132-
when(protocolTokenValidator.verify(eq(tokenRepresentation), any())).thenReturn(ServiceResult.success(participantAgent));
132+
when(protocolTokenValidator.verify(eq(tokenRepresentation), any(), any())).thenReturn(ServiceResult.success(participantAgent));
133133
when(datasetResolver.getById(any(), any(), any())).thenReturn(dataset);
134134

135135
var result = service.getDataset("datasetId", tokenRepresentation, "protocol");
@@ -144,7 +144,7 @@ void shouldFail_whenDatasetIsNull() {
144144
var participantAgent = createParticipantAgent();
145145
var tokenRepresentation = createTokenRepresentation();
146146

147-
when(protocolTokenValidator.verify(eq(tokenRepresentation), any())).thenReturn(ServiceResult.success(participantAgent));
147+
when(protocolTokenValidator.verify(eq(tokenRepresentation), any(), any())).thenReturn(ServiceResult.success(participantAgent));
148148
when(datasetResolver.getById(any(), any(), any())).thenReturn(null);
149149

150150
var result = service.getDataset("datasetId", tokenRepresentation, "protocol");
@@ -156,7 +156,7 @@ void shouldFail_whenDatasetIsNull() {
156156
void shouldFail_whenTokenValidationFails() {
157157
var tokenRepresentation = createTokenRepresentation();
158158

159-
when(protocolTokenValidator.verify(eq(tokenRepresentation), any())).thenReturn(ServiceResult.unauthorized("unauthorized"));
159+
when(protocolTokenValidator.verify(eq(tokenRepresentation), any(), any())).thenReturn(ServiceResult.unauthorized("unauthorized"));
160160

161161
var result = service.getDataset("datasetId", tokenRepresentation, "protocol");
162162

0 commit comments

Comments
 (0)