From e7f8a571f2d89855ee768ae7c103ce04fed4af76 Mon Sep 17 00:00:00 2001 From: Eric Fiege <105237007+efiege@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:48:32 +0200 Subject: [PATCH] fix: Only return `Datasets` with valid `Offers` (#1066) --- CHANGELOG.md | 2 + extensions/dataset-bugfix/build.gradle.kts | 29 ++++ .../edc/dataset/fix/DatasetFixExtension.java | 70 ++++++++++ ...rg.eclipse.edc.spi.system.ServiceExtension | 20 +++ .../build.gradle.kts | 1 + gradle/libs.versions.toml | 1 + settings.gradle.kts | 1 + .../java/de/sovity/edc/e2e/DatasetTest.java | 129 ++++++++++++++++++ 8 files changed, 253 insertions(+) create mode 100644 extensions/dataset-bugfix/build.gradle.kts create mode 100644 extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java create mode 100644 extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension create mode 100644 tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d3532b935..29158730c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ please see [changelog_updates.md](docs/dev/changelog_updates.md). #### Minor Changes +- Only return `Datasets` with valid `Offers` ([#1065](https://github.com/sovity/edc-ce/issues/1065)) + #### Patch Changes - Refactoring: Config as Java Code ([#1051](https://github.com/sovity/edc-ce/pull/1051)) diff --git a/extensions/dataset-bugfix/build.gradle.kts b/extensions/dataset-bugfix/build.gradle.kts new file mode 100644 index 000000000..8f4a914f5 --- /dev/null +++ b/extensions/dataset-bugfix/build.gradle.kts @@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * 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 + ********************************************************************************/ + +plugins { + `java-library` +} + +dependencies { + api(libs.edc.coreSpi) + api(libs.edc.jsonLdSpi) + api(libs.edc.webSpi) + api(libs.edc.dspApiConfiguration) +} diff --git a/extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java b/extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java new file mode 100644 index 000000000..2f3263c98 --- /dev/null +++ b/extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * 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.dataset.fix; + +import jakarta.json.JsonObject; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; +import org.eclipse.edc.protocol.dsp.api.configuration.DspApiConfiguration; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.web.spi.WebService; + +import static jakarta.ws.rs.HttpMethod.GET; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_TYPE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; + +public class DatasetFixExtension implements ServiceExtension { + + + @Inject + private DspApiConfiguration apiConfiguration; + + @Inject + private WebService webService; + + @Override + public void initialize(ServiceExtensionContext context) { + webService.registerResource(apiConfiguration.getContextAlias(), new DatasetFilter()); + } + + private static class DatasetFilter implements ContainerResponseFilter { + + private static final String GET_DATASETS_PATH = "catalog/datasets/"; + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { + if (requestContext.getUriInfo().getPath().contains(GET_DATASETS_PATH) && requestContext.getMethod().equals(GET)) { + if (responseContext.getEntity() instanceof JsonObject jsonObject) { + if (jsonObject.getString(TYPE).equals(DCAT_DATASET_TYPE) && + jsonObject.containsKey(ODRL_POLICY_ATTRIBUTE) && + jsonObject.getJsonArray(ODRL_POLICY_ATTRIBUTE).isEmpty() + ) { + throw new NotFoundException(); + } + } + } + } + } +} diff --git a/extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..b26160fa7 --- /dev/null +++ b/extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,20 @@ +################################################################################# +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# 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 +################################################################################# + +org.eclipse.tractusx.edc.dataset.fix.DatasetFixExtension diff --git a/extensions/sovity-edc-extensions-package/build.gradle.kts b/extensions/sovity-edc-extensions-package/build.gradle.kts index dc4edc6d1..66c98e75c 100644 --- a/extensions/sovity-edc-extensions-package/build.gradle.kts +++ b/extensions/sovity-edc-extensions-package/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { api(project(":extensions:edc-ui-config")) api(project(":extensions:last-commit-info")) api(project(":extensions:wrapper:wrapper")) + api(project(":extensions:dataset-bugfix")) } group = libs.versions.sovityEdcExtensionGroup.get() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e4f3cd36d..78b2f222d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -126,6 +126,7 @@ edc-transferSpi = { module = "org.eclipse.edc:transfer-spi", version.ref = "edc" edc-transformCore = { module = "org.eclipse.edc:transform-core", version.ref = "edc" } edc-transformSpi = { module = "org.eclipse.edc:transform-spi", version.ref = "edc" } edc-vaultFilesystem = { module = "org.eclipse.edc:vault-filesystem", version.ref = "edc" } +edc-webSpi = { module = "org.eclipse.edc:web-spi", version.ref = "edc" } findbugs-jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "findbugs" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 72e602a44..838efe587 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ rootProject.name = "sovity-ce-edc" include(":config") include(":extensions:contract-termination") include(":extensions:database-direct-access") +include(":extensions:dataset-bugfix") include(":extensions:edc-ui-config") include(":extensions:last-commit-info") include(":extensions:mds-logginghouse-binder") diff --git a/tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java b/tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java new file mode 100644 index 000000000..7849715eb --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - init + * + */ + +package de.sovity.edc.e2e; + +import de.sovity.edc.extension.e2e.connector.ConnectorRemote; +import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; +import de.sovity.edc.extension.e2e.extension.Consumer; +import de.sovity.edc.extension.e2e.extension.E2eTestExtension; +import de.sovity.edc.extension.e2e.extension.Provider; +import io.restassured.response.Response; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.Map; +import java.util.UUID; + +import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; +import static io.restassured.http.ContentType.JSON; +import static jakarta.json.Json.createObjectBuilder; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX; +import static org.hamcrest.Matchers.equalTo; + +class DatasetTest { + + @RegisterExtension + private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + + @Test + void canRetrieveOfferedDataset( + @Consumer ConnectorRemote consumerConnector, + @Provider ConnectorConfig providerConfig, + @Provider ConnectorRemote providerConnector) { + // arrange + var assetId = UUID.randomUUID().toString(); + providerConnector.createDataOffer(assetId, "http://example.com"); + + // act & assert + prepareDatasetApiCall( + consumerConnector, + providerConfig.getProtocolApiUrl(), + assetId) + .then() + .statusCode(200) + .body("'edc:description'", equalTo("description")); + } + + @Test + void canNotRetrieveNotOfferedDataset( + @Consumer ConnectorRemote consumerConnector, + @Provider ConnectorConfig providerConfig, + @Provider ConnectorRemote providerConnector) { + // arrange + Map dataSource = Map.of( + EDC_NAMESPACE + "type", "HttpData", + EDC_NAMESPACE + "baseUrl", "http://localhost"); + var assetId = UUID.randomUUID().toString(); + providerConnector.createAsset(assetId, dataSource); + + // act & assert + prepareDatasetApiCall( + consumerConnector, + providerConfig.getProtocolApiUrl(), + assetId) + .then() + .statusCode(502); + } + + @Test + void canNotRetrieveNotOfferedDatasetIfValidOfferAvailable( + @Consumer ConnectorRemote consumerConnector, + @Provider ConnectorConfig providerConfig, + @Provider ConnectorRemote providerConnector) { + // arrange + Map dataSource = Map.of( + EDC_NAMESPACE + "type", "HttpData", + EDC_NAMESPACE + "baseUrl", "http://localhost"); + var notOfferedAssetId = UUID.randomUUID().toString(); + var offeredAssetId = UUID.randomUUID().toString(); + providerConnector.createAsset(notOfferedAssetId, dataSource); + providerConnector.createDataOffer(offeredAssetId, "http://localhost"); + + // act & assert + prepareDatasetApiCall( + consumerConnector, + providerConfig.getProtocolApiUrl(), + notOfferedAssetId) + .then() + .statusCode(502); + + prepareDatasetApiCall( + consumerConnector, + providerConfig.getProtocolApiUrl(), + offeredAssetId) + .then() + .statusCode(200) + .body("'edc:description'", equalTo("description")); + } + + private static Response prepareDatasetApiCall( + ConnectorRemote consumerConnector, + String providerProtocolUrl, + String assetId) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(EDC_NAMESPACE + "counterPartyAddress", providerProtocolUrl) + .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") + .add("@id", assetId) + .build(); + return consumerConnector.prepareManagementApiCall() + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/catalog/dataset/request"); + } +}