diff --git a/CHANGELOG.md b/CHANGELOG.md index a8e185980..6a55e5e8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +## [2.2.2] - 2023-11-21 +### Added +- Added oauth security for sde public api. +- BPN url add API path. + +### Fixed +- Correct dataplane endpoint for digital twin. +- DSP endpoint path for digital-twin edc url. + ## [2.2.1] - 2023-11-27 ### Fix - Update PCF schema fields for SDE diff --git a/INSTALL.md b/INSTALL.md index bd6ae0754..a7bf48033 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -27,13 +27,13 @@ For more details, please refer configuration section from [README.md](README.md) ``` ### RUN SDE Backend Locally #### Prerequisites -- JDK18 -- Postgres 11.9.13 +- JDK17 +- Postgres 12.12.10 #### Steps 1. Clone the GitHub Repository - https://github.com/eclipse-tractusx/managed-simple-data-exchanger-backend. 2. Get your instance of postgres running (Create **dftdb** new database). -3. Setup your project environment to JDK 18. +3. Setup your project environment to JDK 17. 4. Provide require application configuration in application.properties as specified in step configuration.properties. 5. Start the SDE spring boot application from your IDE using main class or use spring CLI. diff --git a/NOTICE.md b/NOTICE.md index 8d5f49436..788f18cee 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -29,7 +29,7 @@ SPDX-License-Identifier: Apache-2.0 The project maintains the following source code repositories in the GitHub organization https://github.com/eclipse-tractusx: -* https://github.com/eclipse-tractusx/dft-backend +* https://github.com/eclipse-tractusx/managed-simple-data-exchanger-backend ## Third-party Content diff --git a/README.md b/README.md index c0343eaa7..dd71f8e3a 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,15 @@ Listed below are configuration keys needed to get the `sde-backend` up and runni | digital-twins.authentication.clientSecret | X | your secrete | Digital twin registry secrete | | digital-twins.authentication.grantType | X | client_credentials | Default value, no need to change | | edc.hostname | X | https://example.provider-connector.com | Your EDC provider connector url | +| edc.managementpath | X | default | edc provider management path | | edc.apiKeyHeader | X | x-api-key | Your connector api key | | edc.apiKey | X | yourpass | Your connector apikey value | | edc.consumer.hostname | X | https://example.consumer-connector.com | Your EDC consumer connector | | edc.consumer.apikeyheader | X | x-api-key | Your connector api key | | edc.consumer.apikey | X | yourpass | Your connector apikey value | | edc.consumer.datauri | X | /api/v1/ids/data | IDS endpoint path | +| edc.consumer.protocol.path | X | default | edc consumer protocol path | +| edc.consumer.managementpath | X | default | edc consumer management path | | dft.hostname | X | https://example.sdehost.com | Your SDE hostname | | dft.apiKeyHeader | X | API_KEY | Your default key | | dft.apiKey | X | yourpass | Your default key password | @@ -77,7 +80,22 @@ Listed below are configuration keys needed to get the `sde-backend` up and runni | connector.discovery.clientId | X | default | client ID for connector discovery | | connector.discovery.clientSecret | X | default | password for connector discovery | | portal.backend.hostname | X | default | Portal backend svc URL based on BPN| -| springdoc.api-docs.path | X | /api-docs | swagger API path | +| springdoc.api-docs.path | X | default | swagger API path | +| bpndiscovery.hostname | X | default | bpn discovery hostname | +| discovery.authentication.url | X | default | discovery authentication url | +| discovery.clientId | X | default | discovery clientId | +| discovery.clientSecret | X | default | discovery clientSecret | +| discovery.grantType | X | default | discovery grantType | +| partner.pool.hostname | X | default | partner pool hostname | +| partner.pool.authentication.url | X | default | partner pool authentication url | +| partner.pool.clientId | X | default | partner pool clientId | +| partner.pool.clientSecret | X | default | partner pool clientSecret | +| partner.pool.grantType | X | default | partner pool grantType | +| portal.backend.hostname | X | default | portal backend hostname | +| portal.backend.authentication.url | X | default | portal authentication url | +| portal.backend.clientId | X | default | portal clientId | +| portal.backend.clientSecret | X | default | portal clientSecret | +| portal.backend.grantType | X | default | portal grantType | #### Example Configuration/application.properties @@ -170,6 +188,24 @@ portal.backend.authentication.url=default portal.backend.clientId=default portal.backend.clientSecret=default portal.backend.grantType=default +bpndiscovery.hostname=default +discovery.authentication.url=default +discovery.clientId=default +discovery.clientSecret=default +discovery.grantType=default +edc.consumer.protocol.path=default +edc.consumer.managementpath=default +edc.managementpath=default +partner.pool.hostname=default +partner.pool.authentication.url=default +partner.pool.clientId=default +partner.pool.clientSecret=default +partner.pool.grantType=default +portal.backend.hostname=default +portal.backend.authentication.url=default +portal.backend.clientId=default +portal.backend.clientSecret=default +portal.backend.grantType=default ``` The above configuration we can use as for different deployment as specified here [InstallationGuide.md](InstallationGuide.md) @@ -329,7 +365,8 @@ Eclipse Tractus-X product(s) installed within the image: - Project license: [Apache License, Version 2.0] https://github.com/eclipse-tractusx/managed-simple-data-exchanger-backend/blob/main/LICENSE **Used base image** -- [eclipse-temurin:19-jdk-jammy](https://github.com/adoptium/containers) +- [eclipse-temurin:17.0.9_9-jdk-jammy](https://github.com/adoptium/containers) +ners) - Official Eclipse Temurin DockerHub page: https://hub.docker.com/_/eclipse-temurin - Eclipse Temurin Project: https://projects.eclipse.org/projects/adoptium.temurin - Additional information about the Eclipse Temurin images: https://github.com/docker-library/repo-info/tree/master/repos/eclipse-temurin diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/ApiHeaderAuthFilter.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/ApiHeaderAuthFilter.java deleted file mode 100644 index 6a1d5f512..000000000 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/ApiHeaderAuthFilter.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022, 2023 T-Systems International GmbH - * Copyright (c) 2022, 2023 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.sde.configuration; - -import java.io.IOException; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.GenericFilterBean; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Configuration -public class ApiHeaderAuthFilter extends GenericFilterBean { - - @Value("${dft.apiKeyHeader}") - private String apiKeyHeader; - - @Value("${dft.apiKey}") - private String apiKeyValue; - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - - var request = (HttpServletRequest) servletRequest; - var response = (HttpServletResponse) servletResponse; - - String authHeaderValue = request.getHeader(apiKeyHeader); - String url = request.getRequestURI(); - - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - - if (url.contains("/public") && !apiKeyValue.equals(authHeaderValue)) { - log.error("**** ApiHeaderAuthFilter genreated Unauthorized response for public api *****************"); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - } else if(auth !=null && auth.getAuthorities()!=null && auth.getAuthorities().isEmpty()){ - log.error("**** ApiHeaderAuthFilter The resource/client is not allowed to access *****************"); - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - } else { - filterChain.doFilter(servletRequest, servletResponse); - } - } -} \ No newline at end of file diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/SecurityConfig.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/SecurityConfig.java index bed20debb..6f699dcc3 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/SecurityConfig.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/SecurityConfig.java @@ -54,7 +54,7 @@ @EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { - private static final String[] PUBLIC_URL = { "/ping", "/cache/**", "/*/public/**", "/api-docs/**", "/swagger-ui/**", + private static final String[] PUBLIC_URL = { "/ping", "/cache/**", "/api-docs/**", "/swagger-ui/**", "*/swagger-ui/**", "/actuator/health/readiness", "/actuator/health/liveness", "/v3/api-docs/**" }; @Value("${keycloak.clientid}") diff --git a/modules/sde-core/src/main/resources/application.properties b/modules/sde-core/src/main/resources/application.properties index 34288b343..bd6537192 100644 --- a/modules/sde-core/src/main/resources/application.properties +++ b/modules/sde-core/src/main/resources/application.properties @@ -74,6 +74,8 @@ edc.hostname= edc.managementpath=/data/v2 edc.apiKeyHeader= edc.apiKey= +edc.dsp.endpointpath=/api/v1/dsp +edc.dataplane.endpointpath=/api/public ## EDC Consumer edc.consumer.hostname= diff --git a/modules/sde-external-services/bpn-discovery/src/main/java/org/eclipse/tractusx/sde/bpndiscovery/api/IBpndiscoveryExternalServiceApi.java b/modules/sde-external-services/bpn-discovery/src/main/java/org/eclipse/tractusx/sde/bpndiscovery/api/IBpndiscoveryExternalServiceApi.java index 01b9a5da6..9f94b4bc2 100644 --- a/modules/sde-external-services/bpn-discovery/src/main/java/org/eclipse/tractusx/sde/bpndiscovery/api/IBpndiscoveryExternalServiceApi.java +++ b/modules/sde-external-services/bpn-discovery/src/main/java/org/eclipse/tractusx/sde/bpndiscovery/api/IBpndiscoveryExternalServiceApi.java @@ -36,17 +36,17 @@ @FeignClient(value = "IBpndiscoveryExternalServiceApi", url = "${bpndiscovery.hostname}", configuration = BpndiscoveryExternalServiceApi.class) public interface IBpndiscoveryExternalServiceApi { - @PostMapping(path = "/api/administration/connectors/bpnDiscovery") + @PostMapping(path = "/administration/connectors/bpnDiscovery") BpnDiscoveryResponse bpnDiscoveryDataByKey(@RequestBody BpnDiscoveryRequest bpnDiscoveryKey); - @PostMapping(path = "/api/administration/connectors/bpnDiscovery/batch") + @PostMapping(path = "/administration/connectors/bpnDiscovery/batch") List bpnDiscoveryBatchDataByList( @RequestBody List bpnDiscoveryKeyList); - @PostMapping(path = "/api/administration/connectors/bpnDiscovery/search") + @PostMapping(path = "/administration/connectors/bpnDiscovery/search") BpnDiscoverySearchResponse bpnDiscoverySearchData(@RequestBody BpnDiscoverySearchRequest bpnDiscoverySearchRequest); - @DeleteMapping(path = "/api/administration/connectors/bpnDiscovery/{resourceId}") + @DeleteMapping(path = "/administration/connectors/bpnDiscovery/{resourceId}") ResponseEntity deleteBpnDiscoveryData(@PathVariable String resourceId); } diff --git a/modules/sde-external-services/digital-twins/src/main/java/org/eclipse/tractusx/sde/digitaltwins/facilitator/DigitalTwinsUtility.java b/modules/sde-external-services/digital-twins/src/main/java/org/eclipse/tractusx/sde/digitaltwins/facilitator/DigitalTwinsUtility.java index d2cb2f7fb..dc870bd02 100644 --- a/modules/sde-external-services/digital-twins/src/main/java/org/eclipse/tractusx/sde/digitaltwins/facilitator/DigitalTwinsUtility.java +++ b/modules/sde-external-services/digital-twins/src/main/java/org/eclipse/tractusx/sde/digitaltwins/facilitator/DigitalTwinsUtility.java @@ -59,9 +59,12 @@ public class DigitalTwinsUtility { @Value(value = "${manufacturerId}") public String manufacturerId; - @Value(value = "${edc.hostname}") - public String edcEndpoint; - + @Value(value = "${edc.hostname}${edc.dsp.endpointpath:/api/v1/dsp}") + public String digitalTwinEdcDspEndpoint; + + @Value(value = "${edc.hostname}${edc.dataplane.endpointpath:/api/public}") + public String digitalTwinEdcDataplaneEndpoint; + ObjectMapper mapper = new ObjectMapper(); private static final Map> publicReadableSpecificAssetIDs = Map.of(MANUFACTURER_PART_ID, @@ -112,12 +115,12 @@ public List prepareDtEndpoint(String shellId, String submodelIdentific List endpoints = new ArrayList<>(); endpoints.add(Endpoint.builder().endpointInterface(CommonConstants.INTERFACE) .protocolInformation(ProtocolInformation.builder() - .endpointAddress(edcEndpoint + CommonConstants.SUBMODEL_CONTEXT_URL) + .endpointAddress(digitalTwinEdcDataplaneEndpoint) .endpointProtocol(CommonConstants.HTTP) .endpointProtocolVersion(List.of(CommonConstants.ENDPOINT_PROTOCOL_VERSION)) .subProtocol(CommonConstants.SUB_PROTOCOL) - .subprotocolBody(encodedUrl("id=" + shellId + "-" + submodelIdentification) + ";dspEndpoint=" - + edcEndpoint) + .subprotocolBody("id=" + shellId + "-" + submodelIdentification + ";dspEndpoint=" + + digitalTwinEdcDspEndpoint) .subprotocolBodyEncoding(CommonConstants.BODY_ENCODING) .securityAttributes(List.of(new SecurityAttributes("NONE", "NONE", "NONE"))).build()) .build()); @@ -144,7 +147,7 @@ public List getSpecificAssetIds(Map specificAssetIds, Li specificIdentifiers.add(new KeyValuePair(entry.getKey(), entry.getValue(), externalSubjectId)); } else { - if (keyList != null && !keyList.isEmpty()) { + if (keyList != null && !keyList.isEmpty() && !entry.getValue().isEmpty()) { externalSubjectId = ExternalSubjectId.builder() .type("ExternalReference").keys(keyList) @@ -172,10 +175,6 @@ private List bpnKeyRefrence(List bpns) { return Collections.emptyList(); } - private String encodedUrl(String format) { - return format.replace(":", "%3A"); - } - private String getFieldFromJsonNode(JsonNode jnode, String fieldName) { if (jnode.get(fieldName) != null) return jnode.get(fieldName).asText(); diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/ContractOfferCatalogApi.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/ContractOfferCatalogApi.java index 4cd20502e..d3f510edd 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/ContractOfferCatalogApi.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/ContractOfferCatalogApi.java @@ -26,7 +26,7 @@ import com.fasterxml.jackson.databind.JsonNode; -@FeignClient(value = "ContractOfferCatalogApi", url = "${edc.consumer.hostname}${edc.consumer.managementpath:/data/v2}", configuration = EDCDataConsumerConfiguration.class) +@FeignClient(value = "ContractOfferCatalogApi", url = "${edc.consumer.hostname}${edc.consumer.managementpath:/data}${edc.consumer.managementpath.apiversion:/v2}", configuration = EDCDataConsumerConfiguration.class) public interface ContractOfferCatalogApi { @PostMapping(value = "/catalog/request") diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java index 91939c674..a24ab7bd5 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java @@ -31,7 +31,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -@FeignClient(value = "EDCFeignClientApi", url = "${edc.hostname}${edc.managementpath:/data/v2}", configuration = EDCDataProviderConfiguration.class) +@FeignClient(value = "EDCFeignClientApi", url = "${edc.hostname}${edc.managementpath:/data}${edc.managementpath.apiversion:/v2}", configuration = EDCDataProviderConfiguration.class) public interface EDCFeignClientApi { @GetMapping(path = "/assets/{id}") diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/asset/AssetEntryRequestFactory.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/asset/AssetEntryRequestFactory.java index 43ede726d..e495d7fe4 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/asset/AssetEntryRequestFactory.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/asset/AssetEntryRequestFactory.java @@ -43,14 +43,24 @@ public class AssetEntryRequestFactory { @Value(value = "${dft.apiKeyHeader}") private String apiKeyHeader; + @Value(value = "${dft.apiKey}") private String apiKey; + @Value(value = "${dft.hostname}") private String dftHostname; + @Value(value = "${manufacturerId}") private String manufacturerId; + @Value(value = "${edc.hostname}") private String edcEndpoint; + + @Value(value = "${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/token") + private String idpIssuerTokenURL; + + @Value(value = "${digital-twins.authentication.clientId}") + private String clientId; public AssetEntryRequest getAssetRequest(String submodel, String assetName, String shellId, String subModelId, String uuid) { @@ -77,7 +87,7 @@ private AssetEntryRequest buildAsset(String submodel, String shellId, String sub private String subModelPayloadUrl(String submodel, String uuid) { return UriComponentsBuilder .fromHttpUrl(dftHostname) - .path("/api/"+submodel+"/public/") + .path("/"+submodel+"/public/") .path(uuid) .toUriString(); } @@ -99,14 +109,20 @@ private HashMap getAssetProperties(String assetId, String assetN return assetProperties; } - private HashMap getDataAddressProperties(String shellId, String subModelId, String endpoint) { - HashMap dataAddressProperties = new HashMap<>(); - dataAddressProperties.put("type", TYPE); - dataAddressProperties.put("baseUrl", String.format(endpoint, shellId, subModelId)); - dataAddressProperties.put("name", NAME); - dataAddressProperties.put("authKey", apiKeyHeader); - dataAddressProperties.put("authCode", apiKey); - return dataAddressProperties; - } + private HashMap getDataAddressProperties(String shellId, String subModelId, String endpoint) { + HashMap dataAddressProperties = new HashMap<>(); + dataAddressProperties.put("type", TYPE); + dataAddressProperties.put("baseUrl", String.format(endpoint, shellId, subModelId)); + dataAddressProperties.put("name", NAME); + dataAddressProperties.put("oauth2:tokenUrl", idpIssuerTokenURL); + dataAddressProperties.put("oauth2:clientId", clientId); + dataAddressProperties.put("oauth2:clientSecretKey", "client-secret"); + dataAddressProperties.put("proxyMethod", "true"); + dataAddressProperties.put("proxyBody", "true"); + dataAddressProperties.put("proxyPath", "true"); + dataAddressProperties.put("proxyQueryParams", "true"); + dataAddressProperties.put("contentType", ASSET_PROP_CONTENT_TYPE); + return dataAddressProperties; + } } diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java index 80d64c5f0..4b2a75ddb 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java @@ -27,9 +27,12 @@ public class AbstractEDCStepsHelper { - @Value("${edc.consumer.hostname}${edc.consumer.managementpath:/data/v2}") + @Value("${edc.consumer.hostname}${edc.consumer.managementpath:/data}${edc.consumer.managementpath.apiversion:/v2}") protected String consumerHost; - + + @Value("${edc.consumer.hostname}${edc.consumer.managementpath:/data}") + protected String consumerHostWithDataPath; + @Value("${edc.consumer.hostname}") protected String consumerHostWithoutDataPath; @@ -39,9 +42,12 @@ public class AbstractEDCStepsHelper { @Value("${edc.consumer.apikey}") private String edcApiKeyValue; - @Value("${edc.hostname}${edc.managementpath:/data/v2}") + @Value("${edc.hostname}${edc.managementpath:/data}${edc.managementpath.apiversion:/v2}") protected String providerHost; - + + @Value("${edc.hostname}${edc.managementpath:/data}") + protected String providerHostWithManagementPath; + @Value("${edc.hostname}") protected String providerHostWithoutDataPath; @@ -66,4 +72,4 @@ public Map getProviderAuthHeader() { return requestHeader; } -} +} \ No newline at end of file