From edf2a65ddd74cd58fc53d45de199a85f6fb4a655 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Wed, 21 May 2025 15:02:30 +0200 Subject: [PATCH 1/5] docs: participant identity for dsp version --- .../README.md | 81 +++++++++++++++++++ docs/developer/decision-records/README.md | 1 + 2 files changed, 82 insertions(+) create mode 100644 docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md diff --git a/docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md b/docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md new file mode 100644 index 0000000000..f7df5cddfa --- /dev/null +++ b/docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md @@ -0,0 +1,81 @@ +# Participant identity for DSP version + +## Decision + +We'll set up extension points to permit to use different DSP identifiers with different protocol versions. +This will also open up the possibility to manage different Dataspaces in the same connector. + +## Rationale + +At the moment the way the identifier is either put in DSP artifacts as Catalogs and Contract Agreements and the way it +is extracted from the counter-party credentials is hardcoded. +So if a Dataspace decides to chan the identifier starting from a specific DSP version, currently this is not +possible. +In the long term vision about having the connector being able to manage multiple dataspace, and potentially multiple +identifiers this refactoring activity becomes mandatory. + +## Approach + +The changes will happen in 2 different contexts: ingress and egress. + +### Ingress +When a new message is received on the DSP protocol the connector will have the possibility to decide how to extract the +id from the claim token based on the protocol version. + +Currently this is done in the `ParticipantAgentService.createFor(ClaimToken token)` method, in which a list of registered +`ParticipantAgentServiceExtension` gets executed, returning a `Map`. These attributes gets then added to +the `ParticipantAgent`, and, if one has the `edc:identity`, then it gets considered as the participant id: + +```java + @Override + public ParticipantAgent createFor(ClaimToken token) { + var attributes = new HashMap(); + extensions.stream().map(extension -> extension.attributesFor(token)).forEach(attributes::putAll); + if (!attributes.containsKey(PARTICIPANT_IDENTITY)) { + var claim = token.getClaim(identityClaimKey); + if (claim != null) { + attributes.put(PARTICIPANT_IDENTITY, claim.toString()); + } + } + return new ParticipantAgent(token.getClaims(), attributes); + } +``` + +This approach is in any case quite confusing, because the identifier is a mandatory property in a `ParticipantAgent`, but +now it's considered "nullable", while there are a lot of validations that are checking that identifier should not be null, +like: +- [`ValidatedConsumerOffer`](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/spi/control-plane/contract-spi/src/main/java/org/eclipse/edc/connector/controlplane/contract/spi/validation/ValidatedConsumerOffer.java#L30) +- pretty much every method in [`ContractValidationService`](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/core/control-plane/control-plane-contract/src/main/java/org/eclipse/edc/connector/controlplane/contract/validation/ContractValidationServiceImpl.java#L76-L77) + validates this +- [`ContractValidationService` 2](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/core/control-plane/control-plane-contract/src/main/java/org/eclipse/edc/connector/controlplane/contract/validation/ContractValidationServiceImpl.java#L90-L93) + +So the proposal here is to: +- make the `ParticipantAgent` have a non-null `id` field, if no id can be provided, the call must return an unauthorized + as soon as possible, likely in the [`DspRequestHandler`](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/data-protocols/dsp/dsp-core/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/message/DspRequestHandlerImpl.java) +- have the `ParticipantAgent` created in the `DspRequestHandler` before doing the service call, and the service call + will receive the `ParticipantAgent` instance instead of the `TokenRepresentation` (that's only used to generate the + `ParticipantAgent` instance in any case). +- In the `ProtocolTokenValidator` there will be a `ParticipantAgentIdExtractorRegistry` that, based on the protocol version + will call a specific `ParticipantAgentIdExtractor` with this signature: + ```java + String extractParticipantIdentity(ClaimToken token); + ``` + by default, it will have the same implementation provided by `DefaultDcpParticipantAgentServiceExtension`, then adopters + can register custom extractors for different versions. + +### Egress +In the outbound communication there are two places in which the participant id is set: +- [`ProviderContractNegotiationManager`](https://github.com/eclipse-edc/Connector/blob/f491d2fe83a69e113bdcb2f89b8c0f556e555ef9/core/control-plane/control-plane-contract/src/main/java/org/eclipse/edc/connector/controlplane/contract/negotiation/ProviderContractNegotiationManagerImpl.java#L137-L148) + during the `ContractAgreement` creation, here the `ParticipantAgentIdExtractorRegistry` will be used again, by passing +- [`CatalogProtocolService`](https://github.com/eclipse-edc/Connector/blob/f491d2fe83a69e113bdcb2f89b8c0f556e555ef9/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/catalog/CatalogProtocolServiceImpl.java#L64) + +To permit the runtime to choose which id to set, a `ParticipantIdProvider` service will be introduced: +```java +interface ParticipantIdProvider { + String participantId(String protocol); +} +``` + +The default implementation will return the `context.getParticipantId()` value, while adopters would be able to chose to +use different values for different protocol versions. + diff --git a/docs/developer/decision-records/README.md b/docs/developer/decision-records/README.md index e55dec308f..a70ed6f9a4 100644 --- a/docs/developer/decision-records/README.md +++ b/docs/developer/decision-records/README.md @@ -79,3 +79,4 @@ - [2025-03-14 Prioritized Transfer Services](./2025-03-14-prioritized-transfer-services) - [2025-04-15 Contract Agreement policy scope](./2025-04-25-agreement-policy-scope) - [2025-04-30 Finalize phase](./2025-04-30-finalize-phase) +- [2024-05-21 Participant identity DSP version](./2025-05-21-participant-identity-dsp-version) From a30728b2e262429a688b863628a986014c3da21c Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Thu, 29 May 2025 09:22:35 +0200 Subject: [PATCH 2/5] adapt to dataspace context --- .../README.md | 81 ------------------- .../2025-05-28-dataspace-context/README.md | 41 ++++++++++ docs/developer/decision-records/README.md | 2 +- 3 files changed, 42 insertions(+), 82 deletions(-) delete mode 100644 docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md create mode 100644 docs/developer/decision-records/2025-05-28-dataspace-context/README.md diff --git a/docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md b/docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md deleted file mode 100644 index f7df5cddfa..0000000000 --- a/docs/developer/decision-records/2025-05-21-participant-identity-dsp-version/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Participant identity for DSP version - -## Decision - -We'll set up extension points to permit to use different DSP identifiers with different protocol versions. -This will also open up the possibility to manage different Dataspaces in the same connector. - -## Rationale - -At the moment the way the identifier is either put in DSP artifacts as Catalogs and Contract Agreements and the way it -is extracted from the counter-party credentials is hardcoded. -So if a Dataspace decides to chan the identifier starting from a specific DSP version, currently this is not -possible. -In the long term vision about having the connector being able to manage multiple dataspace, and potentially multiple -identifiers this refactoring activity becomes mandatory. - -## Approach - -The changes will happen in 2 different contexts: ingress and egress. - -### Ingress -When a new message is received on the DSP protocol the connector will have the possibility to decide how to extract the -id from the claim token based on the protocol version. - -Currently this is done in the `ParticipantAgentService.createFor(ClaimToken token)` method, in which a list of registered -`ParticipantAgentServiceExtension` gets executed, returning a `Map`. These attributes gets then added to -the `ParticipantAgent`, and, if one has the `edc:identity`, then it gets considered as the participant id: - -```java - @Override - public ParticipantAgent createFor(ClaimToken token) { - var attributes = new HashMap(); - extensions.stream().map(extension -> extension.attributesFor(token)).forEach(attributes::putAll); - if (!attributes.containsKey(PARTICIPANT_IDENTITY)) { - var claim = token.getClaim(identityClaimKey); - if (claim != null) { - attributes.put(PARTICIPANT_IDENTITY, claim.toString()); - } - } - return new ParticipantAgent(token.getClaims(), attributes); - } -``` - -This approach is in any case quite confusing, because the identifier is a mandatory property in a `ParticipantAgent`, but -now it's considered "nullable", while there are a lot of validations that are checking that identifier should not be null, -like: -- [`ValidatedConsumerOffer`](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/spi/control-plane/contract-spi/src/main/java/org/eclipse/edc/connector/controlplane/contract/spi/validation/ValidatedConsumerOffer.java#L30) -- pretty much every method in [`ContractValidationService`](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/core/control-plane/control-plane-contract/src/main/java/org/eclipse/edc/connector/controlplane/contract/validation/ContractValidationServiceImpl.java#L76-L77) - validates this -- [`ContractValidationService` 2](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/core/control-plane/control-plane-contract/src/main/java/org/eclipse/edc/connector/controlplane/contract/validation/ContractValidationServiceImpl.java#L90-L93) - -So the proposal here is to: -- make the `ParticipantAgent` have a non-null `id` field, if no id can be provided, the call must return an unauthorized - as soon as possible, likely in the [`DspRequestHandler`](https://github.com/eclipse-edc/Connector/blob/3f59ef6db98153e96750d637d19d8141faeb7a95/data-protocols/dsp/dsp-core/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/message/DspRequestHandlerImpl.java) -- have the `ParticipantAgent` created in the `DspRequestHandler` before doing the service call, and the service call - will receive the `ParticipantAgent` instance instead of the `TokenRepresentation` (that's only used to generate the - `ParticipantAgent` instance in any case). -- In the `ProtocolTokenValidator` there will be a `ParticipantAgentIdExtractorRegistry` that, based on the protocol version - will call a specific `ParticipantAgentIdExtractor` with this signature: - ```java - String extractParticipantIdentity(ClaimToken token); - ``` - by default, it will have the same implementation provided by `DefaultDcpParticipantAgentServiceExtension`, then adopters - can register custom extractors for different versions. - -### Egress -In the outbound communication there are two places in which the participant id is set: -- [`ProviderContractNegotiationManager`](https://github.com/eclipse-edc/Connector/blob/f491d2fe83a69e113bdcb2f89b8c0f556e555ef9/core/control-plane/control-plane-contract/src/main/java/org/eclipse/edc/connector/controlplane/contract/negotiation/ProviderContractNegotiationManagerImpl.java#L137-L148) - during the `ContractAgreement` creation, here the `ParticipantAgentIdExtractorRegistry` will be used again, by passing -- [`CatalogProtocolService`](https://github.com/eclipse-edc/Connector/blob/f491d2fe83a69e113bdcb2f89b8c0f556e555ef9/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/catalog/CatalogProtocolServiceImpl.java#L64) - -To permit the runtime to choose which id to set, a `ParticipantIdProvider` service will be introduced: -```java -interface ParticipantIdProvider { - String participantId(String protocol); -} -``` - -The default implementation will return the `context.getParticipantId()` value, while adopters would be able to chose to -use different values for different protocol versions. - diff --git a/docs/developer/decision-records/2025-05-28-dataspace-context/README.md b/docs/developer/decision-records/2025-05-28-dataspace-context/README.md new file mode 100644 index 0000000000..ec5c174520 --- /dev/null +++ b/docs/developer/decision-records/2025-05-28-dataspace-context/README.md @@ -0,0 +1,41 @@ +# Dataspace Context + +## Decision + +We'll introduce the concept of "Dataspace context", that will permit a connector to being able to interact with multiple +dataspaces with potential different protocol versions, authentication and profiles + +## Rationale + +At the moment the EDC connector only permits to support different protocol version at the same time, by having pluggable +modules that add support for them. + +A Dataspace context is a more hi level concept that enables to define a set of components that will permit the connector +to interact also with different dataspaces, by defining a set of these capabilities: +- wire protocol, version and binding +- authentication protocol +- identifier +- scopes +- ... + +## Approach + +A Dataspace context will be bound to a single DSP endpoint. + +Please note that will be possible to define multiple contexts for a single protocol version, there will be an api context +for every dataspace. + +By default, there will be a single context registered for every DSP module (v0.8, 2024/1, 2025/1, ...) with default identity +service (DCP), default identifier (DID) and so on. + +The adopter will then be able to override these ones with dataspace specific contexts with potentially different capabilities. +That could be done through configuration, under the `edc.dataspace.context` group. +If no setting is found, the current default `protocol` context will be used, otherwise: + +``` +edc.dataspace.context..protocol=dataspace-protocol-http:2025/1 +edc.dataspace.context..auth=dcp:1.0 +edc.dataspace.context.... +``` + +Details about how to configure specific capabilities will come in the actual implementations. diff --git a/docs/developer/decision-records/README.md b/docs/developer/decision-records/README.md index a70ed6f9a4..1860b6e7e4 100644 --- a/docs/developer/decision-records/README.md +++ b/docs/developer/decision-records/README.md @@ -79,4 +79,4 @@ - [2025-03-14 Prioritized Transfer Services](./2025-03-14-prioritized-transfer-services) - [2025-04-15 Contract Agreement policy scope](./2025-04-25-agreement-policy-scope) - [2025-04-30 Finalize phase](./2025-04-30-finalize-phase) -- [2024-05-21 Participant identity DSP version](./2025-05-21-participant-identity-dsp-version) +- [2024-05-28 Dataspace Context](2025-05-28-dataspace-context) From d9508a2f602108eaa344d1551857032e697b62c1 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Mon, 9 Jun 2025 17:15:14 +0200 Subject: [PATCH 3/5] pr remarks --- .../2025-05-28-dataspace-context/README.md | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/docs/developer/decision-records/2025-05-28-dataspace-context/README.md b/docs/developer/decision-records/2025-05-28-dataspace-context/README.md index ec5c174520..c96dd5c4c0 100644 --- a/docs/developer/decision-records/2025-05-28-dataspace-context/README.md +++ b/docs/developer/decision-records/2025-05-28-dataspace-context/README.md @@ -2,33 +2,30 @@ ## Decision -We'll introduce the concept of "Dataspace context", that will permit a connector to being able to interact with multiple -dataspaces with potential different protocol versions, authentication and profiles +We'll introduce the concept of "Dataspace context", which will enable a connector runtime to serve requests for multiple +dataspaces with potentially different protocol versions, authentication, and profiles. ## Rationale -At the moment the EDC connector only permits to support different protocol version at the same time, by having pluggable -modules that add support for them. +At the moment the EDC connector only supports multiple protocol versions at the same time, by having pluggable +modules. -A Dataspace context is a more hi level concept that enables to define a set of components that will permit the connector -to interact also with different dataspaces, by defining a set of these capabilities: +A Dataspace context is a higher-level concept that defines a configuration set and code required to service a request for a particular dataspace. +This includes: - wire protocol, version and binding - authentication protocol - identifier - scopes -- ... +- policy vocabulary and functions ## Approach A Dataspace context will be bound to a single DSP endpoint. -Please note that will be possible to define multiple contexts for a single protocol version, there will be an api context -for every dataspace. - -By default, there will be a single context registered for every DSP module (v0.8, 2024/1, 2025/1, ...) with default identity +By default, there will be a single dataspace context registered for every DSP module (v0.8, 2024/1, 2025/1, ...) with default identity service (DCP), default identifier (DID) and so on. -The adopter will then be able to override these ones with dataspace specific contexts with potentially different capabilities. +The adopter will then be able to override these with dataspace specific contexts with potentially different capabilities. That could be done through configuration, under the `edc.dataspace.context` group. If no setting is found, the current default `protocol` context will be used, otherwise: From 396fb209d82b870fe1238ee3e803e417059f19f3 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Wed, 11 Jun 2025 14:27:34 +0200 Subject: [PATCH 4/5] adapt proposal --- .../2025-05-28-dataspace-context/README.md | 38 ---------------- .../README.md | 43 +++++++++++++++++++ docs/developer/decision-records/README.md | 2 +- 3 files changed, 44 insertions(+), 39 deletions(-) delete mode 100644 docs/developer/decision-records/2025-05-28-dataspace-context/README.md create mode 100644 docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md diff --git a/docs/developer/decision-records/2025-05-28-dataspace-context/README.md b/docs/developer/decision-records/2025-05-28-dataspace-context/README.md deleted file mode 100644 index c96dd5c4c0..0000000000 --- a/docs/developer/decision-records/2025-05-28-dataspace-context/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Dataspace Context - -## Decision - -We'll introduce the concept of "Dataspace context", which will enable a connector runtime to serve requests for multiple -dataspaces with potentially different protocol versions, authentication, and profiles. - -## Rationale - -At the moment the EDC connector only supports multiple protocol versions at the same time, by having pluggable -modules. - -A Dataspace context is a higher-level concept that defines a configuration set and code required to service a request for a particular dataspace. -This includes: -- wire protocol, version and binding -- authentication protocol -- identifier -- scopes -- policy vocabulary and functions - -## Approach - -A Dataspace context will be bound to a single DSP endpoint. - -By default, there will be a single dataspace context registered for every DSP module (v0.8, 2024/1, 2025/1, ...) with default identity -service (DCP), default identifier (DID) and so on. - -The adopter will then be able to override these with dataspace specific contexts with potentially different capabilities. -That could be done through configuration, under the `edc.dataspace.context` group. -If no setting is found, the current default `protocol` context will be used, otherwise: - -``` -edc.dataspace.context..protocol=dataspace-protocol-http:2025/1 -edc.dataspace.context..auth=dcp:1.0 -edc.dataspace.context.... -``` - -Details about how to configure specific capabilities will come in the actual implementations. diff --git a/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md b/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md new file mode 100644 index 0000000000..e3f8f8aafa --- /dev/null +++ b/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md @@ -0,0 +1,43 @@ +# Dataspace Profile Context + +## Decision + +We'll introduce the concept of "Dataspace profile context", which will enable a connector runtime to serve requests for multiple +dataspaces with potentially different protocol versions, authentication, vocabulary and policies. + +## Rationale + +At the moment the EDC connector only supports multiple protocol versions at the same time, by having pluggable +modules. + +The Dataspace Profile Ccontext is an higher-level concept that defines a set of: +- wire protocol, version and binding +- authentication protocol +- policy functions +- vocabulary (jsonld context) +- scopes +- identifier resolution +- ... + +## Approach + +The Dataspace profile context will be defined at compile time, so it will up to the adopters to define their profiles. +A `DataspaceProfileContextRegistry` service will be in place, on which a `DataspaceProfileContext` can be registered. + +By default, there will be an hardcoded context that uses a particular combination of DSP, DSP, vocabulary and so on; such +version will be useful for testing and samples, but for a production use the adopters must explicitly define and register +the expected dataspace contexts by extension. + +So, for example, if a connector is supposed to support multiple DSP version, there will be the need to explicitly register +one profile for every version, same will happen with multiple DCP version and so on. + +Every profile will be represented by a different protocol endpoint, and it will be advertised in the `.well-known/dspace.version` +endpoint. + +### Additional Notes +To be backward compatible, the `profile` information will be passed to management-api and stored as `protocol`, so out of +the box the default profile name will be the DSP version. In the future this could be adapted and the `protocol` attribute/field +could be renamed to `profile`, but there's no urgency to do that. + +To permit certain assets to be published only on certain profiles the `assetsSelector` field of the `ContractDefinition` +can be used, no plans to have a strict correlation between Assets and Dataspace Profile Contexts at the moment. diff --git a/docs/developer/decision-records/README.md b/docs/developer/decision-records/README.md index 1860b6e7e4..8dba09a72e 100644 --- a/docs/developer/decision-records/README.md +++ b/docs/developer/decision-records/README.md @@ -79,4 +79,4 @@ - [2025-03-14 Prioritized Transfer Services](./2025-03-14-prioritized-transfer-services) - [2025-04-15 Contract Agreement policy scope](./2025-04-25-agreement-policy-scope) - [2025-04-30 Finalize phase](./2025-04-30-finalize-phase) -- [2024-05-28 Dataspace Context](2025-05-28-dataspace-context) +- [2024-06-11 Dataspace Profile Context](2025-05-28-dataspace-profile-context) From 4e2a3019741e9320d63aa8d3d473901919744884 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Wed, 11 Jun 2025 16:23:14 +0200 Subject: [PATCH 5/5] pr remarks --- .../2025-05-28-dataspace-profile-context/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md b/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md index e3f8f8aafa..af474a3189 100644 --- a/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md +++ b/docs/developer/decision-records/2025-05-28-dataspace-profile-context/README.md @@ -17,11 +17,9 @@ The Dataspace Profile Ccontext is an higher-level concept that defines a set of: - vocabulary (jsonld context) - scopes - identifier resolution -- ... ## Approach -The Dataspace profile context will be defined at compile time, so it will up to the adopters to define their profiles. A `DataspaceProfileContextRegistry` service will be in place, on which a `DataspaceProfileContext` can be registered. By default, there will be an hardcoded context that uses a particular combination of DSP, DSP, vocabulary and so on; such