From b511ae8f84690a85b923aa64bfa83bd5ad2eeddb Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Tue, 15 Aug 2023 22:19:13 +0200 Subject: [PATCH] fix: add binding to tx namespace for credential policy --- core/json-ld-core/build.gradle.kts | 1 + .../tractusx/edc/jsonld/JsonLdExtension.java | 10 +++- .../src/main/resources/document/edc-v1.jsonld | 47 +++++++++++++++++++ .../src/main/resources/document/tx-v1.jsonld | 21 +++++++++ .../BusinessPartnerValidationExtension.java | 4 +- edc-extensions/cx-policy/build.gradle.kts | 1 + .../SummaryConstraintFunctionsProvider.java | 39 +++++++++++---- .../api/edr/dto/NegotiateEdrRequestDto.java | 3 +- .../edc/helpers/PolicyHelperFunctions.java | 30 ++++++++++++ .../edc/tests/catalog/MiwSsiCatalogTest.java | 33 +++++++++++++ .../src/test/resources/framework-policy.json | 24 ++++++++++ .../tractusx/edc/edr/spi/CoreConstants.java | 5 +- 12 files changed, 204 insertions(+), 14 deletions(-) create mode 100644 core/json-ld-core/src/main/resources/document/edc-v1.jsonld create mode 100644 core/json-ld-core/src/main/resources/document/tx-v1.jsonld create mode 100644 edc-tests/e2e-tests/src/test/resources/framework-policy.json diff --git a/core/json-ld-core/build.gradle.kts b/core/json-ld-core/build.gradle.kts index 22bf99e1a..b43a2063e 100644 --- a/core/json-ld-core/build.gradle.kts +++ b/core/json-ld-core/build.gradle.kts @@ -17,6 +17,7 @@ plugins { } dependencies { + implementation(project(":spi:core-spi")) implementation(libs.edc.spi.core) implementation(libs.edc.spi.jsonld) testImplementation(testFixtures(libs.edc.junit)) diff --git a/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java b/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java index aab292b8e..66d33c122 100644 --- a/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java +++ b/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java @@ -29,10 +29,15 @@ import static java.lang.String.format; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.EDC_CONTEXT; +import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_CONTEXT; +import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_NAMESPACE; +import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_PREFIX; public class JsonLdExtension implements ServiceExtension { public static final String CREDENTIALS_V_1 = "https://www.w3.org/2018/credentials/v1"; + public static final String CREDENTIALS_SUMMARY_V_1 = "https://w3id.org/2023/catenax/credentials/summary/v1"; public static final String CREDENTIALS_SUMMARY_V_1_FALLBACK = "https://catenax-ng.github.io/product-core-schemas/SummaryVC.json"; public static final String SECURITY_JWS_V1 = "https://w3id.org/security/suites/jws-2020/v1"; @@ -43,7 +48,9 @@ public class JsonLdExtension implements ServiceExtension { CREDENTIALS_SUMMARY_V_1, PREFIX + "summary-vc-context-v1.jsonld", CREDENTIALS_SUMMARY_V_1_FALLBACK, PREFIX + "summary-vc-context-v1.jsonld", SECURITY_JWS_V1, PREFIX + "security-jws-2020.jsonld", - SECURITY_ED25519_V1, PREFIX + "security-ed25519-2020.jsonld"); + SECURITY_ED25519_V1, PREFIX + "security-ed25519-2020.jsonld", + TX_CONTEXT, PREFIX + "tx-v1.jsonld", + EDC_CONTEXT, PREFIX + "edc-v1.jsonld"); @Inject private JsonLd jsonLdService; @@ -52,6 +59,7 @@ public class JsonLdExtension implements ServiceExtension { @Override public void initialize(ServiceExtensionContext context) { + jsonLdService.registerNamespace(TX_PREFIX, TX_NAMESPACE); FILES.entrySet().stream().map(this::mapToFile) .forEach(result -> result.onSuccess(entry -> jsonLdService.registerCachedDocument(entry.getKey(), entry.getValue())) .onFailure(failure -> monitor.warning("Failed to register cached json-ld document: " + failure.getFailureDetail()))); diff --git a/core/json-ld-core/src/main/resources/document/edc-v1.jsonld b/core/json-ld-core/src/main/resources/document/edc-v1.jsonld new file mode 100644 index 000000000..d539d3e0f --- /dev/null +++ b/core/json-ld-core/src/main/resources/document/edc-v1.jsonld @@ -0,0 +1,47 @@ +{ + "@context": { + "edc": "https://w3id.org/edc/v0.0.1/ns/", + "@vocab": "https://w3id.org/edc/v0.0.1/ns/", + "schema": "http://schema.org/", + "PolicyDefinition": "edc:PolicyDefinition", + "AssetEntryNewDto": "edc:AssetEntryNewDto", + "DataAddress": "edc:DataAddress", + "NegotiationState": "edc:NegotiationState", + "TerminateNegotiation": "edc:TerminateNegotiation", + "ContractRequest": "edc:ContractRequest", + "policy": { + "@id": "edc:policy", + "@type": "@id", + "@context": [ + "http://www.w3.org/ns/odrl.jsonld" + ] + }, + "createdAt": "edc:createdAt", + "properties": "edc:properties", + "privateProperties": "edc:privateProperties", + "dataAddress": "edc:dataAddress", + "type": "edc:type", + "counterPartyAddress": "edc:counterPartyAddress", + "protocol": "edc:protocol", + "querySpec": "edc:querySpec", + "accessPolicyId": "edc:accessPolicyId", + "contractPolicyId": "edc:contractPolicyId", + "assetsSelector": "edc:assetsSelector", + "state": "edc:state", + "reason": "edc:reason", + "connectorAddress": "edc:connectorAddress", + "offer": "edc:offer", + "asset": "edc:asset", + "offerId": "edc:offerId", + "assetId": "edc:assetId", + "contractId": "edc:contractId", + "connectorId": "edc:connectorId", + "callbackAddresses": "edc:callbackAddresses", + "dataDestination": "edc:dataDestination", + "baseUrl": "edc:baseUrl", + "providerId": "edc:providerId", + "uri": "edc:uri", + "events": "edc:events", + "transactional": "edc:transactional" + } +} \ No newline at end of file diff --git a/core/json-ld-core/src/main/resources/document/tx-v1.jsonld b/core/json-ld-core/src/main/resources/document/tx-v1.jsonld new file mode 100644 index 000000000..58d3c974e --- /dev/null +++ b/core/json-ld-core/src/main/resources/document/tx-v1.jsonld @@ -0,0 +1,21 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "tx": "https://w3id.org/tractusx/v0.0.1/ns/", + "BusinessPartnerNumber": "tx:BusinessPartnerNumber", + "NegotiationInitiateRequestDto": "tx:NegotiationInitiateRequestDto", + "BusinessPartnerGroup": "tx:BusinessPartnerGroup", + "EndpointDataReferenceEntry": "tx:EndpointDataReferenceEntry", + "Membership": "tx:Membership", + "Dismantler": "tx:Dismantler", + "FrameworkAgreement.pcf": "tx:FrameworkAgreement.pcf", + "FrameworkAgreement.sustainability": "tx:FrameworkAgreement.sustainability", + "FrameworkAgreement.quality": "tx:FrameworkAgreement.quality", + "FrameworkAgreement.traceability": "tx:FrameworkAgreement.traceability", + "FrameworkAgreement.behavioraltwin": "tx:FrameworkAgreement.behavioraltwin", + "BPN": "tx:BPN", + "expirationDate": "tx:expirationDate", + "edrState": "tx:edrState" + } +} diff --git a/edc-extensions/bpn-validation/bpn-validation-core/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/BusinessPartnerValidationExtension.java b/edc-extensions/bpn-validation/bpn-validation-core/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/BusinessPartnerValidationExtension.java index 7cca8f600..0be759ea8 100644 --- a/edc-extensions/bpn-validation/bpn-validation-core/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/BusinessPartnerValidationExtension.java +++ b/edc-extensions/bpn-validation/bpn-validation-core/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/BusinessPartnerValidationExtension.java @@ -27,6 +27,7 @@ import static org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionResolver.CATALOGING_SCOPE; import static org.eclipse.edc.connector.contract.spi.validation.ContractValidationService.NEGOTIATION_SCOPE; import static org.eclipse.edc.connector.contract.spi.validation.ContractValidationService.TRANSFER_SCOPE; +import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA; /** * Registers a {@link org.eclipse.tractusx.edc.validation.businesspartner.functions.BusinessPartnerGroupFunction} for the following scopes: @@ -49,7 +50,7 @@ *

* Note that the {@link BusinessPartnerGroupFunction} is an {@link org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction}, thus it is registered with the {@link PolicyEngine} for the {@link Permission} class. */ -@Extension(value = "Registers a function to evaluate whether a BPN number is covered by a certain policy or not", categories = {"policy", "contract"}) +@Extension(value = "Registers a function to evaluate whether a BPN number is covered by a certain policy or not", categories = { "policy", "contract" }) public class BusinessPartnerValidationExtension implements ServiceExtension { private static final String USE = "USE"; @@ -71,6 +72,7 @@ public void initialize(ServiceExtensionContext context) { private void bindToScope(BusinessPartnerGroupFunction function, String scope) { ruleBindingRegistry.bind(USE, scope); + ruleBindingRegistry.bind(ODRL_SCHEMA + "use", scope); ruleBindingRegistry.bind(BusinessPartnerGroupFunction.BUSINESS_PARTNER_CONSTRAINT_KEY, scope); policyEngine.registerFunction(scope, Permission.class, BusinessPartnerGroupFunction.BUSINESS_PARTNER_CONSTRAINT_KEY, function); diff --git a/edc-extensions/cx-policy/build.gradle.kts b/edc-extensions/cx-policy/build.gradle.kts index b146181fc..4b7ffd4cf 100644 --- a/edc-extensions/cx-policy/build.gradle.kts +++ b/edc-extensions/cx-policy/build.gradle.kts @@ -17,6 +17,7 @@ plugins { } dependencies { + implementation(project(":spi:core-spi")) implementation(project(":spi:ssi-spi")) implementation(libs.edc.spi.policyengine) implementation(libs.jakartaJson) diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java index a7f27fe8f..8d6d5241f 100644 --- a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java @@ -18,8 +18,12 @@ import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; import org.eclipse.edc.policy.model.Permission; +import java.util.HashMap; import java.util.Map; +import static java.util.Collections.unmodifiableMap; +import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA; +import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_NAMESPACE; import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.CATALOG_REQUEST_SCOPE; import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.CATALOG_SCOPE; import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.NEGOTIATION_REQUEST_SCOPE; @@ -35,16 +39,26 @@ public class SummaryConstraintFunctionsProvider { /** * Mappings from policy constraint left operand values to the corresponding item value in the summary VP. */ - static final Map CREDENTIAL_MAPPINGS = Map.of( - "Membership", "MembershipCredential", - "Dismantler", "DismantlerCredential", - "FrameworkAgreement.pcf", "PcfCredential", - "FrameworkAgreement.sustainability", "SustainabilityCredential", - "FrameworkAgreement.quality", "QualityCredential", - "FrameworkAgreement.traceability", "TraceabilityCredential", - "FrameworkAgreement.behavioraltwin", "BehaviorTwinCredential", - "BPN", "BpnCredential" - ); + static final Map CREDENTIAL_MAPPINGS; + + + static { + var initialMappings = Map.of( + "Membership", "MembershipCredential", + "Dismantler", "DismantlerCredential", + "FrameworkAgreement.pcf", "PcfCredential", + "FrameworkAgreement.sustainability", "SustainabilityCredential", + "FrameworkAgreement.quality", "QualityCredential", + "FrameworkAgreement.traceability", "TraceabilityCredential", + "FrameworkAgreement.behavioraltwin", "BehaviorTwinCredential", + "BPN", "BpnCredential" + ); + var mappings = new HashMap<>(initialMappings); + initialMappings.forEach((credentialName, summaryType) -> { + mappings.put(TX_NAMESPACE + credentialName, summaryType); + }); + CREDENTIAL_MAPPINGS = unmodifiableMap(mappings); + } /** * Configures and registers required summary functions with the policy engine. @@ -84,6 +98,11 @@ public static void registerBindings(RuleBindingRegistry registry) { registry.bind(constraintName, NEGOTIATION_SCOPE); registry.bind(constraintName, TRANSFER_PROCESS_SCOPE); }); + + registry.bind(ODRL_SCHEMA + "use", CATALOG_SCOPE); + registry.bind(ODRL_SCHEMA + "use", NEGOTIATION_SCOPE); + registry.bind(ODRL_SCHEMA + "use", TRANSFER_PROCESS_SCOPE); + } } diff --git a/edc-extensions/edr/edr-api/src/main/java/org/eclipse/tractusx/edc/api/edr/dto/NegotiateEdrRequestDto.java b/edc-extensions/edr/edr-api/src/main/java/org/eclipse/tractusx/edc/api/edr/dto/NegotiateEdrRequestDto.java index b1f018268..318cfb575 100644 --- a/edc-extensions/edr/edr-api/src/main/java/org/eclipse/tractusx/edc/api/edr/dto/NegotiateEdrRequestDto.java +++ b/edc-extensions/edr/edr-api/src/main/java/org/eclipse/tractusx/edc/api/edr/dto/NegotiateEdrRequestDto.java @@ -25,7 +25,8 @@ public class NegotiateEdrRequestDto { - public static final String EDR_REQUEST_DTO_TYPE = TX_NAMESPACE + "NegotiateEdrRequestDto"; + public static final String EDR_REQUEST_SIMPLE_DTO_TYPE = "NegotiateEdrRequestDto"; + public static final String EDR_REQUEST_DTO_TYPE = TX_NAMESPACE + EDR_REQUEST_SIMPLE_DTO_TYPE; public static final String EDR_REQUEST_DTO_CONNECTOR_ADDRESS = EDC_NAMESPACE + "connectorAddress"; public static final String EDR_REQUEST_DTO_PROTOCOL = EDC_NAMESPACE + "protocol"; public static final String EDR_REQUEST_DTO_CONNECTOR_ID = EDC_NAMESPACE + "connectorId"; diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java index 01c0f35a6..d1196453b 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java @@ -15,14 +15,18 @@ package org.eclipse.tractusx.edc.helpers; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.json.Json; import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; import org.eclipse.edc.connector.policy.spi.PolicyDefinition; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; import org.eclipse.edc.policy.model.AtomicConstraint; import org.eclipse.edc.policy.model.Operator; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.Map; @@ -42,6 +46,8 @@ public class PolicyHelperFunctions { private static final String BUSINESS_PARTNER_EVALUATION_KEY = "BusinessPartnerNumber"; private static final String BUSINESS_PARTNER_CONSTRAINT_KEY = TX_NAMESPACE + "BusinessPartnerGroup"; + private static final ObjectMapper MAPPER = JacksonJsonLd.createObjectMapper(); + /** * Creates a {@link PolicyDefinition} using the given ID, that contains equality constraints for each of the given BusinessPartnerNumbers: * each BPN is converted into an {@link AtomicConstraint} {@code BusinessPartnerNumber EQ [BPN]}. @@ -89,6 +95,30 @@ public static JsonObject frameworkPolicy(String id, Map permissi .build(); } + + /** + * Creates a {@link PolicyDefinition} using the given ID, that contains equality constraints for each of the given BusinessPartnerNumbers: + * each BPN is converted into an {@link AtomicConstraint} {@code BusinessPartnerNumber EQ [BPN]}. + */ + public static JsonObject frameworkTemplatePolicy(String id, String frameworkKind) { + var template = fetchFrameworkTemplate().replace("${POLICY_ID}", id).replace("${FRAMEWORK_CREDENTIAL}", frameworkKind); + try { + return MAPPER.readValue(template, JsonObject.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + private static String fetchFrameworkTemplate() { + try (var stream = PolicyHelperFunctions.class.getClassLoader().getResourceAsStream("framework-policy.json")) { + return new String(stream.readAllBytes(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + public static JsonObjectBuilder policyDefinitionBuilder() { return Json.createObjectBuilder() .add(TYPE, EDC_NAMESPACE + "PolicyDefinitionDto"); diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/catalog/MiwSsiCatalogTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/catalog/MiwSsiCatalogTest.java index 97949b703..5cf929984 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/catalog/MiwSsiCatalogTest.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/catalog/MiwSsiCatalogTest.java @@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.tractusx.edc.helpers.CatalogHelperFunctions.getDatasetAssetId; import static org.eclipse.tractusx.edc.helpers.PolicyHelperFunctions.frameworkPolicy; +import static org.eclipse.tractusx.edc.helpers.PolicyHelperFunctions.frameworkTemplatePolicy; import static org.eclipse.tractusx.edc.helpers.PolicyHelperFunctions.noConstraintPolicyDefinition; import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_BPN; import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_DSP_CALLBACK; @@ -85,6 +86,38 @@ void requestCatalog_fulfillsPolicy_shouldReturnOffer() { SOKRATES.createContractDefinition("test-asset-1", "test-def-2", "test-ap2", "test-cp1"); + // act + var catalog = SOKRATES.getCatalogDatasets(SOKRATES); + + // assert + assertThat(catalog).isNotEmpty() + .hasSize(1) + .allSatisfy(co -> { + assertThat(getDatasetAssetId(co)).isEqualTo("test-asset"); + }); + + } + + + @Test + @DisplayName("Verify that Sokrates receives only the offers he is permitted to using @context") + void requestCatalog_fulfillsPolicy_shouldReturnOffer_withContexts() { + // arrange + SOKRATES.createAsset("test-asset"); + SOKRATES.createAsset("test-asset-1"); + + var bpnAccessPolicy = frameworkTemplatePolicy("test-ap1", "BPN"); + var contractPolicy = noConstraintPolicyDefinition("test-cp1"); + var dismantlerAccessPolicy = frameworkTemplatePolicy("test-ap2", "Dismantler"); + + SOKRATES.createPolicy(bpnAccessPolicy); + SOKRATES.createPolicy(contractPolicy); + SOKRATES.createPolicy(dismantlerAccessPolicy); + + SOKRATES.createContractDefinition("test-asset", "test-def", "test-ap1", "test-cp1"); + SOKRATES.createContractDefinition("test-asset-1", "test-def-2", "test-ap2", "test-cp1"); + + // act var catalog = SOKRATES.getCatalogDatasets(SOKRATES); diff --git a/edc-tests/e2e-tests/src/test/resources/framework-policy.json b/edc-tests/e2e-tests/src/test/resources/framework-policy.json new file mode 100644 index 000000000..321aecbe5 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/resources/framework-policy.json @@ -0,0 +1,24 @@ +{ + "@context": [ + "https://w3id.org/edc/v0.0.1", + "https://w3id.org/tractusx/edc/v0.0.1", + "http://www.w3.org/ns/odrl.jsonld" + ], + "@type": "PolicyDefinitionRequest", + "@id": "${POLICY_ID}", + "policy": { + "@type": "Set", + "permission": [ + { + "action": "use", + "constraint": [ + { + "leftOperand": "${FRAMEWORK_CREDENTIAL}", + "operator": "eq", + "rightOperand": "active" + } + ] + } + ] + } +} diff --git a/spi/core-spi/src/main/java/org/eclipse/tractusx/edc/edr/spi/CoreConstants.java b/spi/core-spi/src/main/java/org/eclipse/tractusx/edc/edr/spi/CoreConstants.java index d9bd5e623..369c40fc4 100644 --- a/spi/core-spi/src/main/java/org/eclipse/tractusx/edc/edr/spi/CoreConstants.java +++ b/spi/core-spi/src/main/java/org/eclipse/tractusx/edc/edr/spi/CoreConstants.java @@ -18,7 +18,10 @@ public final class CoreConstants { public static final String TX_PREFIX = "tx"; public static final String TX_NAMESPACE = "https://w3id.org/tractusx/v0.0.1/ns/"; - + public static final String TX_CONTEXT = "https://w3id.org/tractusx/edc/v0.0.1"; + public static final String EDC_CONTEXT = "https://w3id.org/edc/v0.0.1"; + + private CoreConstants() { } }