From bf1f6b7d891474d6b4478c3ab3fd61e518ab7912 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Fri, 1 Dec 2023 15:12:48 +0100 Subject: [PATCH 01/59] feat(irs-apiirs-edc-client):[#256] added cache mechanism for edr tokens --- .../client/ContractNegotiationService.java | 76 ++++++++++--- .../irs/edc/client/EdcSubmodelClient.java | 98 ++++++++++++---- .../client/EndpointDataReferenceStorage.java | 16 ++- .../EndpointDataReferenceCacheService.java | 90 +++++++++++++++ .../util/EndpointDataReferenceStatus.java | 41 +++++++ .../ContractNegotiationServiceTest.java | 104 ++++++++++++++++- .../irs/edc/client/EdcSubmodelClientTest.java | 106 ++++++++++++------ .../client/SubmodelFacadeWiremockTest.java | 4 +- .../irs/edc/client/SubmodelRetryerTest.java | 20 +++- ...EndpointDataReferenceCacheServiceTest.java | 104 +++++++++++++++++ 10 files changed, 567 insertions(+), 92 deletions(-) create mode 100644 irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java create mode 100644 irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java create mode 100644 irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index e62b4c9126..fd2f2ac78f 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -37,6 +37,7 @@ import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyException; import org.eclipse.tractusx.irs.edc.client.model.CatalogItem; import org.eclipse.tractusx.irs.edc.client.model.ContractOfferDescription; +import org.eclipse.tractusx.irs.edc.client.model.EDRAuthCode; import org.eclipse.tractusx.irs.edc.client.model.NegotiationRequest; import org.eclipse.tractusx.irs.edc.client.model.NegotiationResponse; import org.eclipse.tractusx.irs.edc.client.model.Response; @@ -44,6 +45,7 @@ import org.eclipse.tractusx.irs.edc.client.model.TransferProcessRequest; import org.eclipse.tractusx.irs.edc.client.model.TransferProcessResponse; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; import org.springframework.stereotype.Service; /** @@ -56,45 +58,83 @@ public class ContractNegotiationService { public static final String EDC_PROTOCOL = "dataspace-protocol-http"; private final EdcControlPlaneClient edcControlPlaneClient; - private final PolicyCheckerService policyCheckerService; - private final EdcConfiguration config; public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem) throws ContractNegotiationException, UsagePolicyException, TransferProcessException { - if (!policyCheckerService.isValid(catalogItem.getPolicy())) { - log.info("Policy was not allowed, canceling negotiation."); - throw new UsagePolicyException(catalogItem.getItemId()); - } - - final NegotiationRequest negotiationRequest = createNegotiationRequestFromCatalogItem(providerConnectorUrl, - catalogItem); + return this.negotiate(providerConnectorUrl, catalogItem, + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + } - final Response negotiationId = edcControlPlaneClient.startNegotiations(negotiationRequest); + @SuppressWarnings("PMD.AvoidReassigningParameters") + public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem, + EndpointDataReferenceStatus endpointDataReferenceStatus) + throws ContractNegotiationException, UsagePolicyException, TransferProcessException { - log.info("Fetch negotiation id: {}", negotiationId.getResponseId()); + if (endpointDataReferenceStatus == null) { + log.info( + "Missing information about endpoint data reference from storage, setting token status to REQUIRED_NEW."); + endpointDataReferenceStatus = new EndpointDataReferenceStatus(null, + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW); + } - final CompletableFuture responseFuture = edcControlPlaneClient.getNegotiationResult( - negotiationId); - final NegotiationResponse negotiationResponse = Objects.requireNonNull(getNegotiationResponse(responseFuture)); + NegotiationResponse negotiationResponse = null; + String contractAgreementId = null; + + switch (endpointDataReferenceStatus.tokenStatus()) { + case REQUIRED_NEW -> { + final CompletableFuture responseFuture = startNewNegotiation(providerConnectorUrl, + catalogItem); + negotiationResponse = Objects.requireNonNull(getNegotiationResponse(responseFuture)); + contractAgreementId = negotiationResponse.getContractAgreementId(); + } + case EXPIRED -> { + contractAgreementId = EDRAuthCode.fromAuthCodeToken( + endpointDataReferenceStatus.endpointDataReference().getAuthKey()).getCid(); + log.info( + "Cached endpoint data reference has expired token. Refreshing token without new contract negotiation for contractAgreementId: {}", + contractAgreementId); + } + case VALID -> throw new IllegalStateException( + "Token is present and valid. Contract negotiation should not be started."); + default -> throw new IllegalStateException( + "Unknown token status."); + } final TransferProcessRequest transferProcessRequest = createTransferProcessRequest(providerConnectorUrl, - catalogItem, negotiationResponse); + catalogItem, contractAgreementId); final Response transferProcessId = edcControlPlaneClient.startTransferProcess(transferProcessRequest); - // can be added to cache after completed final CompletableFuture transferProcessFuture = edcControlPlaneClient.getTransferProcess( transferProcessId); final TransferProcessResponse transferProcessResponse = Objects.requireNonNull( getTransferProcessResponse(transferProcessFuture)); log.info("Transfer process completed for transferProcessId: {}", transferProcessResponse.getResponseId()); + return negotiationResponse; } + private CompletableFuture startNewNegotiation(final String providerConnectorUrl, + final CatalogItem catalogItem) throws UsagePolicyException { + log.info("Staring new contract negotiation."); + + if (!policyCheckerService.isValid(catalogItem.getPolicy())) { + log.info("Policy was not allowed, canceling negotiation."); + throw new UsagePolicyException(catalogItem.getItemId()); + } + + final NegotiationRequest negotiationRequest = createNegotiationRequestFromCatalogItem(providerConnectorUrl, + catalogItem); + final Response negotiationId = edcControlPlaneClient.startNegotiations(negotiationRequest); + log.info("Fetch negotiation id: {}", negotiationId.getResponseId()); + + return edcControlPlaneClient.getNegotiationResult(negotiationId); + } + private TransferProcessRequest createTransferProcessRequest(final String providerConnectorUrl, - final CatalogItem catalogItem, final NegotiationResponse response) { + final CatalogItem catalogItem, final String agreementId) { final var destination = DataAddress.Builder.newInstance() .type(TransferProcessDataDestination.DEFAULT_TYPE) .build(); @@ -105,7 +145,7 @@ private TransferProcessRequest createTransferProcessRequest(final String provide TransferProcessRequest.DEFAULT_MANAGED_RESOURCES) .connectorId(catalogItem.getConnectorId()) .connectorAddress(providerConnectorUrl) - .contractId(response.getContractAgreementId()) + .contractId(agreementId) .assetId(catalogItem.getAssetPropId()) .dataDestination(destination); if (StringUtils.isNotBlank(config.getCallbackUrl())) { diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java index 85bffb96a1..4b0c191400 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java @@ -24,12 +24,14 @@ package org.eclipse.tractusx.irs.edc.client; import static org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration.NAMESPACE_EDC_ID; +import static org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus; import java.net.URI; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import io.github.resilience4j.retry.Retry; import io.github.resilience4j.retry.RetryRegistry; @@ -45,6 +47,8 @@ import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationResponse; import org.eclipse.tractusx.irs.edc.client.model.notification.NotificationContent; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; import org.eclipse.tractusx.irs.edc.client.util.Masker; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @@ -64,6 +68,10 @@ CompletableFuture sendNotification(String submodelEndpo CompletableFuture getEndpointReferenceForAsset(String endpointAddress, String filterKey, String filterValue) throws EdcClientException; + + CompletableFuture getEndpointReferenceForAsset(String endpointAddress, String filterKey, + String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference) + throws EdcClientException; } /** @@ -98,6 +106,13 @@ public CompletableFuture sendNotification(final String return CompletableFuture.completedFuture(() -> true); } + @Override + public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + final String filterKey, final String filterValue, + final EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException { + throw new EdcClientException("Not implemented"); + } + @Override public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, final String filterKey, final String filterValue) throws EdcClientException { @@ -122,6 +137,7 @@ class EdcSubmodelClientImpl implements EdcSubmodelClient { private final AsyncPollingService pollingService; private final RetryRegistry retryRegistry; private final EDCCatalogFacade catalogFacade; + private final EndpointDataReferenceCacheService endpointDataReferenceCacheService; private final UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS); private static void stopWatchOnEdcTask(final StopWatch stopWatch) { @@ -131,6 +147,7 @@ private static void stopWatchOnEdcTask(final StopWatch stopWatch) { private NegotiationResponse fetchNegotiationResponseWithFilter(final String connectorEndpoint, final String assetId) throws EdcClientException { + final StopWatch stopWatch = new StopWatch(); stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + connectorEndpoint); @@ -141,6 +158,7 @@ private NegotiationResponse fetchNegotiationResponseWithFilter(final String conn .findFirst() .orElseThrow(() -> new ItemNotFoundInCatalogException(connectorEndpoint, assetId)); + return contractNegotiationService.negotiate(connectorEndpoint, catalogItem); } @@ -156,24 +174,19 @@ private CompletableFuture sendNotificationAsync(final S } - private Optional retrieveSubmodelData(final String submodelDataplaneUrl, final String contractAgreementId, - final StopWatch stopWatch) { - final Optional dataReference = retrieveEndpointDataReference(contractAgreementId); + private Optional retrieveSubmodelData(final String submodelDataplaneUrl, final StopWatch stopWatch, + final EndpointDataReference endpointDataReference) { + log.info("Retrieving data from EDC data plane for dataReference with id {}", endpointDataReference.getId()); + final String data = edcDataPlaneClient.getData(endpointDataReference, submodelDataplaneUrl); + stopWatchOnEdcTask(stopWatch); - if (dataReference.isPresent()) { - final EndpointDataReference ref = dataReference.get(); - log.info("Retrieving data from EDC data plane for dataReference with id {}", ref.getId()); - final String data = edcDataPlaneClient.getData(ref, submodelDataplaneUrl); - stopWatchOnEdcTask(stopWatch); - - return Optional.of(data); - } - return Optional.empty(); + return Optional.of(data); } private Optional retrieveEndpointReference(final String contractAgreementId, final StopWatch stopWatch) { - final Optional dataReference = retrieveEndpointDataReference(contractAgreementId); + final Optional dataReference = retrieveEndpointDataReferenceByContractAgreementId( + contractAgreementId); if (dataReference.isPresent()) { final EndpointDataReference ref = dataReference.get(); @@ -187,7 +200,8 @@ private Optional retrieveEndpointReference(final String c private Optional sendSubmodelNotification(final String contractAgreementId, final EdcNotification notification, final StopWatch stopWatch) { - final Optional dataReference = retrieveEndpointDataReference(contractAgreementId); + final Optional dataReference = retrieveEndpointDataReferenceByContractAgreementId( + contractAgreementId); if (dataReference.isPresent()) { final EndpointDataReference ref = dataReference.get(); @@ -208,14 +222,11 @@ public CompletableFuture getSubmodelRawPayload(final String connectorEnd final StopWatch stopWatch = new StopWatch(); stopWatch.start("Get EDC Submodel task for raw payload, endpoint " + connectorEndpoint); - final var negotiationEndpoint = appendSuffix(connectorEndpoint, - config.getControlplane().getProviderSuffix()); - log.debug("Starting negotiation with EDC endpoint: '{}'", negotiationEndpoint); - final NegotiationResponse negotiationResponse = fetchNegotiationResponseWithFilter(negotiationEndpoint, - assetId); + final EndpointDataReference endpointDataReference = getEndpointDataReference(connectorEndpoint, assetId); + return pollingService.createJob() - .action(() -> retrieveSubmodelData(submodelDataplaneUrl, - negotiationResponse.getContractAgreementId(), stopWatch)) + .action(() -> retrieveSubmodelData(submodelDataplaneUrl, stopWatch, + endpointDataReference)) .timeToLive(config.getSubmodel().getRequestTtl()) .description("waiting for submodel retrieval") .build() @@ -223,6 +234,37 @@ public CompletableFuture getSubmodelRawPayload(final String connectorEnd }); } + @SuppressWarnings("PMD.ConfusingTernary") + private EndpointDataReference getEndpointDataReference(final String connectorEndpoint, final String assetId) + throws EdcClientException { + final EndpointDataReferenceStatus cachedEndpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( + assetId); + EndpointDataReference endpointDataReference; + + if (cachedEndpointDataReference.tokenStatus() != TokenStatus.VALID) { + endpointDataReference = getEndpointDataReferenceAndAddToStorage(connectorEndpoint, assetId, + cachedEndpointDataReference); + } else { + endpointDataReference = cachedEndpointDataReference.endpointDataReference(); + } + + return endpointDataReference; + } + + private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final String connectorEndpoint, + final String assetId, final EndpointDataReferenceStatus cachedEndpointDataReference) + throws EdcClientException { + try { + final EndpointDataReference endpointDataReference = getEndpointReferenceForAsset(connectorEndpoint, + NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference).get(); + endpointDataReferenceStorage.put(assetId, endpointDataReference); + + return endpointDataReference; + } catch (InterruptedException | ExecutionException e) { + throw new EdcClientException(e); + } + } + @Override public CompletableFuture sendNotification(final String connectorEndpoint, final String assetId, final EdcNotification notification) throws EdcClientException { @@ -241,8 +283,17 @@ public CompletableFuture sendNotification(final String @Override public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, final String filterKey, final String filterValue) throws EdcClientException { + return getEndpointReferenceForAsset(endpointAddress, filterKey, filterValue, + new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + } + + @Override + public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + final String filterKey, final String filterValue, + final EndpointDataReferenceStatus endpointDataReferenceStatus) throws EdcClientException { return execute(endpointAddress, () -> { final StopWatch stopWatch = new StopWatch(); + stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + endpointAddress); final String providerWithSuffix = appendSuffix(endpointAddress, config.getControlplane().getProviderSuffix()); @@ -251,7 +302,7 @@ public CompletableFuture getEndpointReferenceForAsset(fin filterValue); final NegotiationResponse response = contractNegotiationService.negotiate(providerWithSuffix, - items.stream().findFirst().orElseThrow()); + items.stream().findFirst().orElseThrow(), endpointDataReferenceStatus); return pollingService.createJob() .action(() -> retrieveEndpointReference(response.getContractAgreementId(), stopWatch)) @@ -275,7 +326,8 @@ private String appendSuffix(final String endpointAddress, final String providerS return addressWithSuffix; } - private Optional retrieveEndpointDataReference(final String contractAgreementId) { + private Optional retrieveEndpointDataReferenceByContractAgreementId( + final String contractAgreementId) { log.info("Retrieving dataReference from storage for contractAgreementId {}", Masker.mask(contractAgreementId)); return endpointDataReferenceStorage.remove(contractAgreementId); } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java index c5d022af91..2110f52961 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java @@ -37,7 +37,8 @@ import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; /** - * InMemory storage for endpoint data references. + * In-memory storage for endpoint data references. + * Values are held either by assetId or contractAgreementId. */ @Service("irsEdcClientEndpointDataReferenceStorage") public class EndpointDataReferenceStorage { @@ -50,8 +51,8 @@ public EndpointDataReferenceStorage( this.storageDuration = storageDuration; } - public void put(final String contractAgreementId, final EndpointDataReference dataReference) { - storageMap.put(contractAgreementId, new ExpiringContainer(Instant.now(), dataReference)); + public void put(final String storageId, final EndpointDataReference dataReference) { + storageMap.put(storageId, new ExpiringContainer(Instant.now(), dataReference)); cleanup(); } @@ -68,8 +69,13 @@ private void cleanup() { }); } - public Optional remove(final String contractAgreementId) { - return Optional.ofNullable(storageMap.remove(contractAgreementId)).map(ExpiringContainer::getDataReference); + public Optional remove(final String storageId) { + return Optional.ofNullable(storageMap.remove(storageId)).map(ExpiringContainer::getDataReference); + } + + public Optional get(final String storageId) { + return Optional.ofNullable( + storageMap.get(storageId) != null ? storageMap.get(storageId).getDataReference() : null); } /** diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java new file mode 100644 index 0000000000..e521ef401e --- /dev/null +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -0,0 +1,90 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.edc.client.util; + +import java.time.Instant; +import java.util.Optional; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; +import org.eclipse.tractusx.irs.edc.client.model.EDRAuthCode; +import org.springframework.stereotype.Service; + +/** + * Cache service to check if there is + * {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} stored. + */ +@Service +@AllArgsConstructor +@Slf4j +public class EndpointDataReferenceCacheService { + + private final EndpointDataReferenceStorage endpointDataReferenceStorage; + + /** + * Returns {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} + * for assetId from {@link org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage} + * @param assetId key for + * {@link org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage} + * @return {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} + * and {@link org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus} + * describing token status + */ + public EndpointDataReferenceStatus getEndpointDataReference(final String assetId) { + final Optional endpointDataReferenceOptional = retrieveEndpointEndpointReferenceByAssetId( + assetId); + + if (endpointDataReferenceOptional.isPresent()) { + final EndpointDataReference endpointDataReference = endpointDataReferenceOptional.get(); + if (isTokenExpired(endpointDataReference)) { + log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", endpointDataReference.getId(), assetId); + return new EndpointDataReferenceStatus(endpointDataReference, EndpointDataReferenceStatus.TokenStatus.EXPIRED); + } else { + log.info("Endpoint data reference with id: {} for assetId: {} found in storage.", endpointDataReference.getId(), assetId); + return new EndpointDataReferenceStatus(endpointDataReference, EndpointDataReferenceStatus.TokenStatus.VALID); + } + } + + log.info("Endpoint data reference for asset id: {} not found in storage.", assetId); + return new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW); + } + + private Optional retrieveEndpointEndpointReferenceByAssetId(final String assetId) { + log.info("Retrieving dataReference from storage for assetId {}", assetId); + return endpointDataReferenceStorage.get(assetId); + } + + private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { + final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); + return Instant.now().isAfter(tokenExpirationInstant); + } + + private static Instant extractTokenExpiration(final String token) { + return Instant.ofEpochSecond(EDRAuthCode.fromAuthCodeToken(token).getExp()); + } +} + + diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java new file mode 100644 index 0000000000..6687aad5fb --- /dev/null +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.edc.client.util; + +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; + +/** + * Represents {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} + * with it's token status + */ +public record EndpointDataReferenceStatus(EndpointDataReference endpointDataReference, TokenStatus tokenStatus) { + /** + * Token status of assigned {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} + */ + public enum TokenStatus { + VALID, + EXPIRED, + REQUIRED_NEW + } +} diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java index 03c0da9bde..da0787bacb 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java @@ -26,12 +26,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.concurrent.CompletableFuture; import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; import org.eclipse.tractusx.irs.edc.client.exceptions.ContractNegotiationException; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.edc.client.exceptions.TransferProcessException; @@ -41,6 +44,7 @@ import org.eclipse.tractusx.irs.edc.client.model.Response; import org.eclipse.tractusx.irs.edc.client.model.TransferProcessResponse; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -92,7 +96,8 @@ void shouldNegotiateSuccessfully() CompletableFuture.completedFuture(TransferProcessResponse.builder().build())); // act - NegotiationResponse result = testee.negotiate(CONNECTOR_URL, catalogItem); + NegotiationResponse result = testee.negotiate(CONNECTOR_URL, catalogItem, + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); // assert assertThat(result).isNotNull(); @@ -113,7 +118,8 @@ void shouldThrowErrorWhenRetrievingNegotiationResult() { when(edcControlPlaneClient.getNegotiationResult(any())).thenReturn(response); // act & assert - assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem)).isInstanceOf(EdcClientException.class); + assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus(null, + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW))).isInstanceOf(EdcClientException.class); } @Test @@ -137,7 +143,8 @@ void shouldThrowErrorWhenRetrievingTransferResult() { when(edcControlPlaneClient.getTransferProcess(any())).thenReturn(transferError); // act & assert - assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem)).isInstanceOf(EdcClientException.class); + assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus(null, + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW))).isInstanceOf(EdcClientException.class); } @Test @@ -152,7 +159,96 @@ void shouldThrowErrorWhenPolicyCheckerReturnFalse() { when(policyCheckerService.isValid(any())).thenReturn(Boolean.FALSE); // act & assert - assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem)).isInstanceOf(EdcClientException.class); + assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus(null, + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW))).isInstanceOf(EdcClientException.class); + } + + @Test + void shouldStartNegotiationProcessWhenTokenStatusIsRequiredNew() + throws TransferProcessException, UsagePolicyException, ContractNegotiationException { + // given + final var assetId = "testTarget"; + final String offerId = "offerId"; + final CatalogItem catalogItem = createCatalogItem(assetId, offerId); + when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(edcControlPlaneClient.startNegotiations(any())).thenReturn( + Response.builder().responseId("negotiationId").build()); + CompletableFuture negotiationResponse = CompletableFuture.completedFuture( + NegotiationResponse.builder().contractAgreementId("agreementId").build()); + when(edcControlPlaneClient.getNegotiationResult(any())).thenReturn(negotiationResponse); + when(edcControlPlaneClient.startTransferProcess(any())).thenReturn( + Response.builder().responseId("transferProcessId").build()); + when(edcControlPlaneClient.getTransferProcess(any())).thenReturn( + CompletableFuture.completedFuture(TransferProcessResponse.builder().build())); + + // when + testee.negotiate(CONNECTOR_URL, catalogItem, + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + + // then + verify(edcControlPlaneClient).startNegotiations(any()); + } + + @Test + void shouldStartNegotiationProcessWhenTokenStatusIsMissing() + throws TransferProcessException, UsagePolicyException, ContractNegotiationException { + // given + final var assetId = "testTarget"; + final String offerId = "offerId"; + final CatalogItem catalogItem = createCatalogItem(assetId, offerId); + when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(edcControlPlaneClient.startNegotiations(any())).thenReturn( + Response.builder().responseId("negotiationId").build()); + CompletableFuture negotiationResponse = CompletableFuture.completedFuture( + NegotiationResponse.builder().contractAgreementId("agreementId").build()); + when(edcControlPlaneClient.getNegotiationResult(any())).thenReturn(negotiationResponse); + when(edcControlPlaneClient.startTransferProcess(any())).thenReturn( + Response.builder().responseId("transferProcessId").build()); + when(edcControlPlaneClient.getTransferProcess(any())).thenReturn( + CompletableFuture.completedFuture(TransferProcessResponse.builder().build())); + + // when + testee.negotiate(CONNECTOR_URL, catalogItem, null); + + // then + verify(edcControlPlaneClient).startNegotiations(any()); + } + + @Test + void shouldNotStartNewNegotiationWhenTokenIsExpired() + throws TransferProcessException, UsagePolicyException, ContractNegotiationException { + // given + final var assetId = "testTarget"; + final String offerId = "offerId"; + final CatalogItem catalogItem = createCatalogItem(assetId, offerId); + + when(edcControlPlaneClient.startTransferProcess(any())).thenReturn( + Response.builder().responseId("transferProcessId").build()); + when(edcControlPlaneClient.getTransferProcess(any())).thenReturn( + CompletableFuture.completedFuture(TransferProcessResponse.builder().build())); + final String encodedAuthKey = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE3MDA3NDc0NjMsImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.HDhEMOGVlwOTAFIKCCUzf_twg08K-rQwElNS2foinB9hRM-htLwoXayMtbXdXS4pFevRn1AXhzcxd5ur7gslJdsNohTiwVP0lXRd0cehWMpRKdDiUCLn4lh0A2fFTYpoX4WIXvqldAADxi0qDmZqLTZdSOqkM40t-Fq8esyFMrO_uC6GL8LUQMLML1HV6nqGkqp-VELEoOMTV1-aVQ-OEv0J24epjNyesx448v0yylhS_vxPmay1zeSJgDCwqzSuY5-EkyIfCN1XqbynMZiNtD2FLbAig0KTAL2rN6WMufSWMjgLUU0mhRbd9bWvqs3JKLVzvagQgS3hMTj5a-C2Tw"; + + // when + testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus( + EndpointDataReference.Builder.newInstance().authKey(encodedAuthKey).endpoint("").authCode("").build(), + EndpointDataReferenceStatus.TokenStatus.EXPIRED)); + + // then + verify(edcControlPlaneClient, never()).startNegotiations(any()); + } + + @Test + void shouldThrowInvalidStateExceptionWhenTokenIsValid() { + // given + final var assetId = "testTarget"; + final String offerId = "offerId"; + final CatalogItem catalogItem = createCatalogItem(assetId, offerId); + + // when + // then + assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus( + EndpointDataReference.Builder.newInstance().authKey("").endpoint("").authCode("").build(), + EndpointDataReferenceStatus.TokenStatus.VALID))).isInstanceOf(IllegalStateException.class); } } \ No newline at end of file diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index 59b9598764..27f7f9af83 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -24,11 +24,11 @@ package org.eclipse.tractusx.irs.edc.client; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -45,6 +45,7 @@ import java.time.ZoneId; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -61,7 +62,7 @@ import org.eclipse.tractusx.irs.component.enums.Direction; import org.eclipse.tractusx.irs.data.StringMapper; import org.eclipse.tractusx.irs.edc.client.exceptions.ContractNegotiationException; -import org.eclipse.tractusx.irs.edc.client.exceptions.TimeoutException; +import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.edc.client.exceptions.TransferProcessException; import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyException; import org.eclipse.tractusx.irs.edc.client.model.CatalogItem; @@ -69,6 +70,8 @@ import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationResponse; import org.eclipse.tractusx.irs.edc.client.model.notification.NotificationContent; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; import org.eclipse.tractusx.irs.testing.containers.LocalTestDataConfigurationAware; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; @@ -102,6 +105,8 @@ class EdcSubmodelClientTest extends LocalTestDataConfigurationAware { private EdcDataPlaneClient edcDataPlaneClient; @Mock private EDCCatalogFacade catalogFacade; + @Mock + private EndpointDataReferenceCacheService endpointDataReferenceCacheService; private EdcSubmodelClient testee; EdcSubmodelClientTest() throws IOException { @@ -120,7 +125,7 @@ void setUp() { config.getSubmodel().setUrnPrefix("/urn"); config.getSubmodel().setRequestTtl(Duration.ofMinutes(10)); testee = new EdcSubmodelClientImpl(config, contractNegotiationService, edcDataPlaneClient, - endpointDataReferenceStorage, pollingService, retryRegistry, catalogFacade); + endpointDataReferenceStorage, pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); } @Test @@ -128,12 +133,13 @@ void shouldRetrieveValidRelationship() throws Exception { // arrange when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); - when(contractNegotiationService.negotiate(any(), any())).thenReturn( + when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( NegotiationResponse.builder().contractAgreementId("agreementId").build()); final EndpointDataReference ref = mock(EndpointDataReference.class); endpointDataReferenceStorage.put("agreementId", ref); final String singleLevelBomAsBuiltJson = readSingleLevelBomAsBuiltData(); when(edcDataPlaneClient.getData(eq(ref), any())).thenReturn(singleLevelBomAsBuiltJson); + when(endpointDataReferenceCacheService.getEndpointDataReference(eq("assetId"))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act final var result = testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); @@ -161,32 +167,6 @@ void shouldSendNotificationSuccessfully() throws Exception { // assert assertThat(response.deliveredSuccessfully()).isTrue(); - verify(contractNegotiationService, times(1)).negotiate(eq(CONNECTOR_ENDPOINT + PROVIDER_SUFFIX), any()); - } - - @Test - void shouldTimeOut() throws Exception { - // arrange - when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( - List.of(CatalogItem.builder().itemId("itemId").build())); - when(contractNegotiationService.negotiate(any(), any())).thenReturn( - NegotiationResponse.builder().contractAgreementId("agreementId").build()); - - // act - final var result = testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "ID"); - clock.travelToFuture(Duration.ofMinutes(20)); - - // assert - assertThatThrownBy(result::get).isInstanceOf(ExecutionException.class) - .hasCauseInstanceOf(TimeoutException.class); - } - - @Test - void shouldThrowErrorWhenCatalogItemCouldNotBeFound() { - // act & assert - assertThatThrownBy( - () -> testee.getSubmodelRawPayload(CONNECTOR_ENDPOINT, SUBMODEL_SUFIX, ASSET_ID)).isInstanceOf( - ItemNotFoundInCatalogException.class); } @NotNull @@ -206,6 +186,7 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsBuil when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(existingCatenaXId).build())); prepareTestdata(existingCatenaXId, "_singleLevelBomAsBuilt"); + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) .get(5, TimeUnit.SECONDS); @@ -219,6 +200,7 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsPlan when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(catenaXId).build())); prepareTestdata(catenaXId, "_singleLevelBomAsPlanned"); + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) .get(5, TimeUnit.SECONDS); @@ -232,6 +214,7 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsSpec when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(catenaXId).build())); prepareTestdata(catenaXId, "_singleLevelBomAsSpecified"); + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) .get(5, TimeUnit.SECONDS); @@ -245,6 +228,7 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelUsag when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(catenaXId).build())); prepareTestdata(catenaXId, "_singleLevelUsageAsBuilt"); + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) .get(5, TimeUnit.SECONDS); @@ -259,6 +243,8 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithNotExistingCatenaXIdAndSing when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(catenaXId).build())); prepareTestdata(catenaXId, "_singleLevelBomAsBuilt"); + when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) .get(5, TimeUnit.SECONDS); @@ -272,6 +258,7 @@ void shouldReturnRawSerialPartWhenExisting() throws Exception { when(catalogFacade.fetchCatalogByFilter("https://connector.endpoint.com" + PROVIDER_SUFFIX, "https://w3id.org/edc/v0.0.1/ns/id", ASSET_ID)).thenReturn(createCatalog(ASSET_ID, 3)); prepareTestdata(existingCatenaXId, "_serialPart"); + when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID).get(5, TimeUnit.SECONDS); @@ -287,6 +274,7 @@ void shouldUseDecodedTargetId() throws Exception { final String target = URLEncoder.encode(ASSET_ID, StandardCharsets.UTF_8); when(catalogFacade.fetchCatalogByFilter("https://connector.endpoint.com" + PROVIDER_SUFFIX, "https://w3id.org/edc/v0.0.1/ns/id", ASSET_ID)).thenReturn(createCatalog(target, 3)); + when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID).get(5, TimeUnit.SECONDS); @@ -302,6 +290,7 @@ void shouldReturnSameRelationshipsForDifferentDirections() throws Exception { when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(parentCatenaXId).build())); prepareTestdata(parentCatenaXId, "_singleLevelBomAsBuilt"); + when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String relationshipsJson = testee.getSubmodelRawPayload("http://localhost/", "_singleLevelBomAsBuilt", ASSET_ID).get(5, TimeUnit.SECONDS); @@ -332,25 +321,70 @@ void shouldRetrieveEndpointReferenceForAsset() throws Exception { // arrange final String filterKey = "filter-key"; final String filterValue = "filter-value"; + final String agreementId = "agreementId"; when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("asset-id").build())); - when(contractNegotiationService.negotiate(any(), any())).thenReturn( - NegotiationResponse.builder().contractAgreementId("agreementId").build()); + when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))) + .thenReturn(NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference expected = mock(EndpointDataReference.class); - endpointDataReferenceStorage.put("agreementId", expected); + endpointDataReferenceStorage.put(agreementId, expected); // act - final var result = testee.getEndpointReferenceForAsset(ENDPOINT_ADDRESS, filterKey, filterValue); + final var result = testee.getEndpointReferenceForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, + new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final EndpointDataReference actual = result.get(5, TimeUnit.SECONDS); // assert assertThat(actual).isEqualTo(expected); } + @Test + void shouldUseCachedEndpointReferenceValueWhenTokenIsValid() throws EdcClientException, ExecutionException, InterruptedException { + // given + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn( + new EndpointDataReferenceStatus(EndpointDataReference.Builder.newInstance().endpoint("").authKey("").authCode("").build(), + TokenStatus.VALID)); + final String value = "result"; + when(edcDataPlaneClient.getData(any(), any())).thenReturn(value); + + // when + final var resultFuture + = testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); + + // then + final String result = resultFuture.get(); + verify(contractNegotiationService, never()).negotiate(any(), any(), any()); + assertThat(result).isEqualTo(value); + } + + @Test + void shouldCreateCacheRecordWhenTokenIsNotValid() + throws EdcClientException { + // given + when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( + List.of(CatalogItem.builder().itemId("itemId").build())); + when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( + NegotiationResponse.builder().contractAgreementId("agreementId").build()); + final EndpointDataReference ref = mock(EndpointDataReference.class); + endpointDataReferenceStorage.put("agreementId", ref); + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn( + new EndpointDataReferenceStatus(null, + TokenStatus.REQUIRED_NEW)); + final String value = "result"; + when(edcDataPlaneClient.getData(any(), any())).thenReturn(value); + + // when + testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); + + // then + final Optional referenceFromStorage = endpointDataReferenceStorage.get("assetId"); + assertThat(referenceFromStorage).isPresent(); + } + private void prepareTestdata(final String catenaXId, final String submodelDataSuffix) throws ContractNegotiationException, IOException, UsagePolicyException, TransferProcessException { - when(contractNegotiationService.negotiate(any(), any())).thenReturn( + when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( NegotiationResponse.builder().contractAgreementId("agreementId").build()); final EndpointDataReference ref = mock(EndpointDataReference.class); endpointDataReferenceStorage.put("agreementId", ref); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java index c1b79fbb26..0a7210fcf4 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java @@ -64,6 +64,7 @@ import org.eclipse.tractusx.irs.edc.client.policy.Permission; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; import org.eclipse.tractusx.irs.edc.client.policy.PolicyType; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -116,6 +117,7 @@ void configureSystemUnderTest() { final EdcDataPlaneClient dataPlaneClient = new EdcDataPlaneClient(restTemplate); final EDCCatalogFacade catalogFacade = new EDCCatalogFacade(controlPlaneClient, config); + final EndpointDataReferenceCacheService endpointDataReferenceCacheService = new EndpointDataReferenceCacheService(new EndpointDataReferenceStorage(Duration.ofMinutes(1))); acceptedPoliciesProvider = mock(AcceptedPoliciesProvider.class); when(acceptedPoliciesProvider.getAcceptedPolicies()).thenReturn(List.of(new AcceptedPolicy(policy("IRS Policy", @@ -130,7 +132,7 @@ void configureSystemUnderTest() { final RetryRegistry retryRegistry = RetryRegistry.ofDefaults(); this.edcSubmodelClient = new EdcSubmodelClientImpl(config, contractNegotiationService, dataPlaneClient, storage, - pollingService, retryRegistry, catalogFacade); + pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); } @AfterEach diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java index bed998e08e..e0c228f4bb 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java @@ -28,6 +28,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.time.Clock; import java.time.Duration; @@ -36,6 +37,8 @@ import io.github.resilience4j.retry.RetryRegistry; import io.github.resilience4j.retry.internal.InMemoryRetryRegistry; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -55,6 +58,8 @@ class SubmodelExponentialRetryTest { private RestTemplate restTemplate; @Mock private PolicyCheckerService policyCheckerService; + @Mock + private EndpointDataReferenceCacheService endpointDataReferenceCacheService; private EdcSubmodelFacade testee; @BeforeEach @@ -73,10 +78,12 @@ void setUp() { final ContractNegotiationService negotiationService = new ContractNegotiationService(controlPlaneClient, policyCheckerService, config); final EdcDataPlaneClient dataPlaneClient = new EdcDataPlaneClient(restTemplate); - final EndpointDataReferenceStorage storage = new EndpointDataReferenceStorage(Duration.ofMinutes(1)); + final EndpointDataReferenceStorage endpointDataReferenceStorage = new EndpointDataReferenceStorage( + Duration.ofMinutes(1)); - final EdcSubmodelClient client = new EdcSubmodelClientImpl(config, negotiationService, dataPlaneClient, storage, - pollingService, retryRegistry, catalogFacade); + final EdcSubmodelClient client = new EdcSubmodelClientImpl(config, negotiationService, dataPlaneClient, + endpointDataReferenceStorage, + pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); testee = new EdcSubmodelFacade(client); } @@ -87,6 +94,8 @@ void shouldRetryExecutionOfGetSubmodelOnClientMaxAttemptTimes() { eq(String.class))).willThrow( new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "EDC remote exception")); + when(endpointDataReferenceCacheService.getEndpointDataReference("9300395e-c0a5-4e88-bc57-a3973fec4c26")).thenReturn(new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + // Act assertThatThrownBy(() -> testee.getSubmodelRawPayload( "https://connector.endpoint.com", @@ -95,7 +104,7 @@ void shouldRetryExecutionOfGetSubmodelOnClientMaxAttemptTimes() { HttpServerErrorException.class); // Assert - verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts())).exchange(any(String.class), + verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts() * 3)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); } @@ -104,6 +113,7 @@ void shouldRetryOnAnyRuntimeException() { // Arrange given(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))).willThrow(new RuntimeException("EDC remote exception")); + when(endpointDataReferenceCacheService.getEndpointDataReference("9300395e-c0a5-4e88-bc57-a3973fec4c26")).thenReturn(new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); // Act assertThatThrownBy(() -> testee.getSubmodelRawPayload( @@ -112,7 +122,7 @@ void shouldRetryOnAnyRuntimeException() { "9300395e-c0a5-4e88-bc57-a3973fec4c26")).hasCauseInstanceOf(RuntimeException.class); // Assert - verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts())).exchange(any(String.class), + verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts() * 3)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); } diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java new file mode 100644 index 0000000000..6af28d7ddf --- /dev/null +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java @@ -0,0 +1,104 @@ +package org.eclipse.tractusx.irs.edc.client.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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 + ********************************************************************************/ +@ExtendWith(MockitoExtension.class) +class EndpointDataReferenceCacheServiceTest { + + @Mock + private EndpointDataReferenceStorage endpointDataReferenceStorage; + + @InjectMocks + private EndpointDataReferenceCacheService endpointDataReferenceCacheService; + + @Test + public void shouldReturnStatusRequiredNewWhenThereIsNoRecordInCache() { + // given + final String assetId = "assetId"; + when(endpointDataReferenceStorage.get(assetId)).thenReturn(Optional.empty()); + + // when + final EndpointDataReferenceStatus endpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( + assetId); + + // then + assertThat(endpointDataReference.endpointDataReference()).isNull(); + assertThat(endpointDataReference.tokenStatus()).isEqualTo(EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW); + } + + @Test + public void shouldReturnStatusExpiredAndCorrectEndpointDataReferenceWhenThereIsRecordInCacheWithExpiredToken() { + // given + final String assetId = "assetId"; + final String authKey = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE3MDA3NDc0NjMsImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.HDhEMOGVlwOTAFIKCCUzf_twg08K-rQwElNS2foinB9hRM-htLwoXayMtbXdXS4pFevRn1AXhzcxd5ur7gslJdsNohTiwVP0lXRd0cehWMpRKdDiUCLn4lh0A2fFTYpoX4WIXvqldAADxi0qDmZqLTZdSOqkM40t-Fq8esyFMrO_uC6GL8LUQMLML1HV6nqGkqp-VELEoOMTV1-aVQ-OEv0J24epjNyesx448v0yylhS_vxPmay1zeSJgDCwqzSuY5-EkyIfCN1XqbynMZiNtD2FLbAig0KTAL2rN6WMufSWMjgLUU0mhRbd9bWvqs3JKLVzvagQgS3hMTj5a-C2Tw"; + final EndpointDataReference endpointDataReferenceWithExpiredToken = EndpointDataReference.Builder.newInstance() + .endpoint("") + .authCode(authKey) + .authKey("") + .build(); + when(endpointDataReferenceStorage.get(assetId)).thenReturn(Optional.of(endpointDataReferenceWithExpiredToken)); + + // when + final EndpointDataReferenceStatus endpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( + assetId); + + // then + assertThat(endpointDataReference.endpointDataReference()).isEqualTo(endpointDataReferenceWithExpiredToken); + assertThat(endpointDataReference.tokenStatus()).isEqualTo(EndpointDataReferenceStatus.TokenStatus.EXPIRED); + } + + @Test + public void shouldReturnStatusValidAndCorrectEndpointDataReferenceWhenThereIsRecordInCacheWithValidToken() { + // given + final String assetId = "assetId"; + final String authCode = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjk5OTk5OTk5OTksImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.OnqBmy76W6s7e8U9xYxlRPFBS-DyFoVzIMtnw8fSNQ8yd2HkqrRRFvGb8ttTQ0aAxFQjvyN6o59e0j_tAPQkNkXvJf7ahlJGjhlK9sPaFiXqdfYIH9cX0Czc-zsum248Q1WQfcQA8veDFHv09sO3Adr48hLa4-0ZLBu6GX6x1gUT10qKc4pCSzMJFqFLUst6Bi6nFwDHa68V9GjYxmyU-b3wXk5Nt5lkt1ak3rb0Kpd84wyEsNN09x_EC3PPMkI1UtgevhYN_lvtuweRvLgJjCbIHWmxTgewPY7GmYye_IhrgRvum6danyCUjEwp0-vPUpfzUNsvF60CJnk9Jq-jnQ"; + final EndpointDataReference endpointDataReferenceWithExpiredToken = EndpointDataReference.Builder.newInstance() + .endpoint("") + .authCode(authCode) + .authKey("") + .build(); + when(endpointDataReferenceStorage.get(assetId)).thenReturn(Optional.of(endpointDataReferenceWithExpiredToken)); + + // when + final EndpointDataReferenceStatus endpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( + assetId); + + // then + assertThat(endpointDataReference.endpointDataReference()).isEqualTo(endpointDataReferenceWithExpiredToken); + assertThat(endpointDataReference.tokenStatus()).isEqualTo(EndpointDataReferenceStatus.TokenStatus.VALID); + } +} \ No newline at end of file From 645ee4fbc42e5832ee222f99f3a7941c73defadb Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 09:41:57 +0100 Subject: [PATCH 02/59] feat(irs-apiirs-edc-client):[#256] fix for potential null pointer exceptions --- .../tractusx/irs/edc/client/ContractNegotiationService.java | 2 +- .../irs/edc/client/util/EndpointDataReferenceCacheService.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index fd2f2ac78f..69e42718f5 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -91,7 +91,7 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca } case EXPIRED -> { contractAgreementId = EDRAuthCode.fromAuthCodeToken( - endpointDataReferenceStatus.endpointDataReference().getAuthKey()).getCid(); + Objects.requireNonNull(endpointDataReferenceStatus.endpointDataReference().getAuthKey())).getCid(); log.info( "Cached endpoint data reference has expired token. Refreshing token without new contract negotiation for contractAgreementId: {}", contractAgreementId); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index e521ef401e..e1237781cc 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.irs.edc.client.util; import java.time.Instant; +import java.util.Objects; import java.util.Optional; import lombok.AllArgsConstructor; @@ -78,7 +79,7 @@ private Optional retrieveEndpointEndpointReferenceByAsset } private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { - final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); + final Instant tokenExpirationInstant = extractTokenExpiration(Objects.requireNonNull(endpointDataReference.getAuthCode())); return Instant.now().isAfter(tokenExpirationInstant); } From cb2c22313ec5d33151847444d7c9896c44d79487 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 09:50:22 +0100 Subject: [PATCH 03/59] feat(irs-apiirs-edc-client):[#256] removed unnecessary stubbing --- .../eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index 27f7f9af83..bd1f253459 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -371,7 +371,6 @@ void shouldCreateCacheRecordWhenTokenIsNotValid() new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String value = "result"; - when(edcDataPlaneClient.getData(any(), any())).thenReturn(value); // when testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); From 1e2fb192f57affb149ecc2d706aa7f37cb866ecf Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 11:09:22 +0100 Subject: [PATCH 04/59] feat(irs-apiirs-edc-client):[#256] sonar finding fix --- .../tractusx/irs/edc/client/ContractNegotiationService.java | 5 ++++- .../eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java | 5 ++++- .../edc/client/util/EndpointDataReferenceCacheService.java | 5 ++--- .../tractusx/irs/edc/client/EdcSubmodelClientTest.java | 1 - 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 69e42718f5..83f3693dd7 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -90,8 +90,11 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca contractAgreementId = negotiationResponse.getContractAgreementId(); } case EXPIRED -> { + if (endpointDataReferenceStatus.endpointDataReference().getAuthKey() == null) { + throw new IllegalStateException("Missing information about AuthKey."); + } contractAgreementId = EDRAuthCode.fromAuthCodeToken( - Objects.requireNonNull(endpointDataReferenceStatus.endpointDataReference().getAuthKey())).getCid(); + endpointDataReferenceStatus.endpointDataReference().getAuthKey()).getCid(); log.info( "Cached endpoint data reference has expired token. Refreshing token without new contract negotiation for contractAgreementId: {}", contractAgreementId); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java index 4b0c191400..e27b90e39c 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java @@ -260,7 +260,10 @@ private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final Stri endpointDataReferenceStorage.put(assetId, endpointDataReference); return endpointDataReference; - } catch (InterruptedException | ExecutionException e) { + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new EdcClientException(e); + } catch (ExecutionException e) { throw new EdcClientException(e); } } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index e1237781cc..ebea8c2180 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -24,7 +24,6 @@ package org.eclipse.tractusx.irs.edc.client.util; import java.time.Instant; -import java.util.Objects; import java.util.Optional; import lombok.AllArgsConstructor; @@ -58,7 +57,7 @@ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId final Optional endpointDataReferenceOptional = retrieveEndpointEndpointReferenceByAssetId( assetId); - if (endpointDataReferenceOptional.isPresent()) { + if (endpointDataReferenceOptional.isPresent() && endpointDataReferenceOptional.get().getAuthCode() != null) { final EndpointDataReference endpointDataReference = endpointDataReferenceOptional.get(); if (isTokenExpired(endpointDataReference)) { log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", endpointDataReference.getId(), assetId); @@ -79,7 +78,7 @@ private Optional retrieveEndpointEndpointReferenceByAsset } private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { - final Instant tokenExpirationInstant = extractTokenExpiration(Objects.requireNonNull(endpointDataReference.getAuthCode())); + final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); return Instant.now().isAfter(tokenExpirationInstant); } diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index bd1f253459..f927f89a5a 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -370,7 +370,6 @@ void shouldCreateCacheRecordWhenTokenIsNotValid() when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn( new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); - final String value = "result"; // when testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); From e8158a6960df6fae12366aadf51b279d90b0129b Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 11:25:01 +0100 Subject: [PATCH 05/59] feat(irs-apiirs-edc-client):[#256] fix findbug findings --- irs-edc-client/pom.xml | 11 +++++++++++ .../irs/edc/client/ContractNegotiationService.java | 3 +++ .../util/EndpointDataReferenceCacheService.java | 2 ++ pom.xml | 1 + 4 files changed, 17 insertions(+) diff --git a/irs-edc-client/pom.xml b/irs-edc-client/pom.xml index 10d3049c1e..d63dc8776c 100644 --- a/irs-edc-client/pom.xml +++ b/irs-edc-client/pom.xml @@ -225,6 +225,17 @@ ${awaitility.version} test + + com.google.code.findbugs + annotations + ${findbug.version} + + + com.google.code.findbugs + jsr305 + 3.0.1 + provided + diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 83f3693dd7..fdd9a6f174 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -68,6 +68,9 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca } @SuppressWarnings("PMD.AvoidReassigningParameters") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", + justification="Not reachable code") public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem, EndpointDataReferenceStatus endpointDataReferenceStatus) throws ContractNegotiationException, UsagePolicyException, TransferProcessException { diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index ebea8c2180..963a1c7773 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -77,6 +77,8 @@ private Optional retrieveEndpointEndpointReferenceByAsset return endpointDataReferenceStorage.get(assetId); } + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); return Instant.now().isAfter(tokenExpirationInstant); diff --git a/pom.xml b/pom.xml index d52a2dc84e..18a5ace2aa 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,7 @@ 5.9.2 2.4.10 1.19.1 + 3.0.1 4.7.3.2 From 54f62bcb54dc510aaffbade0cc55dcead17db4a8 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 11:29:59 +0100 Subject: [PATCH 06/59] feat(irs-apiirs-edc-client):[#256] fix findbug findings --- .../tractusx/irs/edc/client/ContractNegotiationService.java | 4 ++-- .../edc/client/util/EndpointDataReferenceCacheService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index fdd9a6f174..89bdd72c0a 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -69,8 +69,8 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca @SuppressWarnings("PMD.AvoidReassigningParameters") @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", - justification="Not reachable code") + value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", + justification = "Not reachable code") public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem, EndpointDataReferenceStatus endpointDataReferenceStatus) throws ContractNegotiationException, UsagePolicyException, TransferProcessException { diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index 963a1c7773..598439fe81 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -78,7 +78,7 @@ private Optional retrieveEndpointEndpointReferenceByAsset } @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") + value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); return Instant.now().isAfter(tokenExpirationInstant); From 2495ac15a508e77c62e1ef0d7197dc407819599f Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 11:59:37 +0100 Subject: [PATCH 07/59] feat(irs-apiirs-edc-client):[#256] address code smells --- .../edc/client/ContractNegotiationService.java | 3 ++- .../EndpointDataReferenceCacheService.java | 18 +++++++++++------- .../irs/edc/client/EdcSubmodelClientTest.java | 10 +++++----- .../EndpointDataReferenceCacheServiceTest.java | 6 +++--- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 89bdd72c0a..91947f7b6d 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -46,6 +46,7 @@ import org.eclipse.tractusx.irs.edc.client.model.TransferProcessResponse; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.util.Masker; import org.springframework.stereotype.Service; /** @@ -100,7 +101,7 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca endpointDataReferenceStatus.endpointDataReference().getAuthKey()).getCid(); log.info( "Cached endpoint data reference has expired token. Refreshing token without new contract negotiation for contractAgreementId: {}", - contractAgreementId); + Masker.mask(contractAgreementId)); } case VALID -> throw new IllegalStateException( "Token is present and valid. Contract negotiation should not be started."); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index 598439fe81..70cc301dde 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -47,8 +47,9 @@ public class EndpointDataReferenceCacheService { /** * Returns {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} * for assetId from {@link org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage} + * * @param assetId key for - * {@link org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage} + * {@link org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage} * @return {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} * and {@link org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus} * describing token status @@ -60,11 +61,15 @@ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId if (endpointDataReferenceOptional.isPresent() && endpointDataReferenceOptional.get().getAuthCode() != null) { final EndpointDataReference endpointDataReference = endpointDataReferenceOptional.get(); if (isTokenExpired(endpointDataReference)) { - log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", endpointDataReference.getId(), assetId); - return new EndpointDataReferenceStatus(endpointDataReference, EndpointDataReferenceStatus.TokenStatus.EXPIRED); + log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", + endpointDataReference.getId(), assetId); + return new EndpointDataReferenceStatus(endpointDataReference, + EndpointDataReferenceStatus.TokenStatus.EXPIRED); } else { - log.info("Endpoint data reference with id: {} for assetId: {} found in storage.", endpointDataReference.getId(), assetId); - return new EndpointDataReferenceStatus(endpointDataReference, EndpointDataReferenceStatus.TokenStatus.VALID); + log.info("Endpoint data reference with id: {} for assetId: {} found in storage.", + endpointDataReference.getId(), assetId); + return new EndpointDataReferenceStatus(endpointDataReference, + EndpointDataReferenceStatus.TokenStatus.VALID); } } @@ -77,8 +82,7 @@ private Optional retrieveEndpointEndpointReferenceByAsset return endpointDataReferenceStorage.get(assetId); } - @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); return Instant.now().isAfter(tokenExpirationInstant); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index f927f89a5a..3a694937c6 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -139,7 +139,7 @@ void shouldRetrieveValidRelationship() throws Exception { endpointDataReferenceStorage.put("agreementId", ref); final String singleLevelBomAsBuiltJson = readSingleLevelBomAsBuiltData(); when(edcDataPlaneClient.getData(eq(ref), any())).thenReturn(singleLevelBomAsBuiltJson); - when(endpointDataReferenceCacheService.getEndpointDataReference(eq("assetId"))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference("assetId")).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act final var result = testee.getSubmodelRawPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); @@ -243,7 +243,7 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithNotExistingCatenaXIdAndSing when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(catenaXId).build())); prepareTestdata(catenaXId, "_singleLevelBomAsBuilt"); - when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference(ASSET_ID)).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) @@ -258,7 +258,7 @@ void shouldReturnRawSerialPartWhenExisting() throws Exception { when(catalogFacade.fetchCatalogByFilter("https://connector.endpoint.com" + PROVIDER_SUFFIX, "https://w3id.org/edc/v0.0.1/ns/id", ASSET_ID)).thenReturn(createCatalog(ASSET_ID, 3)); prepareTestdata(existingCatenaXId, "_serialPart"); - when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference(ASSET_ID)).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID).get(5, TimeUnit.SECONDS); @@ -274,7 +274,7 @@ void shouldUseDecodedTargetId() throws Exception { final String target = URLEncoder.encode(ASSET_ID, StandardCharsets.UTF_8); when(catalogFacade.fetchCatalogByFilter("https://connector.endpoint.com" + PROVIDER_SUFFIX, "https://w3id.org/edc/v0.0.1/ns/id", ASSET_ID)).thenReturn(createCatalog(target, 3)); - when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference(ASSET_ID)).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelRawPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID).get(5, TimeUnit.SECONDS); @@ -290,7 +290,7 @@ void shouldReturnSameRelationshipsForDifferentDirections() throws Exception { when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId(parentCatenaXId).build())); prepareTestdata(parentCatenaXId, "_singleLevelBomAsBuilt"); - when(endpointDataReferenceCacheService.getEndpointDataReference(eq(ASSET_ID))).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference(ASSET_ID)).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String relationshipsJson = testee.getSubmodelRawPayload("http://localhost/", "_singleLevelBomAsBuilt", ASSET_ID).get(5, TimeUnit.SECONDS); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java index 6af28d7ddf..b84e338b78 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java @@ -46,7 +46,7 @@ class EndpointDataReferenceCacheServiceTest { private EndpointDataReferenceCacheService endpointDataReferenceCacheService; @Test - public void shouldReturnStatusRequiredNewWhenThereIsNoRecordInCache() { + void shouldReturnStatusRequiredNewWhenThereIsNoRecordInCache() { // given final String assetId = "assetId"; when(endpointDataReferenceStorage.get(assetId)).thenReturn(Optional.empty()); @@ -61,7 +61,7 @@ public void shouldReturnStatusRequiredNewWhenThereIsNoRecordInCache() { } @Test - public void shouldReturnStatusExpiredAndCorrectEndpointDataReferenceWhenThereIsRecordInCacheWithExpiredToken() { + void shouldReturnStatusExpiredAndCorrectEndpointDataReferenceWhenThereIsRecordInCacheWithExpiredToken() { // given final String assetId = "assetId"; final String authKey = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE3MDA3NDc0NjMsImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.HDhEMOGVlwOTAFIKCCUzf_twg08K-rQwElNS2foinB9hRM-htLwoXayMtbXdXS4pFevRn1AXhzcxd5ur7gslJdsNohTiwVP0lXRd0cehWMpRKdDiUCLn4lh0A2fFTYpoX4WIXvqldAADxi0qDmZqLTZdSOqkM40t-Fq8esyFMrO_uC6GL8LUQMLML1HV6nqGkqp-VELEoOMTV1-aVQ-OEv0J24epjNyesx448v0yylhS_vxPmay1zeSJgDCwqzSuY5-EkyIfCN1XqbynMZiNtD2FLbAig0KTAL2rN6WMufSWMjgLUU0mhRbd9bWvqs3JKLVzvagQgS3hMTj5a-C2Tw"; @@ -82,7 +82,7 @@ public void shouldReturnStatusExpiredAndCorrectEndpointDataReferenceWhenThereIsR } @Test - public void shouldReturnStatusValidAndCorrectEndpointDataReferenceWhenThereIsRecordInCacheWithValidToken() { + void shouldReturnStatusValidAndCorrectEndpointDataReferenceWhenThereIsRecordInCacheWithValidToken() { // given final String assetId = "assetId"; final String authCode = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjk5OTk5OTk5OTksImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.OnqBmy76W6s7e8U9xYxlRPFBS-DyFoVzIMtnw8fSNQ8yd2HkqrRRFvGb8ttTQ0aAxFQjvyN6o59e0j_tAPQkNkXvJf7ahlJGjhlK9sPaFiXqdfYIH9cX0Czc-zsum248Q1WQfcQA8veDFHv09sO3Adr48hLa4-0ZLBu6GX6x1gUT10qKc4pCSzMJFqFLUst6Bi6nFwDHa68V9GjYxmyU-b3wXk5Nt5lkt1ak3rb0Kpd84wyEsNN09x_EC3PPMkI1UtgevhYN_lvtuweRvLgJjCbIHWmxTgewPY7GmYye_IhrgRvum6danyCUjEwp0-vPUpfzUNsvF60CJnk9Jq-jnQ"; From 9654457472ff663198abfc041323bf30ca46ccf2 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 4 Dec 2023 12:27:24 +0100 Subject: [PATCH 08/59] feat(irs-apiirs-edc-client):[#256] removed dependency --- irs-edc-client/pom.xml | 11 ----------- .../irs/edc/client/ContractNegotiationService.java | 3 --- .../util/EndpointDataReferenceCacheService.java | 1 - pom.xml | 1 - 4 files changed, 16 deletions(-) diff --git a/irs-edc-client/pom.xml b/irs-edc-client/pom.xml index d63dc8776c..10d3049c1e 100644 --- a/irs-edc-client/pom.xml +++ b/irs-edc-client/pom.xml @@ -225,17 +225,6 @@ ${awaitility.version} test - - com.google.code.findbugs - annotations - ${findbug.version} - - - com.google.code.findbugs - jsr305 - 3.0.1 - provided - diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 91947f7b6d..26adfe26ad 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -69,9 +69,6 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca } @SuppressWarnings("PMD.AvoidReassigningParameters") - @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", - justification = "Not reachable code") public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem, EndpointDataReferenceStatus endpointDataReferenceStatus) throws ContractNegotiationException, UsagePolicyException, TransferProcessException { diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index 70cc301dde..1abe0b14b8 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -82,7 +82,6 @@ private Optional retrieveEndpointEndpointReferenceByAsset return endpointDataReferenceStorage.get(assetId); } - @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); return Instant.now().isAfter(tokenExpirationInstant); diff --git a/pom.xml b/pom.xml index 18a5ace2aa..d52a2dc84e 100644 --- a/pom.xml +++ b/pom.xml @@ -105,7 +105,6 @@ 5.9.2 2.4.10 1.19.1 - 3.0.1 4.7.3.2 From 6b8e0db4f486beaa055757499e0fe75718e07119 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Wed, 6 Dec 2023 11:26:06 +0100 Subject: [PATCH 09/59] feat(irs-api):[#256] spotbug fix --- .../irs/edc/client/ContractNegotiationService.java | 6 +++--- .../edc/client/util/EndpointDataReferenceCacheService.java | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 26adfe26ad..b4665d6676 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -91,11 +91,11 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca contractAgreementId = negotiationResponse.getContractAgreementId(); } case EXPIRED -> { - if (endpointDataReferenceStatus.endpointDataReference().getAuthKey() == null) { + final String authKey = endpointDataReferenceStatus.endpointDataReference().getAuthKey(); + if (authKey == null) { throw new IllegalStateException("Missing information about AuthKey."); } - contractAgreementId = EDRAuthCode.fromAuthCodeToken( - endpointDataReferenceStatus.endpointDataReference().getAuthKey()).getCid(); + contractAgreementId = EDRAuthCode.fromAuthCodeToken(authKey).getCid(); log.info( "Cached endpoint data reference has expired token. Refreshing token without new contract negotiation for contractAgreementId: {}", Masker.mask(contractAgreementId)); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index 1abe0b14b8..4f742bd666 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -31,6 +31,7 @@ import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; import org.eclipse.tractusx.irs.edc.client.model.EDRAuthCode; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; /** @@ -60,7 +61,7 @@ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId if (endpointDataReferenceOptional.isPresent() && endpointDataReferenceOptional.get().getAuthCode() != null) { final EndpointDataReference endpointDataReference = endpointDataReferenceOptional.get(); - if (isTokenExpired(endpointDataReference)) { + if (isTokenExpired(endpointDataReferenceOptional.get().getAuthCode())) { log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", endpointDataReference.getId(), assetId); return new EndpointDataReferenceStatus(endpointDataReference, @@ -82,8 +83,8 @@ private Optional retrieveEndpointEndpointReferenceByAsset return endpointDataReferenceStorage.get(assetId); } - private static boolean isTokenExpired(final EndpointDataReference endpointDataReference) { - final Instant tokenExpirationInstant = extractTokenExpiration(endpointDataReference.getAuthCode()); + private static boolean isTokenExpired(final @NotNull String authCode) { + final Instant tokenExpirationInstant = extractTokenExpiration(authCode); return Instant.now().isAfter(tokenExpirationInstant); } From d9d43afc9e8a2412597c07d7899e15b51d4a1b2d Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Wed, 6 Dec 2023 11:34:04 +0100 Subject: [PATCH 10/59] feat(irs-api):[#256] spotbug fix --- .../EndpointDataReferenceCacheService.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java index 4f742bd666..604e422bd5 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java @@ -59,18 +59,21 @@ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId final Optional endpointDataReferenceOptional = retrieveEndpointEndpointReferenceByAssetId( assetId); - if (endpointDataReferenceOptional.isPresent() && endpointDataReferenceOptional.get().getAuthCode() != null) { - final EndpointDataReference endpointDataReference = endpointDataReferenceOptional.get(); - if (isTokenExpired(endpointDataReferenceOptional.get().getAuthCode())) { - log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", - endpointDataReference.getId(), assetId); - return new EndpointDataReferenceStatus(endpointDataReference, - EndpointDataReferenceStatus.TokenStatus.EXPIRED); - } else { - log.info("Endpoint data reference with id: {} for assetId: {} found in storage.", - endpointDataReference.getId(), assetId); - return new EndpointDataReferenceStatus(endpointDataReference, - EndpointDataReferenceStatus.TokenStatus.VALID); + if (endpointDataReferenceOptional.isPresent()) { + final String authCode = endpointDataReferenceOptional.get().getAuthCode(); + if (authCode != null) { + final EndpointDataReference endpointDataReference = endpointDataReferenceOptional.get(); + if (isTokenExpired(authCode)) { + log.info("Endpoint data reference with expired token and id: {} for assetId: {} found in storage.", + endpointDataReference.getId(), assetId); + return new EndpointDataReferenceStatus(endpointDataReference, + EndpointDataReferenceStatus.TokenStatus.EXPIRED); + } else { + log.info("Endpoint data reference with id: {} for assetId: {} found in storage.", + endpointDataReference.getId(), assetId); + return new EndpointDataReferenceStatus(endpointDataReference, + EndpointDataReferenceStatus.TokenStatus.VALID); + } } } From 2f3994f7f95918ddb4ed7cbbb39d3f716022a6eb Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Fri, 8 Dec 2023 10:50:14 +0100 Subject: [PATCH 11/59] feat(irs-registry-client):[#256] added cache for send notification --- .../client/ContractNegotiationService.java | 17 ++-- .../irs/edc/client/EdcSubmodelClient.java | 94 +++++++++++-------- .../client/EndpointDataReferenceStorage.java | 7 +- .../EndpointDataReferenceCacheService.java | 4 +- .../EndpointDataReferenceStatus.java | 2 +- .../ContractNegotiationServiceTest.java | 2 +- .../edc/client/EdcCallbackControllerTest.java | 4 +- .../irs/edc/client/EdcSubmodelClientTest.java | 9 +- .../client/SubmodelFacadeWiremockTest.java | 2 +- .../irs/edc/client/SubmodelRetryerTest.java | 4 +- ...EndpointDataReferenceCacheServiceTest.java | 32 ++++--- 11 files changed, 98 insertions(+), 79 deletions(-) rename irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/{util => cache/endpointdatareference}/EndpointDataReferenceCacheService.java (96%) rename irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/{util => cache/endpointdatareference}/EndpointDataReferenceStatus.java (95%) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index b4665d6676..344cd039a8 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -45,7 +45,7 @@ import org.eclipse.tractusx.irs.edc.client.model.TransferProcessRequest; import org.eclipse.tractusx.irs.edc.client.model.TransferProcessResponse; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; import org.eclipse.tractusx.irs.edc.client.util.Masker; import org.springframework.stereotype.Service; @@ -68,22 +68,25 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); } - @SuppressWarnings("PMD.AvoidReassigningParameters") public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem, - EndpointDataReferenceStatus endpointDataReferenceStatus) + final EndpointDataReferenceStatus endpointDataReferenceStatus) throws ContractNegotiationException, UsagePolicyException, TransferProcessException { + EndpointDataReferenceStatus resultEndpointDataReferenceStatus; + if (endpointDataReferenceStatus == null) { log.info( "Missing information about endpoint data reference from storage, setting token status to REQUIRED_NEW."); - endpointDataReferenceStatus = new EndpointDataReferenceStatus(null, + resultEndpointDataReferenceStatus = new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW); + } else { + resultEndpointDataReferenceStatus = endpointDataReferenceStatus; } NegotiationResponse negotiationResponse = null; - String contractAgreementId = null; + String contractAgreementId; - switch (endpointDataReferenceStatus.tokenStatus()) { + switch (resultEndpointDataReferenceStatus.tokenStatus()) { case REQUIRED_NEW -> { final CompletableFuture responseFuture = startNewNegotiation(providerConnectorUrl, catalogItem); @@ -91,7 +94,7 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca contractAgreementId = negotiationResponse.getContractAgreementId(); } case EXPIRED -> { - final String authKey = endpointDataReferenceStatus.endpointDataReference().getAuthKey(); + final String authKey = resultEndpointDataReferenceStatus.endpointDataReference().getAuthKey(); if (authKey == null) { throw new IllegalStateException("Missing information about AuthKey."); } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java index e27b90e39c..3024f80792 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java @@ -24,7 +24,7 @@ package org.eclipse.tractusx.irs.edc.client; import static org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration.NAMESPACE_EDC_ID; -import static org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus; +import static org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus.TokenStatus; import java.net.URI; import java.util.List; @@ -43,12 +43,13 @@ import org.eclipse.tractusx.irs.data.StringMapper; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.edc.client.model.CatalogItem; +import org.eclipse.tractusx.irs.edc.client.model.EDRAuthCode; import org.eclipse.tractusx.irs.edc.client.model.NegotiationResponse; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationResponse; import org.eclipse.tractusx.irs.edc.client.model.notification.NotificationContent; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; import org.eclipse.tractusx.irs.edc.client.util.Masker; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @@ -70,8 +71,7 @@ CompletableFuture getEndpointReferenceForAsset(String end String filterValue) throws EdcClientException; CompletableFuture getEndpointReferenceForAsset(String endpointAddress, String filterKey, - String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference) - throws EdcClientException; + String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException; } /** @@ -162,31 +162,36 @@ private NegotiationResponse fetchNegotiationResponseWithFilter(final String conn return contractNegotiationService.negotiate(connectorEndpoint, catalogItem); } - private CompletableFuture sendNotificationAsync(final String contractAgreementId, - final EdcNotification notification, final StopWatch stopWatch) { + private CompletableFuture sendNotificationAsync(final String assetId, + final EdcNotification notification, final StopWatch stopWatch, + final EndpointDataReference endpointDataReference) { return pollingService.createJob() - .action(() -> sendSubmodelNotification(contractAgreementId, notification, stopWatch)) + .action(() -> sendSubmodelNotification(assetId, notification, stopWatch, + endpointDataReference)) .timeToLive(config.getSubmodel().getRequestTtl()) .description("waiting for submodel notification to be sent") .build() .schedule(); - } private Optional retrieveSubmodelData(final String submodelDataplaneUrl, final StopWatch stopWatch, final EndpointDataReference endpointDataReference) { - log.info("Retrieving data from EDC data plane for dataReference with id {}", endpointDataReference.getId()); - final String data = edcDataPlaneClient.getData(endpointDataReference, submodelDataplaneUrl); - stopWatchOnEdcTask(stopWatch); + if (endpointDataReference != null) { + log.info("Retrieving data from EDC data plane for dataReference with id {}", endpointDataReference.getId()); + final String data = edcDataPlaneClient.getData(endpointDataReference, submodelDataplaneUrl); + stopWatchOnEdcTask(stopWatch); - return Optional.of(data); + return Optional.of(data); + } + + return Optional.empty(); } - private Optional retrieveEndpointReference(final String contractAgreementId, + private Optional retrieveEndpointReference(final String storageId, final StopWatch stopWatch) { final Optional dataReference = retrieveEndpointDataReferenceByContractAgreementId( - contractAgreementId); + storageId); if (dataReference.isPresent()) { final EndpointDataReference ref = dataReference.get(); @@ -198,19 +203,17 @@ private Optional retrieveEndpointReference(final String c return Optional.empty(); } - private Optional sendSubmodelNotification(final String contractAgreementId, - final EdcNotification notification, final StopWatch stopWatch) { - final Optional dataReference = retrieveEndpointDataReferenceByContractAgreementId( - contractAgreementId); + private Optional sendSubmodelNotification(final String assetId, + final EdcNotification notification, final StopWatch stopWatch, + final EndpointDataReference endpointDataReference) { - if (dataReference.isPresent()) { - final EndpointDataReference ref = dataReference.get(); - log.info("Sending dataReference to EDC data plane for contractAgreementId '{}'", - Masker.mask(contractAgreementId)); - final EdcNotificationResponse response = edcDataPlaneClient.sendData(ref, notification); + if (endpointDataReference != null) { + log.info("Sending dataReference to EDC data plane for assetId '{}'", assetId); + final EdcNotificationResponse response = edcDataPlaneClient.sendData(endpointDataReference, notification); stopWatchOnEdcTask(stopWatch); return Optional.of(response); } + return Optional.empty(); } @@ -234,18 +237,19 @@ public CompletableFuture getSubmodelRawPayload(final String connectorEnd }); } - @SuppressWarnings("PMD.ConfusingTernary") private EndpointDataReference getEndpointDataReference(final String connectorEndpoint, final String assetId) throws EdcClientException { + log.info("Retrieving endpoint data reference from cache for assed id: {}", assetId); final EndpointDataReferenceStatus cachedEndpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( assetId); EndpointDataReference endpointDataReference; - if (cachedEndpointDataReference.tokenStatus() != TokenStatus.VALID) { + if (cachedEndpointDataReference.tokenStatus() == TokenStatus.VALID) { + log.info("Endpoint data reference found in cache with token status valid, reusing cache record."); + endpointDataReference = cachedEndpointDataReference.endpointDataReference(); + } else { endpointDataReference = getEndpointDataReferenceAndAddToStorage(connectorEndpoint, assetId, cachedEndpointDataReference); - } else { - endpointDataReference = cachedEndpointDataReference.endpointDataReference(); } return endpointDataReference; @@ -274,12 +278,9 @@ public CompletableFuture sendNotification(final String return execute(connectorEndpoint, () -> { final StopWatch stopWatch = new StopWatch(); stopWatch.start("Send EDC notification task, endpoint " + connectorEndpoint); - final var negotiationEndpoint = appendSuffix(connectorEndpoint, - config.getControlplane().getProviderSuffix()); - final NegotiationResponse negotiationResponse = fetchNegotiationResponseWithFilter(negotiationEndpoint, - assetId); + final EndpointDataReference endpointDataReference = getEndpointDataReference(connectorEndpoint, assetId); - return sendNotificationAsync(negotiationResponse.getContractAgreementId(), notification, stopWatch); + return sendNotificationAsync(assetId, notification, stopWatch, endpointDataReference); }); } @@ -307,8 +308,10 @@ public CompletableFuture getEndpointReferenceForAsset(fin final NegotiationResponse response = contractNegotiationService.negotiate(providerWithSuffix, items.stream().findFirst().orElseThrow(), endpointDataReferenceStatus); + final String storageId = getStorageId(endpointDataReferenceStatus, response); + return pollingService.createJob() - .action(() -> retrieveEndpointReference(response.getContractAgreementId(), stopWatch)) + .action(() -> retrieveEndpointReference(storageId, stopWatch)) .timeToLive(config.getSubmodel().getRequestTtl()) .description("waiting for Endpoint Reference retrieval") .build() @@ -317,6 +320,21 @@ public CompletableFuture getEndpointReferenceForAsset(fin }); } + private static String getStorageId(final EndpointDataReferenceStatus endpointDataReferenceStatus, + final NegotiationResponse response) { + final String storageId; + if (response != null) { + storageId = response.getContractAgreementId(); + } else { + final String authKey = endpointDataReferenceStatus.endpointDataReference().getAuthKey(); + if (authKey == null) { + throw new IllegalStateException("Missing information about AuthKey."); + } + storageId = EDRAuthCode.fromAuthCodeToken(authKey).getCid(); + } + return storageId; + } + private String appendSuffix(final String endpointAddress, final String providerSuffix) { String addressWithSuffix; if (endpointAddress.endsWith(providerSuffix)) { @@ -329,10 +347,10 @@ private String appendSuffix(final String endpointAddress, final String providerS return addressWithSuffix; } - private Optional retrieveEndpointDataReferenceByContractAgreementId( - final String contractAgreementId) { - log.info("Retrieving dataReference from storage for contractAgreementId {}", Masker.mask(contractAgreementId)); - return endpointDataReferenceStorage.remove(contractAgreementId); + private Optional retrieveEndpointDataReferenceByContractAgreementId(final String storageId) { + log.info("Retrieving dataReference from storage for storageId (assetId or contractAgreementId): {}", + Masker.mask(storageId)); + return endpointDataReferenceStorage.get(storageId); } @SuppressWarnings({ "PMD.AvoidRethrowingException", diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java index 2110f52961..80bd53c4d3 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EndpointDataReferenceStorage.java @@ -69,13 +69,8 @@ private void cleanup() { }); } - public Optional remove(final String storageId) { - return Optional.ofNullable(storageMap.remove(storageId)).map(ExpiringContainer::getDataReference); - } - public Optional get(final String storageId) { - return Optional.ofNullable( - storageMap.get(storageId) != null ? storageMap.get(storageId).getDataReference() : null); + return Optional.ofNullable(storageMap.get(storageId)).map(ExpiringContainer::getDataReference); } /** diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java similarity index 96% rename from irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java rename to irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java index 604e422bd5..2b044a0b39 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java @@ -21,7 +21,7 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package org.eclipse.tractusx.irs.edc.client.util; +package org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference; import java.time.Instant; import java.util.Optional; @@ -52,7 +52,7 @@ public class EndpointDataReferenceCacheService { * @param assetId key for * {@link org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage} * @return {@link org.eclipse.edc.spi.types.domain.edr.EndpointDataReference} - * and {@link org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus} + * and {@link EndpointDataReferenceStatus.TokenStatus} * describing token status */ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId) { diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceStatus.java similarity index 95% rename from irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java rename to irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceStatus.java index 6687aad5fb..f14745a5b5 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceStatus.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceStatus.java @@ -21,7 +21,7 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package org.eclipse.tractusx.irs.edc.client.util; +package org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java index da0787bacb..2748e84e0c 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java @@ -44,7 +44,7 @@ import org.eclipse.tractusx.irs.edc.client.model.Response; import org.eclipse.tractusx.irs.edc.client.model.TransferProcessResponse; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcCallbackControllerTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcCallbackControllerTest.java index 9297a473df..f43d2aa7ad 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcCallbackControllerTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcCallbackControllerTest.java @@ -49,7 +49,7 @@ void shouldStoreAgreementId() { testee.receiveEdcCallback(ref); // assert - final var result = storage.remove("testId"); + final var result = storage.get("testId"); assertThat(result).isNotNull().contains(ref); } @@ -62,7 +62,7 @@ void shouldDoNothingWhenEDRTokenIsInvalid() { testee.receiveEdcCallback(ref); // assert - final var result = storage.remove("testId"); + final var result = storage.get("testId"); assertThat(result).isNotNull().isEmpty(); } } \ No newline at end of file diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index 3a694937c6..730469b02f 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -24,7 +24,7 @@ package org.eclipse.tractusx.irs.edc.client; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus.TokenStatus; +import static org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus.TokenStatus; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -70,8 +70,8 @@ import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationResponse; import org.eclipse.tractusx.irs.edc.client.model.notification.NotificationContent; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; import org.eclipse.tractusx.irs.testing.containers.LocalTestDataConfigurationAware; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; @@ -155,11 +155,12 @@ void shouldSendNotificationSuccessfully() throws Exception { final EdcNotification notification = EdcNotification.builder().build(); when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); - when(contractNegotiationService.negotiate(any(), any())).thenReturn( + when(contractNegotiationService.negotiate(any(), any(), any())).thenReturn( NegotiationResponse.builder().contractAgreementId("agreementId").build()); final EndpointDataReference ref = mock(EndpointDataReference.class); endpointDataReferenceStorage.put("agreementId", ref); when(edcDataPlaneClient.sendData(ref, notification)).thenReturn(() -> true); + when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act final var result = testee.sendNotification(CONNECTOR_ENDPOINT, "notify-request-asset", notification); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java index 0a7210fcf4..a6fdc2217e 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java @@ -64,7 +64,7 @@ import org.eclipse.tractusx.irs.edc.client.policy.Permission; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; import org.eclipse.tractusx.irs.edc.client.policy.PolicyType; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java index e0c228f4bb..2ed23c9674 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java @@ -37,8 +37,8 @@ import io.github.resilience4j.retry.RetryRegistry; import io.github.resilience4j.retry.internal.InMemoryRetryRegistry; import org.eclipse.tractusx.irs.edc.client.policy.PolicyCheckerService; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceCacheService; -import org.eclipse.tractusx.irs.edc.client.util.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java index b84e338b78..96dd69b0a1 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/util/EndpointDataReferenceCacheServiceTest.java @@ -1,18 +1,3 @@ -package org.eclipse.tractusx.irs.edc.client.util; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -import java.util.Optional; - -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - /******************************************************************************** * Copyright (c) 2021,2022,2023 * 2022: ZF Friedrichshafen AG @@ -36,6 +21,23 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +package org.eclipse.tractusx.irs.edc.client.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; +import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + @ExtendWith(MockitoExtension.class) class EndpointDataReferenceCacheServiceTest { From 1e321b5deaabb8628079d9481a89dadcea39ec82 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Fri, 8 Dec 2023 10:54:12 +0100 Subject: [PATCH 12/59] feat(irs-registry-client):[#256] removed unused method --- .../irs/edc/client/EdcSubmodelClient.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java index 3024f80792..4ef55da505 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java @@ -145,23 +145,6 @@ private static void stopWatchOnEdcTask(final StopWatch stopWatch) { log.info("EDC Task '{}' took {} ms", stopWatch.getLastTaskName(), stopWatch.getLastTaskTimeMillis()); } - private NegotiationResponse fetchNegotiationResponseWithFilter(final String connectorEndpoint, final String assetId) - throws EdcClientException { - - final StopWatch stopWatch = new StopWatch(); - stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + connectorEndpoint); - - final List catalog = catalogFacade.fetchCatalogByFilter(connectorEndpoint, NAMESPACE_EDC_ID, - assetId); - - final CatalogItem catalogItem = catalog.stream() - .findFirst() - .orElseThrow(() -> new ItemNotFoundInCatalogException(connectorEndpoint, - assetId)); - - return contractNegotiationService.negotiate(connectorEndpoint, catalogItem); - } - private CompletableFuture sendNotificationAsync(final String assetId, final EdcNotification notification, final StopWatch stopWatch, final EndpointDataReference endpointDataReference) { From 667f575dad7d6d5904ddebf94cbc72c3d33ef852 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Mon, 11 Dec 2023 11:13:33 +0100 Subject: [PATCH 13/59] feat(irs-registry-client):[#256] added changelog record --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2716573f2c..2de4ac2b05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated edc dependencies to 0.2.1 - Update deprecated field `providerUrl` to `counterPartyAddress` in EDC catalog request - Update ESS EDC notification creation asset endpoint to v3 +- Added EDR token cache to reuse token after contract negotiation ## [4.2.0] - 2023-11-28 From f60a102a0fc2dd4a34eb1076354c63e09eca1e93 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 09:53:33 +0100 Subject: [PATCH 14/59] feat(impl):[#259] new authentication through api key impl --- .config/spotbugs-excludes.xml | 4 +- .../configmap-spring-app-config.yaml | 15 +-- charts/irs-helm/values.yaml | 9 +- .../eclipse/tractusx/irs/IrsApplication.java | 4 +- ...nciesHealthMetricsExportConfiguration.java | 4 +- .../HealthMetricsExportConfiguration.java | 2 +- .../irs/configuration/HealthStatusHelper.java | 2 +- .../converter/IrsTokenParser.java | 66 ---------- .../converter/JwtAuthenticationConverter.java | 59 --------- .../security/ApiKeyAuthentication.java | 35 +++--- .../security/ApiKeyAuthenticationFilter.java | 82 +++++++++++++ .../security/ApiKeyAuthority.java | 41 +++++++ .../security/ApiKeysConfiguration.java | 64 ++++++++++ .../security/AuthenticationService.java | 52 ++++++++ .../{ => security}/SecurityConfiguration.java | 113 +++++++++-------- .../irs/controllers/BatchController.java | 12 +- .../irs/controllers/IrsController.java | 12 +- .../irs/ess/controller/EssController.java | 6 +- irs-api/src/main/resources/application.yml | 16 +-- .../eclipse/tractusx/irs/ControllerTest.java | 48 ++++++++ .../configuration/HealthStatusHelperTest.java | 2 +- .../JwtAuthenticationConverterTest.java | 115 ------------------ .../ApiKeyAuthenticationFilterTest.java | 30 +++++ .../irs/controllers/BatchControllerTest.java | 45 +++---- .../irs/controllers/IrsControllerTest.java | 94 +++++++------- .../controllers/IrsExceptionHandlerTest.java | 32 +++-- .../irs/ess/controller/EssControllerTest.java | 35 +++--- .../EssRecursiveControllerTest.java | 15 +-- .../common/auth/AuthorizationServiceTest.java | 112 ----------------- .../controllers/PolicyStoreController.java | 8 +- 30 files changed, 540 insertions(+), 594 deletions(-) delete mode 100644 irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/IrsTokenParser.java delete mode 100644 irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverter.java rename irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/AuthorizationService.java => irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java (56%) create mode 100644 irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java create mode 100644 irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java create mode 100644 irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java create mode 100644 irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java rename irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/{ => security}/SecurityConfiguration.java (58%) create mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java delete mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverterTest.java create mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java delete mode 100644 irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/AuthorizationServiceTest.java diff --git a/.config/spotbugs-excludes.xml b/.config/spotbugs-excludes.xml index e38b12df62..ff2379382f 100644 --- a/.config/spotbugs-excludes.xml +++ b/.config/spotbugs-excludes.xml @@ -25,13 +25,13 @@ - + - + diff --git a/charts/irs-helm/templates/configmap-spring-app-config.yaml b/charts/irs-helm/templates/configmap-spring-app-config.yaml index c3961c4b2a..7032da7f92 100644 --- a/charts/irs-helm/templates/configmap-spring-app-config.yaml +++ b/charts/irs-helm/templates/configmap-spring-app-config.yaml @@ -34,6 +34,11 @@ data: irs: apiUrl: {{ tpl (.Values.irsUrl | default "http://localhost") . | quote }} + security: + api: + keys: + admin: {{ tpl (.Values.apiKeyAdmin | default "") . | quote }} + regular: {{ tpl (.Values.apiKeyRegular | default "") . | quote }} blobstore: endpoint: {{ tpl (.Values.minioUrl | default "") . | quote }} @@ -62,9 +67,6 @@ data: token-uri: {{ tpl (.Values.oauth2.clientTokenUri | default "http://localhost") . | quote }} portal: token-uri: {{ tpl (.Values.oauth2.clientTokenUri | default "http://localhost") . | quote }} - resourceserver: - jwt: - jwk-set-uri: {{ tpl (.Values.oauth2.jwkSetUri | default "http://localhost") . | quote }} digitalTwinRegistry: descriptorEndpoint: {{ tpl (.Values.digitalTwinRegistry.descriptorEndpoint | default "") . | quote }} @@ -145,13 +147,6 @@ data: {{- end }} {{- end }} - apiAllowedBpn: {{ tpl (.Values.bpn | default "") . | quote }} - - oauth: - resourceClaim: {{ tpl (.Values.oauth.resourceClaim | default "resource_access") . | quote }} - irsNamespace: {{ tpl (.Values.oauth.irsNamespace | default "") . | quote }} - roles: {{ tpl (.Values.oauth.roles | default "roles") . | quote }} - {{- if .Values.config.content }} {{- tpl (toYaml .Values.config.content) . | nindent 4 }} {{- end }} diff --git a/charts/irs-helm/values.yaml b/charts/irs-helm/values.yaml index 32f565aff3..3e066f347d 100644 --- a/charts/irs-helm/values.yaml +++ b/charts/irs-helm/values.yaml @@ -105,7 +105,8 @@ readinessProbe: # IRS Configuration # ##################### irsUrl: # "https://" -bpn: # BPN for this IRS instance; only users with this BPN are allowed to access the API +apiKeyAdmin: # Api key to access API with admin role +apiKeyRegular: # Api key to access API with regular/view role ingress: enabled: false @@ -153,7 +154,6 @@ oauth2: clientId: # clientSecret: # clientTokenUri: # - jwkSetUri: # portal: oauth2: clientId: # @@ -217,11 +217,6 @@ ess: policydefinitionsPath: /management/v2/policydefinitions # EDC management API "policydefinitions" path - used for notification policy definition creation contractdefinitionsPath: /management/v2/contractdefinitions # EDC management API "contractdefinitions" path - used for notification contract definitions creation -oauth: - resourceClaim: "resource_access" # Name of the JWT claim for roles - irsNamespace: "Cl20-CX-IRS" # Namespace for the IRS roles - roles: "roles" # Name of the list of roles within the IRS namespace - config: # If true, the config provided below will completely replace the configmap. # In this case, you need to provide all required config values defined above yourself! diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/IrsApplication.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/IrsApplication.java index 9d4bbbf566..81c0e0fa27 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/IrsApplication.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/IrsApplication.java @@ -26,6 +26,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration; import org.springframework.boot.context.TypeExcludeFilter; import org.springframework.cache.annotation.EnableCaching; @@ -37,7 +39,7 @@ /** * Application entry point. */ -@SpringBootApplication(exclude = WebSocketServletAutoConfiguration.class) +@SpringBootApplication(exclude = { SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class, WebSocketServletAutoConfiguration.class }) @EnableScheduling @EnableCaching @EnableAsync diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/DependenciesHealthMetricsExportConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/DependenciesHealthMetricsExportConfiguration.java index fee6f78ca5..9016948bec 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/DependenciesHealthMetricsExportConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/DependenciesHealthMetricsExportConfiguration.java @@ -73,7 +73,7 @@ private void registerOverallHealthMetric(final MeterRegistry registry, log.debug("Registering metric '{}'", metricDescriptor.name); final ToDoubleFunction statusProvider = // - healthIndicator -> HealthStatusHelper.healthStatustoNumeric(overallStatus(healthIndicator)); + healthIndicator -> HealthStatusHelper.healthStatusToNumeric(overallStatus(healthIndicator)); Gauge.builder(metricDescriptor.name, dependenciesHealthIndicator, statusProvider) .description(metricDescriptor.description()) @@ -103,7 +103,7 @@ private void registerIrsDependencyHealthMetric(final MeterRegistry registry, log.debug("Registering metric '{}' tag '{}'", metricDescriptor.name, dependencyName); final ToDoubleFunction statusProvider = // - healthIndicator -> HealthStatusHelper.healthStatustoNumeric( + healthIndicator -> HealthStatusHelper.healthStatusToNumeric( getIrsDependencyStatus(healthIndicator, dependencyName)); Gauge.builder(metricDescriptor.name, dependenciesHealthIndicator, statusProvider) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthMetricsExportConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthMetricsExportConfiguration.java index 4f3f323fcf..d56559f3e1 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthMetricsExportConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthMetricsExportConfiguration.java @@ -55,7 +55,7 @@ private void registerIrsHealthMetrics(final MeterRegistry registry, final Health log.debug("Registering metric '{}'", metricName); final ToDoubleFunction statusProvider = // - healthEndpoint -> HealthStatusHelper.healthStatustoNumeric(getIrsStatus(healthEndpoint)); + healthEndpoint -> HealthStatusHelper.healthStatusToNumeric(getIrsStatus(healthEndpoint)); Gauge.builder(metricName, irsHealthEndpoint, statusProvider) .description("The IRS health status.") diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelper.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelper.java index c531a0e4ca..305bccd738 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelper.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelper.java @@ -45,7 +45,7 @@ public class HealthStatusHelper { * @param status the health status * @return the numeric representation of the health status */ - public static int healthStatustoNumeric(final Status status) { + public static int healthStatusToNumeric(final Status status) { // see Spring documentation - map health indicators to metrics: // https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/IrsTokenParser.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/IrsTokenParser.java deleted file mode 100644 index 198e767930..0000000000 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/IrsTokenParser.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021,2022,2023 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH AG - * Copyright (c) 2021,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.irs.configuration.converter; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import com.nimbusds.jose.shaded.gson.internal.LinkedTreeMap; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jwt.Jwt; - -/** - * Parsing JWT - retrieving resource_access claim with IRS roles. - */ -@Slf4j -@AllArgsConstructor -public class IrsTokenParser { - - private String resourceAccessClaim; - private String irsResourceAccess; - private String roles; - - /** - * Parsing JWT - retrieving resource_access claim with IRS roles. - * - * @param jwt source - * @return set of roles from token - */ - public Set extractIrsRolesFromToken(final Jwt jwt) { - return Optional.ofNullable(jwt.getClaim(resourceAccessClaim)) - .map(LinkedTreeMap.class::cast) - .map(accesses -> accesses.get(irsResourceAccess)) - .map(LinkedTreeMap.class::cast) - .map(irsAccesses -> irsAccesses.get(roles)) - .map(irsRoles -> ((List) irsRoles).stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toSet())) - .orElse(Collections.emptySet()); - } -} diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverter.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverter.java deleted file mode 100644 index 81f4b71ced..0000000000 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverter.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021,2022,2023 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH AG - * Copyright (c) 2021,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.irs.configuration.converter; - -import java.util.Collection; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import lombok.AllArgsConstructor; -import org.jetbrains.annotations.NotNull; -import org.springframework.core.convert.converter.Converter; -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; -import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; - -/** - * JWT Converter - */ -@AllArgsConstructor -public class JwtAuthenticationConverter implements Converter { - - private JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter; - private IrsTokenParser irsTokenParser; - - @Override - public AbstractAuthenticationToken convert(final @NotNull Jwt source) { - final Collection grantedAuthorities = jwtGrantedAuthoritiesConverter.convert(source); - - final Collection authorities = Stream.concat( - grantedAuthorities != null ? grantedAuthorities.stream() : Stream.empty(), - irsTokenParser.extractIrsRolesFromToken(source).stream()).collect(Collectors.toSet()); - - return new JwtAuthenticationToken(source, authorities); - } -} - diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/AuthorizationService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java similarity index 56% rename from irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/AuthorizationService.java rename to irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java index f695499d15..7584d033c8 100644 --- a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/AuthorizationService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java @@ -21,33 +21,30 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package org.eclipse.tractusx.irs.common.auth; +package org.eclipse.tractusx.irs.configuration.security; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; +import org.springframework.security.authentication.AbstractAuthenticationToken; /** - * BPN contains in JWT Token matches BPN under which IRS product is registered. + * Api key authentication representation */ -@Service -public class AuthorizationService { +public class ApiKeyAuthentication extends AbstractAuthenticationToken { - private final SecurityHelperService securityHelperService; - private final String apiAllowedBpn; + private final ApiKeyAuthority apiKeyAuthority; - public AuthorizationService(@Value("${apiAllowedBpn:}") final String apiAllowedBpn) { - this.securityHelperService = new SecurityHelperService(); - this.apiAllowedBpn = apiAllowedBpn; + public ApiKeyAuthentication(final ApiKeyAuthority apiKeyAuthority) { + super(apiKeyAuthority.authorities()); + this.apiKeyAuthority = apiKeyAuthority; + setAuthenticated(true); } - public boolean verifyBpn() { - if (StringUtils.isBlank(apiAllowedBpn)) { - return false; - } - - final String bpnFromToken = securityHelperService.getBpnClaim(); - return apiAllowedBpn.equals(bpnFromToken); + @Override + public Object getCredentials() { + return apiKeyAuthority.apiKey(); } + @Override + public Object getPrincipal() { + return apiKeyAuthority.apiKey(); + } } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java new file mode 100644 index 0000000000..484254e393 --- /dev/null +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java @@ -0,0 +1,82 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.configuration.security; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.eclipse.tractusx.irs.dtos.ErrorResponse; +import org.eclipse.tractusx.irs.util.JsonUtil; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +/** + * Filter to execute authentication based on X-API-KEY header + */ +@RequiredArgsConstructor +class ApiKeyAuthenticationFilter extends OncePerRequestFilter { + + private final AuthenticationService authenticationService; + private final JsonUtil jsonUtil; + + @Override + protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain filterChain) throws ServletException, IOException { + try { + final Authentication authentication = authenticationService.getAuthentication(request); + SecurityContextHolder.getContext().setAuthentication(authentication); + } catch (final BadCredentialsException exception) { + unauthorizedResponse(response, exception); + } + + filterChain.doFilter(request, response); + } + + private void unauthorizedResponse(final HttpServletResponse servletResponse, final Exception exception) throws IOException { + servletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + servletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); + servletResponse.setCharacterEncoding(StandardCharsets.UTF_8.name()); + + final ErrorResponse errorResponse = ErrorResponse.builder() + .withStatusCode(HttpStatus.UNAUTHORIZED) + .withError(exception.getMessage()) + .build(); + + + try (PrintWriter writer = servletResponse.getWriter()) { + writer.print(jsonUtil.asString(errorResponse)); + writer.flush(); + } + } +} diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java new file mode 100644 index 0000000000..6b61ab6047 --- /dev/null +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.configuration.security; + +import java.util.List; + +import org.springframework.security.core.GrantedAuthority; + +/** + * @param apiKey + * @param authorities + */ +public record ApiKeyAuthority(String apiKey, List authorities) { + + @SuppressWarnings("PMD.ShortMethodName") + public static ApiKeyAuthority of(final String apiKey, final List authorities) { + return new ApiKeyAuthority(apiKey, authorities); + } + +} diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java new file mode 100644 index 0000000000..c8be770750 --- /dev/null +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java @@ -0,0 +1,64 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.configuration.security; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Setter; +import org.eclipse.tractusx.irs.common.auth.IrsRoles; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.stereotype.Component; +import org.springframework.validation.annotation.Validated; + +/** + * Configuration class for api keys + */ +@Component +@ConfigurationProperties(prefix = "irs.security.api.keys") +@Validated +@Setter +class ApiKeysConfiguration { + + private static final int MIN_API_KEY_SIZE = 20; + + @NotBlank + @Size(min = MIN_API_KEY_SIZE) + private String admin; + + @NotBlank + @Size(min = MIN_API_KEY_SIZE) + private String regular; + + /* package */ ApiKeyAuthority authorityOf(final String apiKey) { + if (apiKey.equals(admin)) { + return ApiKeyAuthority.of(apiKey, AuthorityUtils.createAuthorityList(IrsRoles.ADMIN_IRS)); + } else if (apiKey.equals(regular)) { + return ApiKeyAuthority.of(regular, AuthorityUtils.createAuthorityList(IrsRoles.VIEW_IRS)); + } + + throw new BadCredentialsException("Wrong ApiKey"); + } +} diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java new file mode 100644 index 0000000000..aafebcfc39 --- /dev/null +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java @@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.configuration.security; + +import com.apicatalog.jsonld.StringUtils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +/** + * Check X-API-KEY header against api keys from config + */ +@RequiredArgsConstructor +@Service +public class AuthenticationService { + + private static final String AUTH_TOKEN_HEADER_NAME = "X-API-KEY"; + + private final ApiKeysConfiguration apiKeysConfiguration; + + public Authentication getAuthentication(final HttpServletRequest request) { + final String apiKeyHeader = request.getHeader(AUTH_TOKEN_HEADER_NAME); + if (StringUtils.isBlank(apiKeyHeader)) { + throw new BadCredentialsException("Wrong ApiKey"); + } + + return new ApiKeyAuthentication(apiKeysConfiguration.authorityOf(apiKeyHeader)); + } +} diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/SecurityConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java similarity index 58% rename from irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/SecurityConfiguration.java rename to irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java index d7a46ab4bd..432fce53fa 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/SecurityConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java @@ -21,17 +21,23 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package org.eclipse.tractusx.irs.configuration; +package org.eclipse.tractusx.irs.configuration.security; +import static java.util.Arrays.stream; import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; +import java.io.IOException; import java.time.Duration; import java.util.List; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.eclipse.tractusx.irs.common.ApiConstants; -import org.eclipse.tractusx.irs.configuration.converter.IrsTokenParser; -import org.eclipse.tractusx.irs.configuration.converter.JwtAuthenticationConverter; -import org.springframework.beans.factory.annotation.Value; +import org.eclipse.tractusx.irs.util.JsonUtil; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; @@ -40,16 +46,18 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; -import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter; import org.springframework.security.web.header.writers.PermissionsPolicyHeaderWriter; import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter; import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter; import org.springframework.security.web.util.matcher.AnyRequestMatcher; +import org.springframework.util.AntPathMatcher; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.OncePerRequestFilter; /** * Security config bean @@ -57,21 +65,22 @@ @Configuration @EnableWebSecurity @EnableMethodSecurity +@SuppressWarnings({ "PMD.ExcessiveImports" }) public class SecurityConfiguration { - private static final String[] WHITELIST = { - "/actuator/health", - "/actuator/health/readiness", - "/actuator/health/liveness", - "/actuator/prometheus", - "/api/swagger-ui/**", - "/api/api-docs", - "/api/api-docs.yaml", - "/api/api-docs/swagger-config", - "/" + ApiConstants.API_PREFIX_INTERNAL + "/endpoint-data-reference", - "/ess/mock/notification/receive", - "/ess/notification/receive", - "/ess/notification/receive-recursive" + private static final String[] WHITELIST = { "/actuator/health", + "/actuator/health/readiness", + "/actuator/health/liveness", + "/actuator/prometheus", + "/api/swagger-ui/**", + "/api/api-docs", + "/api/api-docs.yaml", + "/api/api-docs/swagger-config", + "/favicon.ico", + "/" + ApiConstants.API_PREFIX_INTERNAL + "/endpoint-data-reference", + "/ess/mock/notification/receive", + "/ess/notification/receive", + "/ess/notification/receive-recursive" }; private static final long HSTS_MAX_AGE_DAYS = 365; private static final String ONLY_SELF_SCRIPT_SRC = "script-src 'self'"; @@ -80,7 +89,7 @@ public class SecurityConfiguration { @SuppressWarnings("PMD.SignatureDeclareThrowsException") @Bean /* package */ SecurityFilterChain securityFilterChain(final HttpSecurity httpSecurity, - final JwtAuthenticationConverter jwtAuthenticationConverter) throws Exception { + final AuthenticationService authenticationService) throws Exception { httpSecurity.httpBasic(AbstractHttpConfigurer::disable); httpSecurity.formLogin(AbstractHttpConfigurer::disable); httpSecurity.csrf(AbstractHttpConfigurer::disable); @@ -88,39 +97,53 @@ public class SecurityConfiguration { httpSecurity.cors(Customizer.withDefaults()); httpSecurity.headers(headers -> headers.httpStrictTransportSecurity( - httpStrictTransportSecurity -> - httpStrictTransportSecurity.maxAgeInSeconds(Duration.ofDays(HSTS_MAX_AGE_DAYS).toSeconds()) - .includeSubDomains(true) - .preload(true) - .requestMatcher(AnyRequestMatcher.INSTANCE))); + httpStrictTransportSecurity -> httpStrictTransportSecurity.maxAgeInSeconds( + Duration.ofDays(HSTS_MAX_AGE_DAYS).toSeconds()).includeSubDomains(true).preload(true).requestMatcher(AnyRequestMatcher.INSTANCE))); - httpSecurity.headers(headers -> headers.xssProtection(xXssConfig -> - xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))); + httpSecurity.headers(headers -> headers.xssProtection(xXssConfig -> xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))); httpSecurity.headers(headers -> headers.addHeaderWriter(new ContentSecurityPolicyHeaderWriter(ONLY_SELF_SCRIPT_SRC))); httpSecurity.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)); - httpSecurity.headers(headers -> headers.addHeaderWriter(new ReferrerPolicyHeaderWriter( - ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN))); + httpSecurity.headers(headers -> headers.addHeaderWriter(new ReferrerPolicyHeaderWriter(ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN))); httpSecurity.headers(headers -> headers.addHeaderWriter(new PermissionsPolicyHeaderWriter(PERMISSION_POLICY))); - httpSecurity.sessionManagement(sessionManagement -> sessionManagement - .sessionCreationPolicy(STATELESS)); + httpSecurity.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(STATELESS)); - httpSecurity.authorizeHttpRequests(auth -> auth - .requestMatchers(WHITELIST) - .permitAll() - .requestMatchers("/**") - .authenticated()); + httpSecurity.authorizeHttpRequests(auth -> auth.requestMatchers(WHITELIST).permitAll().requestMatchers("/**").authenticated()); - httpSecurity.oauth2ResourceServer(oauth2ResourceServer -> - oauth2ResourceServer.jwt(jwt -> - jwt.jwtAuthenticationConverter(jwtAuthenticationConverter))) - .oauth2Client(Customizer.withDefaults()); + httpSecurity.addFilterBefore(new IgnoreWhitelistedPathFilter(new ApiKeyAuthenticationFilter(authenticationService, new JsonUtil())), UsernamePasswordAuthenticationFilter.class); + + httpSecurity.exceptionHandling(AbstractHttpConfigurer::disable); return httpSecurity.build(); } + /** + * Dont execute delegate filter on whitelisted paths + */ + @RequiredArgsConstructor + private static final class IgnoreWhitelistedPathFilter extends OncePerRequestFilter { + + private final Filter delegate; + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + + @Override + protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws + ServletException, IOException { + if (isNotWhitelisted(request)) { + delegate.doFilter(request, response, filterChain); + } else { + filterChain.doFilter(request, response); + } + } + + private boolean isNotWhitelisted(final HttpServletRequest request) { + return stream(WHITELIST).noneMatch(path -> pathMatcher.match(path, request.getRequestURI())); + } + } + + @Bean /* package */ CorsConfigurationSource corsConfigurationSource() { final CorsConfiguration configuration = new CorsConfiguration(); @@ -134,16 +157,4 @@ public class SecurityConfiguration { source.registerCorsConfiguration("/**", configuration); return source; } - - @Bean - /* package */ IrsTokenParser irsTokenParser(@Value("${oauth.resourceClaim}") final String resourceAccessClaim, - @Value("${oauth.irsNamespace}") final String irsResourceAccess, - @Value("${oauth.roles}") final String roles) { - return new IrsTokenParser(resourceAccessClaim, irsResourceAccess, roles); - } - - @Bean - /* package */ JwtAuthenticationConverter jwtAuthenticationConverter(final IrsTokenParser irsTokenParser) { - return new JwtAuthenticationConverter(new JwtGrantedAuthoritiesConverter(), irsTokenParser); - } } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/BatchController.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/BatchController.java index f638ac0bcb..d8c7f4db7d 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/BatchController.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/BatchController.java @@ -49,7 +49,6 @@ import org.eclipse.tractusx.irs.component.RegisterBatchOrder; import org.eclipse.tractusx.irs.component.RegisterBpnInvestigationBatchOrder; import org.eclipse.tractusx.irs.dtos.ErrorResponse; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; import org.eclipse.tractusx.irs.services.CreationBatchService; import org.eclipse.tractusx.irs.services.QueryBatchService; import org.eclipse.tractusx.irs.services.timeouts.CancelBatchProcessingService; @@ -79,7 +78,6 @@ public class BatchController { private final CreationBatchService creationBatchService; private final QueryBatchService queryBatchService; private final CancelBatchProcessingService cancelBatchProcessingService; - private final AuthorizationService authorizationService; @Operation(operationId = "registerOrder", summary = "Registers an IRS order with an array of {globalAssetIds}. " @@ -116,7 +114,7 @@ public class BatchController { }) @PostMapping("/orders") @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public BatchOrderCreated registerBatchOrder(final @Valid @RequestBody RegisterBatchOrder request) { final UUID batchOrderId = creationBatchService.create(request); return BatchOrderCreated.builder().id(batchOrderId).build(); @@ -155,7 +153,7 @@ public BatchOrderCreated registerBatchOrder(final @Valid @RequestBody RegisterBa }) @PostMapping("/ess/orders") @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public BatchOrderCreated registerESSInvestigationOrder(final @Valid @RequestBody RegisterBpnInvestigationBatchOrder request) { final UUID batchOrderId = creationBatchService.create(request); return BatchOrderCreated.builder().id(batchOrderId).build(); @@ -199,7 +197,7 @@ public BatchOrderCreated registerESSInvestigationOrder(final @Valid @RequestBody }), }) @GetMapping("/orders/{orderId}") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public BatchOrderResponse getBatchOrder( @Parameter(description = "Id of the order.", schema = @Schema(implementation = UUID.class), name = "orderId", example = "6c311d29-5753-46d4-b32c-19b918ea93b0") @Size(min = IrsAppConstants.JOB_ID_SIZE, @@ -245,7 +243,7 @@ public BatchOrderResponse getBatchOrder( }), }) @GetMapping("/orders/{orderId}/batches/{batchId}") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public BatchResponse getBatch( @Parameter(description = "Id of the order.", schema = @Schema(implementation = UUID.class), name = "orderId", example = "6c311d29-5753-46d4-b32c-19b918ea93b0") @Size(min = IrsAppConstants.JOB_ID_SIZE, @@ -294,7 +292,7 @@ public BatchResponse getBatch( }), }) @PutMapping("/orders/{orderId}") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public BatchOrderResponse cancelBatchOrder( @Parameter(description = "Id of the order.", schema = @Schema(implementation = UUID.class), name = "orderId", example = "6c311d29-5753-46d4-b32c-19b918ea93b0") @Size(min = IrsAppConstants.JOB_ID_SIZE, diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/IrsController.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/IrsController.java index a3fb4bea4c..2324ee45e5 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/IrsController.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/controllers/IrsController.java @@ -57,7 +57,6 @@ import org.eclipse.tractusx.irs.connector.job.IrsTimer; import org.eclipse.tractusx.irs.dtos.ErrorResponse; import org.eclipse.tractusx.irs.semanticshub.AspectModels; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; import org.eclipse.tractusx.irs.services.SemanticHubService; import org.eclipse.tractusx.irs.services.validation.SchemaNotFoundException; @@ -92,7 +91,6 @@ public class IrsController { private final IrsItemGraphQueryService itemJobService; private final SemanticHubService semanticHubService; - private final AuthorizationService authorizationService; @Operation(operationId = "registerJobForGlobalAssetId", summary = "Register an IRS job to retrieve an item graph for given {globalAssetId}.", @@ -128,7 +126,7 @@ public class IrsController { @IrsTimer("registerjob") @PostMapping("/jobs") @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public JobHandle registerJobForGlobalAssetId(final @Valid @RequestBody RegisterJob request) { return itemJobService.registerItemJob(request); } @@ -179,7 +177,7 @@ public JobHandle registerJobForGlobalAssetId(final @Valid @RequestBody RegisterJ }) @IrsTimer("getjob") @GetMapping("/jobs/{id}") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public ResponseEntity getJobById( @Parameter(description = "Id of the job.", schema = @Schema(implementation = UUID.class), name = "id", example = "6c311d29-5753-46d4-b32c-19b918ea93b0") @Size(min = IrsAppConstants.JOB_ID_SIZE, @@ -232,7 +230,7 @@ public ResponseEntity getJobById( }) @IrsTimer("canceljob") @PutMapping("/jobs/{id}") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public Job cancelJobByJobId( @Parameter(description = "Id of the job.", schema = @Schema(implementation = UUID.class), name = "id", example = "6c311d29-5753-46d4-b32c-19b918ea93b0") @Size(min = IrsAppConstants.JOB_ID_SIZE, @@ -274,7 +272,7 @@ public Job cancelJobByJobId( @IrsTimer("getjobbystate") @GetMapping("/jobs") @PageableAsQueryParam - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public PageResult getJobsByState( @Valid @ParameterObject @Parameter(description = "Requested job states.", in = QUERY, explode = Explode.FALSE, array = @ArraySchema(schema = @Schema(implementation = JobState.class), maxItems = Integer.MAX_VALUE)) @@ -308,7 +306,7 @@ public PageResult getJobsByState( }), }) @GetMapping("/aspectmodels") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public AspectModels getAllAvailableAspectModels() throws SchemaNotFoundException { return semanticHubService.getAllAspectModels(); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/EssController.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/EssController.java index 2ba3374983..04bb98e83e 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/EssController.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/EssController.java @@ -41,7 +41,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.irs.ess.service.EssService; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.component.JobHandle; import org.eclipse.tractusx.irs.component.Jobs; @@ -73,7 +72,6 @@ class EssController { private final EssService essService; - private final AuthorizationService authorizationService; @Operation(operationId = "registerBPNInvestigation", summary = "Registers an IRS job to start an investigation if a given bpn is contained in a part chain of a given globalAssetId.", @@ -108,7 +106,7 @@ class EssController { }) @PostMapping("/bpn/investigations") @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public JobHandle registerBPNInvestigation(final @Valid @RequestBody RegisterBpnInvestigationJob request) { return essService.startIrsJob(request); } @@ -151,7 +149,7 @@ public JobHandle registerBPNInvestigation(final @Valid @RequestBody RegisterBpnI }), }) @GetMapping("/bpn/investigations/{id}") - @PreAuthorize("@authorizationService.verifyBpn() && hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") + @PreAuthorize("hasAnyAuthority('" + IrsRoles.ADMIN_IRS + "', '" + IrsRoles.VIEW_IRS + "')") public Jobs getBPNInvestigation( @Parameter(description = "Id of the job.", schema = @Schema(implementation = UUID.class), name = "id", example = "6c311d29-5753-46d4-b32c-19b918ea93b0") @Valid @PathVariable final UUID id) { diff --git a/irs-api/src/main/resources/application.yml b/irs-api/src/main/resources/application.yml index 52f8cd87b1..4132ba837f 100644 --- a/irs-api/src/main/resources/application.yml +++ b/irs-api/src/main/resources/application.yml @@ -22,9 +22,7 @@ spring: token-uri: ${OAUTH2_CLIENT_TOKEN_URI:https://default} # OAuth2 endpoint to request tokens using the client credentials portal: token-uri: ${PORTAL_OAUTH2_CLIENT_TOKEN_URI:https://default} # OAuth2 endpoint to request tokens using the client credentials - resourceserver: - jwt: - jwk-set-uri: ${OAUTH2_JWK_SET_URI:https://default} # OAuth2 endpoint to request the JWK set + management: # Spring management API config, see https://spring.io/guides/gs/centralized-configuration/ endpoints: @@ -96,6 +94,11 @@ irs: # Application config completed: P7D # ISO 8601 Duration cron: expression: "*/10 * * * * ?" # Determines how often the number of stored jobs is updated in the metrics API. + security: + api: + keys: + admin: ${API_KEY_ADMIN} + regular: ${API_KEY_REGULAR} blobstore: endpoint: "${MINIO_URL}" # S3 compatible API endpoint (e.g. Minio) @@ -238,10 +241,3 @@ ess: mockEdcResult: { } # Mocked BPN Investigation results mockRecursiveEdcAsset: # Mocked BPN Recursive Investigation results -apiAllowedBpn: ${API_ALLOWED_BPN:BPNL00000001CRHK} # BPN value that is allowed to access IRS API - -# OAuth2 JWT token parse config. This configures the structure IRS expects when parsing the IRS role of an access token. -oauth: - resourceClaim: "resource_access" # Name of the JWT claim for roles - irsNamespace: "Cl20-CX-IRS" # Namespace for the IRS roles - roles: "roles" # Name of the list of roles within the IRS namespace diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java new file mode 100644 index 0000000000..ae20b160c0 --- /dev/null +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java @@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import jakarta.servlet.http.HttpServletRequest; +import org.eclipse.tractusx.irs.configuration.security.ApiKeyAuthentication; +import org.eclipse.tractusx.irs.configuration.security.ApiKeyAuthority; +import org.eclipse.tractusx.irs.configuration.security.AuthenticationService; +import org.eclipse.tractusx.irs.util.JsonUtil; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.authority.AuthorityUtils; + +public abstract class ControllerTest { + + @MockBean + protected AuthenticationService authenticationService; + + protected void authenticateWith(String... roles) { + when(authenticationService.getAuthentication(any(HttpServletRequest.class))) + .thenReturn(new ApiKeyAuthentication( + ApiKeyAuthority.of("123", AuthorityUtils.createAuthorityList(roles)))); + } + +} diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelperTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelperTest.java index 2aab79b058..531a42e8f6 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelperTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/HealthStatusHelperTest.java @@ -43,6 +43,6 @@ public static List healthStatusToNumeric() { @ParameterizedTest @MethodSource void healthStatusToNumeric(final Status status, final int numericStatus) { - assertThat(HealthStatusHelper.healthStatustoNumeric(status)).isEqualTo(numericStatus); + assertThat(HealthStatusHelper.healthStatusToNumeric(status)).isEqualTo(numericStatus); } } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverterTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverterTest.java deleted file mode 100644 index b79822fce1..0000000000 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/converter/JwtAuthenticationConverterTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021,2022,2023 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH AG - * Copyright (c) 2021,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.irs.configuration.converter; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.security.oauth2.jwt.JwtClaimNames.SUB; - -import java.time.Instant; -import java.util.List; -import java.util.Map; - -import com.nimbusds.jose.shaded.gson.internal.LinkedTreeMap; -import org.eclipse.tractusx.irs.common.auth.IrsRoles; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; - -class JwtAuthenticationConverterTest { - - private JwtAuthenticationConverter jwtAuthenticationConverter; - - @BeforeEach - void setUp() { - final String resourceAccessClaim = "resource_access"; - final String irsResourceAccess = "Cl20-CX-IRS"; - final String roles = "roles"; - jwtAuthenticationConverter = new JwtAuthenticationConverter(new JwtGrantedAuthoritiesConverter(), - new IrsTokenParser(resourceAccessClaim, irsResourceAccess, roles)); - } - - @Test - void shouldParseJwtTokenAndFindViewIrsRole() { - // given - final Map irsResourceAccess = new LinkedTreeMap<>(); - final Map irsRoles = new LinkedTreeMap<>(); - irsRoles.put("roles", List.of("view_irs")); - irsResourceAccess.put("Cl20-CX-IRS", irsRoles); - final Jwt jwt = jwt(irsResourceAccess); - - // when - final AbstractAuthenticationToken authenticationToken = jwtAuthenticationConverter.convert(jwt); - - // then - assertThat(authenticationToken).isNotNull(); - assertThat(authenticationToken.getAuthorities()).isNotNull(); - assertThat(authenticationToken.getAuthorities()).contains(new SimpleGrantedAuthority(IrsRoles.VIEW_IRS)); - } - - @Test - void shouldParseJwtTokenAndNotFindIrsRolesWhenWrongKey() { - // given - final Map irsResourceAccess = new LinkedTreeMap<>(); - final Map irsRoles = new LinkedTreeMap<>(); - irsRoles.put("roles", List.of()); - irsResourceAccess.put("Cl20-CX-IRS-WRONG-KEY", irsRoles); - final Jwt jwt = jwt(irsResourceAccess); - - // when - final AbstractAuthenticationToken authenticationToken = jwtAuthenticationConverter.convert(jwt); - - // then - assertThat(authenticationToken).isNotNull(); - assertThat(authenticationToken.getAuthorities()).isNotNull(); - assertThat(authenticationToken.getAuthorities()).isEmpty(); - } - - @Test - void shouldParseJwtTokenAndNotFindIrsRolesWhenWrongRolesKey() { - // given - final Map irsResourceAccess = new LinkedTreeMap<>(); - final Map irsRoles = new LinkedTreeMap<>(); - irsRoles.put("rolesWrong", List.of("view_irs")); - irsResourceAccess.put("Cl20-CX-IRS-WRONG-KEY", irsRoles); - final Jwt jwt = jwt(irsResourceAccess); - - // when - final AbstractAuthenticationToken authenticationToken = jwtAuthenticationConverter.convert(jwt); - - // then - assertThat(authenticationToken).isNotNull(); - assertThat(authenticationToken.getAuthorities()).isNotNull(); - assertThat(authenticationToken.getAuthorities()).isEmpty(); - } - - Jwt jwt(final Map irsResourceAccess) { - final Map claims = new LinkedTreeMap<>(); - claims.putAll(Map.of("resource_access", irsResourceAccess, SUB, "sub", "clientId", "clientId")); - - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(30), Map.of("alg", "none"), claims); - } -} \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java new file mode 100644 index 0000000000..57ee7e5223 --- /dev/null +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java @@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.configuration.security; + +import static org.junit.jupiter.api.Assertions.*; + +class ApiKeyAuthenticationFilterTest { + +} \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java index 2e1b5cef34..5f4af60059 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java @@ -23,6 +23,8 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.controllers; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.eclipse.tractusx.irs.util.TestMother.registerBatchOrder; import static org.eclipse.tractusx.irs.util.TestMother.registerBpnInvestigationBatchOrder; import static org.hamcrest.Matchers.containsString; @@ -36,12 +38,12 @@ import java.util.UUID; import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.tractusx.irs.ControllerTest; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.component.BatchOrderResponse; import org.eclipse.tractusx.irs.component.BatchResponse; import org.eclipse.tractusx.irs.component.RegisterBatchOrder; -import org.eclipse.tractusx.irs.configuration.SecurityConfiguration; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; +import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.services.CreationBatchService; import org.eclipse.tractusx.irs.services.QueryBatchService; import org.eclipse.tractusx.irs.services.timeouts.CancelBatchProcessingService; @@ -51,12 +53,12 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.access.AccessDeniedException; import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(BatchController.class) @Import(SecurityConfiguration.class) -class BatchControllerTest { +class BatchControllerTest extends ControllerTest { @Autowired private MockMvc mockMvc; @@ -70,21 +72,17 @@ class BatchControllerTest { @MockBean private CancelBatchProcessingService cancelBatchProcessingService; - @MockBean(name = "authorizationService") - private AuthorizationService authorizationService; - @Test - void shouldReturnUnauthorizedWhenAuthenticationIsMissing() throws Exception { - this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerBatchOrder("urn:uuid:4132cd2b-cbe7-4881-a6b4-39fdc31cca2b")))) - .andExpect(status().isUnauthorized()); + void shouldReturnUnauthorizedWhenAuthenticationIsMissing() { + assertThatThrownBy(() -> this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString( + registerBatchOrder("urn:uuid:4132cd2b-cbe7-4881-a6b4-39fdc31cca2b")))) + ).isInstanceOf(AccessDeniedException.class); } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturnBadRequestWhenGlobalAssetIdWithWrongFormat() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -93,9 +91,8 @@ void shouldReturnBadRequestWhenGlobalAssetIdWithWrongFormat() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturnBadRequestWhenBatchSizeNotMod10Compliant() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); final RegisterBatchOrder registerBatchOrder = registerBatchOrder("MALFORMED_GLOBAL_ASSET"); registerBatchOrder.setBatchSize(33); @@ -105,9 +102,8 @@ void shouldReturnBadRequestWhenBatchSizeNotMod10Compliant() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldRegisterRegularJobBatchOrder() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -116,9 +112,8 @@ void shouldRegisterRegularJobBatchOrder() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldRegisterEssJobBatchOrder() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); this.mockMvc.perform(post("/irs/ess/orders").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -127,9 +122,8 @@ void shouldRegisterEssJobBatchOrder() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturnBatchOrder() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); final UUID orderId = UUID.randomUUID(); when(queryBatchService.findOrderById(orderId)).thenReturn(BatchOrderResponse.builder().orderId(orderId).build()); @@ -140,11 +134,11 @@ void shouldReturnBatchOrder() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturnBatch() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final UUID orderId = UUID.randomUUID(); final UUID batchId = UUID.randomUUID(); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); when(queryBatchService.findBatchById(orderId, batchId)).thenReturn( BatchResponse.builder().batchId(batchId).orderId(orderId).build()); @@ -155,9 +149,8 @@ void shouldReturnBatch() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldCancelBatchOrder() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); final UUID orderId = UUID.randomUUID(); when(queryBatchService.findOrderById(orderId)).thenReturn(BatchOrderResponse.builder().orderId(orderId).build()); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java index d266e5ad84..d175fdf001 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java @@ -24,6 +24,8 @@ package org.eclipse.tractusx.irs.controllers; import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.eclipse.tractusx.irs.util.TestMother.registerBatchOrder; import static org.eclipse.tractusx.irs.util.TestMother.registerJob; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithDepthAndAspect; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithUrl; @@ -49,6 +51,9 @@ import java.util.stream.Stream; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import org.eclipse.tractusx.irs.ControllerTest; +import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.component.Job; import org.eclipse.tractusx.irs.component.JobHandle; import org.eclipse.tractusx.irs.component.JobStatusResult; @@ -57,10 +62,9 @@ import org.eclipse.tractusx.irs.component.RegisterJob; import org.eclipse.tractusx.irs.component.enums.Direction; import org.eclipse.tractusx.irs.component.enums.JobState; -import org.eclipse.tractusx.irs.configuration.SecurityConfiguration; +import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.semanticshub.AspectModel; import org.eclipse.tractusx.irs.semanticshub.AspectModels; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; import org.eclipse.tractusx.irs.services.SemanticHubService; import org.junit.jupiter.api.Test; @@ -73,13 +77,14 @@ import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.server.ResponseStatusException; @WebMvcTest(IrsController.class) @Import(SecurityConfiguration.class) -class IrsControllerTest { +class IrsControllerTest extends ControllerTest { private final UUID jobId = UUID.randomUUID(); @@ -92,8 +97,6 @@ class IrsControllerTest { private IrsItemGraphQueryService service; @MockBean private SemanticHubService semanticHubService; - @MockBean(name = "authorizationService") - private AuthorizationService authorizationService; private static Stream corruptedJobs() { return Stream.of(registerJobWithDepthAndAspect(110, null), @@ -103,11 +106,12 @@ private static Stream corruptedJobs() { } @Test - @WithMockUser(authorities = "view_irs") void initiateJobForGlobalAssetId() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final UUID returnedJob = UUID.randomUUID(); when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build()); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -117,26 +121,19 @@ void initiateJobForGlobalAssetId() throws Exception { } @Test - void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() throws Exception { - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().isUnauthorized()); + void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() { + when(authenticationService.getAuthentication(any(HttpServletRequest.class))) + .thenThrow(new BadCredentialsException("Wrong ApiKey")); + + assertThatThrownBy(() -> this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString( + registerJobWithoutDepthAndAspect()))) + ).isInstanceOf(AccessDeniedException.class); } @Test - @WithMockUser(authorities = "view_irs_wrong_authority") void shouldReturnForbiddenStatusWhenRequiredAuthorityIsMissing() throws Exception { - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().isForbidden()); - } - - @Test - @WithMockUser(authorities = "view_irs") - void shouldReturnForbiddenStatusWhenWrongBpnInJwtToken() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.FALSE); + authenticateWith("view_irs_wrong_authority"); this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -146,16 +143,18 @@ void shouldReturnForbiddenStatusWhenWrongBpnInJwtToken() throws Exception { @ParameterizedTest @MethodSource("corruptedJobs") - @WithMockUser(authorities = "view_irs") void shouldReturnBadRequestWhenRegisterJobBodyNotValid(final RegisterJob registerJob) throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString(registerJob))) .andExpect(status().isBadRequest()); } @Test - @WithMockUser(authorities = "view_irs") void shouldReturnBadRequestWhenRegisterJobHasWrongCallbackUrl() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( registerJobWithUrl("hhh://example.com")))) @@ -163,11 +162,11 @@ void shouldReturnBadRequestWhenRegisterJobHasWrongCallbackUrl() throws Exception } @Test - @WithMockUser(authorities = "view_irs") void shouldAcceptCorrectCallbackUrl() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final UUID returnedJob = UUID.randomUUID(); when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build()); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -176,8 +175,9 @@ void shouldAcceptCorrectCallbackUrl() throws Exception { } @Test - @WithMockUser(authorities = "view_irs") void getJobsByState() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final JobStatusResult returnedJob = JobStatusResult.builder() .id(UUID.randomUUID()) .state(JobState.COMPLETED) @@ -187,7 +187,6 @@ void getJobsByState() throws Exception { final String returnJobAsString = objectMapper.writeValueAsString(returnedJob); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); when(service.getJobsByState(any(), any())).thenReturn( new PageResult(new PagedListHolder<>(List.of(returnedJob)))); @@ -205,20 +204,19 @@ void getJobsByState() throws Exception { } @Test - @WithMockUser(authorities = "view_irs") void cancelJobById() throws Exception { - final Job canceledJob = Job.builder().id(jobId).state(JobState.CANCELED).build(); + authenticateWith(IrsRoles.VIEW_IRS); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + final Job canceledJob = Job.builder().id(jobId).state(JobState.CANCELED).build(); when(this.service.cancelJobById(jobId)).thenReturn(canceledJob); this.mockMvc.perform(put("/irs/jobs/" + jobId)).andExpect(status().isOk()); } @Test - @WithMockUser(authorities = "view_irs") void cancelJobById_throwEntityNotFoundException() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); + given(this.service.cancelJobById(jobId)).willThrow( new ResponseStatusException(HttpStatus.NOT_FOUND, "No job exists with id " + jobId)); @@ -228,18 +226,19 @@ void cancelJobById_throwEntityNotFoundException() throws Exception { } @Test - @WithMockUser(authorities = "view_irs") void getJobWithMalformedIdShouldReturnBadRequest() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final String jobIdMalformed = UUID.randomUUID() + "MALFORMED"; this.mockMvc.perform(get("/irs/jobs/" + jobIdMalformed)).andExpect(status().isBadRequest()); } @Test - @WithMockUser(authorities = "view_irs") void shouldReturnBadRequestWhenRegisterJobWithMalformedAspectJson() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(service.registerItemJob(any())).thenThrow(IllegalArgumentException.class); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); final String requestBody = "{ \"aspects\": [ \"MALFORMED\" ], \"globalAssetId\": \"urn:uuid:8a61c8db-561e-4db0-84ec-a693fc5ffdf6\" }"; this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON).content(requestBody)) @@ -247,9 +246,9 @@ void shouldReturnBadRequestWhenRegisterJobWithMalformedAspectJson() throws Excep } @Test - @WithMockUser(authorities = "view_irs") void shouldReturnBadRequestWhenCancelingAlreadyCompletedJob() throws Exception { - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); + authenticateWith(IrsRoles.VIEW_IRS); + given(this.service.cancelJobById(jobId)).willThrow(new IllegalStateException( format("Cannot transition from state %s to %s", JobState.COMPLETED, JobState.CANCELED))); @@ -259,8 +258,9 @@ void shouldReturnBadRequestWhenCancelingAlreadyCompletedJob() throws Exception { } @Test - @WithMockUser(authorities = "view_irs") void shouldReturnAspectModels() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final AspectModel assemblyPartRelationship = AspectModel.builder() .name("AssemblyPartRelationship") .urn("urn:bamm:io.catenax.assembly_part_relationship:1.1.1#AssemblyPartRelationship") @@ -274,7 +274,6 @@ void shouldReturnAspectModels() throws Exception { .models(List.of(assemblyPartRelationship)) .build(); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); given(this.semanticHubService.getAllAspectModels()).willReturn(aspectModels); final String aspectModelResponseAsString = objectMapper.writeValueAsString(aspectModels); @@ -284,8 +283,9 @@ void shouldReturnAspectModels() throws Exception { } @Test - @WithMockUser(authorities = "view_irs_wrong_authority") void shouldReturnForbiddenStatusForAspectModelsWhenRequiredAuthorityIsMissing() throws Exception { + authenticateWith("view_irs_wrong_authority"); + this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( registerJobWithoutDepthAndAspect()))) @@ -293,13 +293,13 @@ void shouldReturnForbiddenStatusForAspectModelsWhenRequiredAuthorityIsMissing() } @Test - @WithMockUser(authorities = "view_irs") void shouldReturnPartialWhenJobCompleted() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final Jobs runningJob = Jobs.builder().job(Job.builder().id(jobId).state(JobState.RUNNING).build()).build(); final boolean shouldIncludePartial = Boolean.TRUE; final boolean shouldNotIncludePartial = Boolean.FALSE; - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(runningJob); this.mockMvc.perform(get("/irs/jobs/" + jobId).queryParam("returnUncompletedJob", String.valueOf(shouldIncludePartial))).andExpect(status().isPartialContent()); @@ -307,13 +307,13 @@ void shouldReturnPartialWhenJobCompleted() throws Exception { } @Test - @WithMockUser(authorities = "view_irs") void shouldReturnOkWhenJobCompleted() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final Jobs completedJob = Jobs.builder().job(Job.builder().id(jobId).state(JobState.COMPLETED).build()).build(); final boolean shouldIncludePartial = Boolean.TRUE; final boolean shouldNotIncludePartial = Boolean.FALSE; - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(completedJob); this.mockMvc.perform(get("/irs/jobs/" + jobId).queryParam("returnUncompletedJob", String.valueOf(shouldIncludePartial))).andExpect(status().isOk()); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index 59f061716c..8287dc8d6f 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -32,9 +32,9 @@ import static org.springframework.web.client.HttpServerErrorException.InternalServerError; import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.tractusx.irs.ControllerTest; import org.eclipse.tractusx.irs.common.auth.IrsRoles; -import org.eclipse.tractusx.irs.configuration.SecurityConfiguration; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; +import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; import org.eclipse.tractusx.irs.services.SemanticHubService; import org.junit.jupiter.api.Test; @@ -44,29 +44,26 @@ import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; @WebMvcTest(IrsController.class) @Import(SecurityConfiguration.class) -class IrsExceptionHandlerTest { +class IrsExceptionHandlerTest extends ControllerTest { @MockBean private IrsItemGraphQueryService service; @MockBean private SemanticHubService semanticHubService; - @MockBean(name = "authorizationService") - private AuthorizationService authorizationService; @Autowired private MockMvc mockMvc; @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void handleAll() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(service.registerItemJob(any())).thenThrow(InternalServerError.class); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -75,10 +72,10 @@ void handleAll() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturn500WhenGetSemanticModelsFails() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -87,10 +84,10 @@ void shouldReturn500WhenGetSemanticModelsFails() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturn400WhenProvidingBadInput() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -99,10 +96,10 @@ void shouldReturn400WhenProvidingBadInput() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturn400WhenCatchingIllegalStateException() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -111,10 +108,10 @@ void shouldReturn400WhenCatchingIllegalStateException() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); - when(authorizationService.verifyBpn()).thenReturn(Boolean.TRUE); this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( @@ -123,8 +120,9 @@ void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exc } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturn403WhenRightsAreMissing() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssControllerTest.java index fd34ee0585..192f6600f5 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssControllerTest.java @@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -34,23 +33,25 @@ import java.util.UUID; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.tractusx.irs.ess.service.EssService; -import org.eclipse.tractusx.irs.common.auth.AuthorizationService; +import org.eclipse.tractusx.irs.ControllerTest; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.component.JobHandle; import org.eclipse.tractusx.irs.component.Jobs; import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.RegisterBpnInvestigationJob; +import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; +import org.eclipse.tractusx.irs.ess.service.EssService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(EssController.class) -class EssControllerTest { +@Import(SecurityConfiguration.class) +class EssControllerTest extends ControllerTest { @Autowired private MockMvc mockMvc; @@ -58,28 +59,26 @@ class EssControllerTest { @MockBean private EssService essService; - @MockBean(name = "authorizationService") - private AuthorizationService authorizationService; - private final String path = "/ess/bpn/investigations"; private final String globalAssetId = "urn:uuid:d3c0bf85-d44f-47c5-990d-fec8a36065c6"; private final String bpn = "BPNS000000000DDD"; @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldRegisterBpnInvestigationForValidRequest() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + when(essService.startIrsJob(any(RegisterBpnInvestigationJob.class))).thenReturn( JobHandle.builder().id(UUID.randomUUID()).build()); - this.mockMvc.perform(post(path).with(csrf()) - .contentType(MediaType.APPLICATION_JSON) + this.mockMvc.perform(post(path).contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( reqBody(globalAssetId, List.of(bpn))))).andExpect(status().isCreated()); } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldGetJob() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + final String jobId = UUID.randomUUID().toString(); when(essService.getIrsJob(jobId)).thenReturn(Jobs.builder().build()); @@ -87,20 +86,20 @@ void shouldGetJob() throws Exception { } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturnBadRequestForWrongGlobalAssetId() throws Exception { - this.mockMvc.perform(post(path).with(csrf()) - .contentType(MediaType.APPLICATION_JSON) + authenticateWith(IrsRoles.VIEW_IRS); + + this.mockMvc.perform(post(path).contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( reqBody("wrongGlobalAssetId", List.of(bpn))))) .andExpect(status().isBadRequest()); } @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldReturnBadRequestForWrongBpn() throws Exception { - this.mockMvc.perform(post(path).with(csrf()) - .contentType(MediaType.APPLICATION_JSON) + authenticateWith(IrsRoles.VIEW_IRS); + + this.mockMvc.perform(post(path).contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString( reqBody(globalAssetId, List.of(bpn, "WRONG_BPN"))))) .andExpect(status().isBadRequest()); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java index fa74452107..7d08cde90f 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java @@ -23,28 +23,30 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.ess.controller; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.tractusx.irs.ess.service.EssRecursiveService; +import org.eclipse.tractusx.irs.ControllerTest; import org.eclipse.tractusx.irs.common.auth.IrsRoles; +import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationHeader; import org.eclipse.tractusx.irs.edc.client.model.notification.InvestigationNotificationContent; +import org.eclipse.tractusx.irs.ess.service.EssRecursiveService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(EssRecursiveController.class) -class EssRecursiveControllerTest { +@Import(SecurityConfiguration.class) +class EssRecursiveControllerTest extends ControllerTest { private final String path = "/ess/notification/receive-recursive"; @@ -55,11 +57,10 @@ class EssRecursiveControllerTest { private EssRecursiveService essRecursiveService; @Test - @WithMockUser(authorities = IrsRoles.VIEW_IRS) void shouldHandleRecursiveBpnInvestigationByNotification() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); - this.mockMvc.perform(post(path).with(csrf()) - .contentType(MediaType.APPLICATION_JSON) + this.mockMvc.perform(post(path).contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString(prepareNotification()))) .andExpect(status().isCreated()); } diff --git a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/AuthorizationServiceTest.java b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/AuthorizationServiceTest.java deleted file mode 100644 index 1cc89800f7..0000000000 --- a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/AuthorizationServiceTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021,2022,2023 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH AG - * Copyright (c) 2021,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.irs.common.auth; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.springframework.security.oauth2.jwt.JwtClaimNames.SUB; - -import java.time.Instant; -import java.util.Map; - -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; - -class AuthorizationServiceTest { - - @Test - void shouldReturnTrueWhenTokenBpnIsEqualToAllowedBpn() { - // given - final String BPN = "BPNL00000001CRHK"; - final Map claims = Map.of(SUB, "sub", "clientId", "clientId", "bpn", BPN); - thereIsJwtAuthenticationWithClaims(claims); - final AuthorizationService authorizationService = new AuthorizationService(BPN); - - // when - final Boolean isBpnAllowed = authorizationService.verifyBpn(); - - // then - assertThat(isBpnAllowed).isEqualTo(Boolean.TRUE); - } - - @Test - void shouldReturnFalseWhenTokenBpnIsDifferentThanAllowedBpn() { - // given - final String claimBPN = "BPNL00000003CRHK"; - final String configurationBPN = "BPNL00000003CML1"; - final Map claims = Map.of(SUB, "sub", "clientId", "clientId", "bpn", claimBPN); - thereIsJwtAuthenticationWithClaims(claims); - final AuthorizationService authorizationService = new AuthorizationService(configurationBPN); - - // when - final Boolean isBpnAllowed = authorizationService.verifyBpn(); - - // then - assertThat(isBpnAllowed).isEqualTo(Boolean.FALSE); - } - - @Test - void shouldReturnFalseWhenNotAllowedBpnConfigured() { - // given - final String emptyConfigurationBPN = ""; - final AuthorizationService authorizationService = new AuthorizationService(emptyConfigurationBPN); - - // when - final Boolean isBpnAllowed = authorizationService.verifyBpn(); - - // then - assertThat(isBpnAllowed).isEqualTo(Boolean.FALSE); - } - - @Test - void shouldReturnFalseTokenBpnIsMissing() { - // given - final String configurationBPN = "BPNL00000003CML1"; - final Map claims = Map.of(SUB, "sub", "clientId", "clientId"); - thereIsJwtAuthenticationWithClaims(claims); - final AuthorizationService authorizationService = new AuthorizationService(configurationBPN); - - // when - final Boolean isBpnAllowed = authorizationService.verifyBpn(); - - // then - assertThat(isBpnAllowed).isEqualTo(Boolean.FALSE); - } - - private void thereIsJwtAuthenticationWithClaims(final Map claims) { - final JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(jwt(claims)); - SecurityContext securityContext = mock(SecurityContext.class); - Mockito.when(securityContext.getAuthentication()).thenReturn(jwtAuthenticationToken); - SecurityContextHolder.setContext(securityContext); - } - - Jwt jwt(final Map claims) { - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(30), Map.of("alg", "none"), claims); - } - -} diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java index efad6f94d8..ad18b47f6a 100644 --- a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java @@ -99,7 +99,7 @@ public class PolicyStoreController { }) @PostMapping("/policies") @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize("@authorizationService.verifyBpn() && hasAuthority('" + IrsRoles.ADMIN_IRS + "')") + @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") public void registerAllowedPolicy(final @Valid @RequestBody CreatePolicyRequest request) { service.registerPolicy(request); } @@ -128,7 +128,7 @@ public void registerAllowedPolicy(final @Valid @RequestBody CreatePolicyRequest }) @GetMapping("/policies") @ResponseStatus(HttpStatus.OK) - @PreAuthorize("@authorizationService.verifyBpn() && hasAuthority('" + IrsRoles.ADMIN_IRS + "')") + @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") public List getPolicies() { return service.getStoredPolicies(); } @@ -160,7 +160,7 @@ public List getPolicies() { }) @DeleteMapping("/policies/{policyId}") @ResponseStatus(HttpStatus.OK) - @PreAuthorize("@authorizationService.verifyBpn() && hasAuthority('" + IrsRoles.ADMIN_IRS + "')") + @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") public void deleteAllowedPolicy(@PathVariable("policyId") final String policyId) { service.deletePolicy(policyId); } @@ -191,7 +191,7 @@ public void deleteAllowedPolicy(@PathVariable("policyId") final String policyId) }) @PutMapping("/policies/{policyId}") @ResponseStatus(HttpStatus.OK) - @PreAuthorize("@authorizationService.verifyBpn() && hasAuthority('" + IrsRoles.ADMIN_IRS + "')") + @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") public void updateAllowedPolicy(@PathVariable("policyId") final String policyId, final @Valid @RequestBody UpdatePolicyRequest request) { service.updatePolicy(policyId, request); From 4896a5382c9f2ab01d9426452833eddc0f636e6d Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 10:30:57 +0100 Subject: [PATCH 15/59] feat(impl):[#259] update changelog and spotbug --- CHANGELOG.md | 8 ++++++-- irs-api/pom.xml | 4 ---- .../configuration/security/ApiKeyAuthentication.java | 6 +++--- .../irs/configuration/security/ApiKeyAuthority.java | 11 ++++++++--- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f02488d510..3437d8cb38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] - ### Added - - Added cache mechanism in DiscoveryFinderClientImpl for findDiscoveryEndpoints +### Changed +- Authentication was redesigned to use API keys, instead of OAuth2 protocol. The api key has to be sent as a X-API-KEY request header. IRS is supporting two types of API keys - one for admin and one for regular/view usage. Use new ``apiKeyAdmin`` and ``apiKeyRegular`` config entries to set up API keys. + +### Removed +- Removed ``oauth.resourceClaim``, ``oauth.irsNamespace``,``oauth.roles``,``oauth2.jwkSetUri`` config entries + ## [4.3.0] - 2023-12-08 ### Added - Added support for `hasAlternatives` property in SingleLevelBomAsBuilt aspect diff --git a/irs-api/pom.xml b/irs-api/pom.xml index 2f2f9eaffa..fef1c4530f 100644 --- a/irs-api/pom.xml +++ b/irs-api/pom.xml @@ -92,10 +92,6 @@ org.springframework.boot spring-boot-starter-log4j2 - - org.springframework.boot - spring-boot-starter-oauth2-resource-server - org.springframework.boot spring-boot-starter-oauth2-client diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java index 7584d033c8..ec7db45d07 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java @@ -33,18 +33,18 @@ public class ApiKeyAuthentication extends AbstractAuthenticationToken { private final ApiKeyAuthority apiKeyAuthority; public ApiKeyAuthentication(final ApiKeyAuthority apiKeyAuthority) { - super(apiKeyAuthority.authorities()); + super(apiKeyAuthority.getAuthorities()); this.apiKeyAuthority = apiKeyAuthority; setAuthenticated(true); } @Override public Object getCredentials() { - return apiKeyAuthority.apiKey(); + return apiKeyAuthority.getApiKey(); } @Override public Object getPrincipal() { - return apiKeyAuthority.apiKey(); + return apiKeyAuthority.getApiKey(); } } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java index 6b61ab6047..e20fe04b92 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthority.java @@ -23,15 +23,20 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.configuration.security; +import java.io.Serializable; import java.util.List; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.springframework.security.core.GrantedAuthority; /** - * @param apiKey - * @param authorities */ -public record ApiKeyAuthority(String apiKey, List authorities) { +@RequiredArgsConstructor +@Getter +public class ApiKeyAuthority implements Serializable { + private final String apiKey; + private final List authorities; @SuppressWarnings("PMD.ShortMethodName") public static ApiKeyAuthority of(final String apiKey, final List authorities) { From 5a7a9a7375e09e526296f6d24984f76c5b1b1434 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 11:11:05 +0100 Subject: [PATCH 16/59] feat(impl):[#259] fix tests --- irs-api/src/main/resources/application-local.yml | 8 +++++--- .../tractusx/irs/ConnectorEndpointServiceTest.java | 2 +- .../eclipse/tractusx/irs/DiscoveryFinderClientTest.java | 2 +- .../semanticshub/SemanticHubCacheInitializerTests.java | 2 +- .../services/IrsItemGraphQueryServiceSpringBootTest.java | 4 +--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/irs-api/src/main/resources/application-local.yml b/irs-api/src/main/resources/application-local.yml index edf68dcfce..ecf0b3c1cd 100644 --- a/irs-api/src/main/resources/application-local.yml +++ b/irs-api/src/main/resources/application-local.yml @@ -21,13 +21,15 @@ irs: ttl: failed: PT1H completed: PT1H + security: + api: + keys: + admin: 01234567890123456789 + regular: 09876543210987654321 spring: security: oauth2: - resourceserver: - jwt: - jwk-set-uri: https://localhost client: provider: common: diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ConnectorEndpointServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ConnectorEndpointServiceTest.java index ce1d478bd1..048790dbb6 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ConnectorEndpointServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ConnectorEndpointServiceTest.java @@ -38,7 +38,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "digitalTwinRegistry.type=central" }) -@ActiveProfiles(profiles = "test") +@ActiveProfiles(profiles = { "test", "local" }) @Import(TestConfig.class) @ExtendWith({ MockitoExtension.class, SpringExtension.class diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/DiscoveryFinderClientTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/DiscoveryFinderClientTest.java index d2a64c674a..245e7c8c23 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/DiscoveryFinderClientTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/DiscoveryFinderClientTest.java @@ -52,7 +52,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = "irs-edc-client.discoveryFinderClient.cacheTTL=PT0.1S") -@ActiveProfiles(profiles = "test") +@ActiveProfiles(profiles = { "test", "local" }) @Import({ TestConfig.class }) class DiscoveryFinderClientTest { diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/semanticshub/SemanticHubCacheInitializerTests.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/semanticshub/SemanticHubCacheInitializerTests.java index a340d91474..23c25e2635 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/semanticshub/SemanticHubCacheInitializerTests.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/semanticshub/SemanticHubCacheInitializerTests.java @@ -39,7 +39,7 @@ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @Import(TestConfig.class) -@ActiveProfiles(profiles = { "test" }) +@ActiveProfiles(profiles = { "test", "local" }) class SemanticHubCacheInitializerTests { @Autowired diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java index c486c57a80..ce4358be40 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java @@ -80,9 +80,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "digitalTwinRegistry.type=central" }) -@ActiveProfiles(profiles = { "test", - "stubtest" -}) +@ActiveProfiles(profiles = { "test", "stubtest", "local" }) @Import(TestConfig.class) class IrsItemGraphQueryServiceSpringBootTest { From 9c49bca65d00e60bfd3910b67c0b4bc20ff9ba64 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 11:35:11 +0100 Subject: [PATCH 17/59] feat(impl):[#259] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3437d8cb38..4cef97d594 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Authentication was redesigned to use API keys, instead of OAuth2 protocol. The api key has to be sent as a X-API-KEY request header. IRS is supporting two types of API keys - one for admin and one for regular/view usage. Use new ``apiKeyAdmin`` and ``apiKeyRegular`` config entries to set up API keys. ### Removed -- Removed ``oauth.resourceClaim``, ``oauth.irsNamespace``,``oauth.roles``,``oauth2.jwkSetUri`` config entries +- Removed ``oauth.resourceClaim``, ``oauth.irsNamespace``,``oauth.roles``,``oauth2.jwkSetUri``,``bpn`` config entries ## [4.3.0] - 2023-12-08 ### Added From c71698b6a96e55aea5c819a5c228aeb657070673 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 11:55:09 +0100 Subject: [PATCH 18/59] feat(impl):[#259] fix test --- .../controllers/IrsExceptionHandlerTest.java | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index 8287dc8d6f..4d3ea008b1 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -77,9 +77,7 @@ void shouldReturn500WhenGetSemanticModelsFails() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); - this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) + this.mockMvc.perform(get("/irs/aspectmodels")) .andExpect(status().is5xxServerError()); } @@ -89,9 +87,7 @@ void shouldReturn400WhenProvidingBadInput() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); - this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) + this.mockMvc.perform(get("/irs/aspectmodels")) .andExpect(status().isBadRequest()); } @@ -101,9 +97,7 @@ void shouldReturn400WhenCatchingIllegalStateException() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); - this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) + this.mockMvc.perform(get("/irs/aspectmodels")) .andExpect(status().isBadRequest()); } @@ -113,9 +107,7 @@ void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exc when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); - this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) + this.mockMvc.perform(get("/irs/aspectmodels")) .andExpect(status().isBadRequest()); } @@ -125,9 +117,7 @@ void shouldReturn403WhenRightsAreMissing() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); - this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) + this.mockMvc.perform(get("/irs/aspectmodels")) .andExpect(status().isForbidden()); } } \ No newline at end of file From 849ce618da37aaa007627ea6efc9c1f2c6247f09 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 12:53:57 +0100 Subject: [PATCH 19/59] feat(impl):[#259] fix tests --- .../security/ApiKeyAuthenticationFilter.java | 3 +-- .../security/SecurityConfiguration.java | 2 -- .../eclipse/tractusx/irs/ControllerTest.java | 1 - .../irs/controllers/BatchControllerTest.java | 19 +++++++++++-------- .../irs/controllers/IrsControllerTest.java | 13 +++++-------- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java index 484254e393..5ec2714cb0 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilter.java @@ -56,11 +56,10 @@ protected void doFilterInternal(final HttpServletRequest request, final HttpServ try { final Authentication authentication = authenticationService.getAuthentication(request); SecurityContextHolder.getContext().setAuthentication(authentication); + filterChain.doFilter(request, response); } catch (final BadCredentialsException exception) { unauthorizedResponse(response, exception); } - - filterChain.doFilter(request, response); } private void unauthorizedResponse(final HttpServletResponse servletResponse, final Exception exception) throws IOException { diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java index 432fce53fa..ef317f7bcf 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/SecurityConfiguration.java @@ -114,8 +114,6 @@ public class SecurityConfiguration { httpSecurity.addFilterBefore(new IgnoreWhitelistedPathFilter(new ApiKeyAuthenticationFilter(authenticationService, new JsonUtil())), UsernamePasswordAuthenticationFilter.class); - httpSecurity.exceptionHandling(AbstractHttpConfigurer::disable); - return httpSecurity.build(); } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java index ae20b160c0..a4b52a282b 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ControllerTest.java @@ -30,7 +30,6 @@ import org.eclipse.tractusx.irs.configuration.security.ApiKeyAuthentication; import org.eclipse.tractusx.irs.configuration.security.ApiKeyAuthority; import org.eclipse.tractusx.irs.configuration.security.AuthenticationService; -import org.eclipse.tractusx.irs.util.JsonUtil; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.core.authority.AuthorityUtils; diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java index 5f4af60059..380c694096 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/BatchControllerTest.java @@ -23,11 +23,10 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.controllers; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.eclipse.tractusx.irs.util.TestMother.registerBatchOrder; import static org.eclipse.tractusx.irs.util.TestMother.registerBpnInvestigationBatchOrder; import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -38,6 +37,7 @@ import java.util.UUID; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; import org.eclipse.tractusx.irs.ControllerTest; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.component.BatchOrderResponse; @@ -53,7 +53,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; -import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(BatchController.class) @@ -73,11 +73,14 @@ class BatchControllerTest extends ControllerTest { private CancelBatchProcessingService cancelBatchProcessingService; @Test - void shouldReturnUnauthorizedWhenAuthenticationIsMissing() { - assertThatThrownBy(() -> this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerBatchOrder("urn:uuid:4132cd2b-cbe7-4881-a6b4-39fdc31cca2b")))) - ).isInstanceOf(AccessDeniedException.class); + void shouldReturnUnauthorizedWhenAuthenticationIsMissing() throws Exception { + when(authenticationService.getAuthentication(any(HttpServletRequest.class))) + .thenThrow(new BadCredentialsException("Wrong ApiKey")); + + this.mockMvc.perform(post("/irs/orders").contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString( + registerBatchOrder("urn:uuid:4132cd2b-cbe7-4881-a6b4-39fdc31cca2b")))) + .andExpect(status().isUnauthorized()); } @Test diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java index d175fdf001..dc8510cee1 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java @@ -24,8 +24,6 @@ package org.eclipse.tractusx.irs.controllers; import static java.lang.String.format; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.eclipse.tractusx.irs.util.TestMother.registerBatchOrder; import static org.eclipse.tractusx.irs.util.TestMother.registerJob; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithDepthAndAspect; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithUrl; @@ -77,7 +75,6 @@ import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.server.ResponseStatusException; @@ -121,14 +118,14 @@ void initiateJobForGlobalAssetId() throws Exception { } @Test - void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() { + void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() throws Exception { when(authenticationService.getAuthentication(any(HttpServletRequest.class))) .thenThrow(new BadCredentialsException("Wrong ApiKey")); - assertThatThrownBy(() -> this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - ).isInstanceOf(AccessDeniedException.class); + this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString( + registerJobWithoutDepthAndAspect()))) + .andExpect(status().isUnauthorized()); } @Test From a6ef420be8bf423488a066d3eab8034c747b35e7 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 13:12:28 +0100 Subject: [PATCH 20/59] feat(impl):[#259] fix tests --- .../controllers/IrsExceptionHandlerTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index 4d3ea008b1..c684bcc671 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -71,15 +71,15 @@ void handleAll() throws Exception { .andExpect(status().is5xxServerError()); } - @Test - void shouldReturn500WhenGetSemanticModelsFails() throws Exception { - authenticateWith(IrsRoles.VIEW_IRS); - - when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); - - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().is5xxServerError()); - } +// @Test +// void shouldReturn500WhenGetSemanticModelsFails() throws Exception { +// authenticateWith(IrsRoles.VIEW_IRS); +// +// when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); +// +// this.mockMvc.perform(get("/irs/aspectmodels")) +// .andExpect(status().is5xxServerError()); +// } @Test void shouldReturn400WhenProvidingBadInput() throws Exception { From 464f7e954761d681d59e65e978c7f381abb64306 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 13:26:56 +0100 Subject: [PATCH 21/59] feat(impl):[#259] fix tests --- .../controllers/IrsExceptionHandlerTest.java | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index c684bcc671..fa4dc83453 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -59,65 +59,65 @@ class IrsExceptionHandlerTest extends ControllerTest { @Autowired private MockMvc mockMvc; - @Test - void handleAll() throws Exception { - authenticateWith(IrsRoles.VIEW_IRS); - - when(service.registerItemJob(any())).thenThrow(InternalServerError.class); - - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().is5xxServerError()); - } - // @Test -// void shouldReturn500WhenGetSemanticModelsFails() throws Exception { +// void handleAll() throws Exception { // authenticateWith(IrsRoles.VIEW_IRS); // -// when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); +// when(service.registerItemJob(any())).thenThrow(InternalServerError.class); // -// this.mockMvc.perform(get("/irs/aspectmodels")) +// this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) +// .content(new ObjectMapper().writeValueAsString( +// registerJobWithoutDepthAndAspect()))) // .andExpect(status().is5xxServerError()); // } - - @Test - void shouldReturn400WhenProvidingBadInput() throws Exception { - authenticateWith(IrsRoles.VIEW_IRS); - - when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); - - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isBadRequest()); - } - - @Test - void shouldReturn400WhenCatchingIllegalStateException() throws Exception { - authenticateWith(IrsRoles.VIEW_IRS); - - when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); - - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isBadRequest()); - } - - @Test - void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exception { - authenticateWith(IrsRoles.VIEW_IRS); - - when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); - - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isBadRequest()); - } - - @Test - void shouldReturn403WhenRightsAreMissing() throws Exception { - authenticateWith(IrsRoles.VIEW_IRS); - - when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); - - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isForbidden()); - } +// +//// @Test +//// void shouldReturn500WhenGetSemanticModelsFails() throws Exception { +//// authenticateWith(IrsRoles.VIEW_IRS); +//// +//// when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); +//// +//// this.mockMvc.perform(get("/irs/aspectmodels")) +//// .andExpect(status().is5xxServerError()); +//// } +// +// @Test +// void shouldReturn400WhenProvidingBadInput() throws Exception { +// authenticateWith(IrsRoles.VIEW_IRS); +// +// when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); +// +// this.mockMvc.perform(get("/irs/aspectmodels")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void shouldReturn400WhenCatchingIllegalStateException() throws Exception { +// authenticateWith(IrsRoles.VIEW_IRS); +// +// when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); +// +// this.mockMvc.perform(get("/irs/aspectmodels")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exception { +// authenticateWith(IrsRoles.VIEW_IRS); +// +// when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); +// +// this.mockMvc.perform(get("/irs/aspectmodels")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void shouldReturn403WhenRightsAreMissing() throws Exception { +// authenticateWith(IrsRoles.VIEW_IRS); +// +// when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); +// +// this.mockMvc.perform(get("/irs/aspectmodels")) +// .andExpect(status().isForbidden()); +// } } \ No newline at end of file From e2e57a5ea0a73249b2d8bc4c1dd098a959e70d52 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 13:56:30 +0100 Subject: [PATCH 22/59] feat(impl):[#259] great --- .../controllers/IrsExceptionHandlerTest.java | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index fa4dc83453..4d3ea008b1 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -59,65 +59,65 @@ class IrsExceptionHandlerTest extends ControllerTest { @Autowired private MockMvc mockMvc; -// @Test -// void handleAll() throws Exception { -// authenticateWith(IrsRoles.VIEW_IRS); -// -// when(service.registerItemJob(any())).thenThrow(InternalServerError.class); -// -// this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) -// .content(new ObjectMapper().writeValueAsString( -// registerJobWithoutDepthAndAspect()))) -// .andExpect(status().is5xxServerError()); -// } -// -//// @Test -//// void shouldReturn500WhenGetSemanticModelsFails() throws Exception { -//// authenticateWith(IrsRoles.VIEW_IRS); -//// -//// when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); -//// -//// this.mockMvc.perform(get("/irs/aspectmodels")) -//// .andExpect(status().is5xxServerError()); -//// } -// -// @Test -// void shouldReturn400WhenProvidingBadInput() throws Exception { -// authenticateWith(IrsRoles.VIEW_IRS); -// -// when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); -// -// this.mockMvc.perform(get("/irs/aspectmodels")) -// .andExpect(status().isBadRequest()); -// } -// -// @Test -// void shouldReturn400WhenCatchingIllegalStateException() throws Exception { -// authenticateWith(IrsRoles.VIEW_IRS); -// -// when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); -// -// this.mockMvc.perform(get("/irs/aspectmodels")) -// .andExpect(status().isBadRequest()); -// } -// -// @Test -// void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exception { -// authenticateWith(IrsRoles.VIEW_IRS); -// -// when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); -// -// this.mockMvc.perform(get("/irs/aspectmodels")) -// .andExpect(status().isBadRequest()); -// } -// -// @Test -// void shouldReturn403WhenRightsAreMissing() throws Exception { -// authenticateWith(IrsRoles.VIEW_IRS); -// -// when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); -// -// this.mockMvc.perform(get("/irs/aspectmodels")) -// .andExpect(status().isForbidden()); -// } + @Test + void handleAll() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + + when(service.registerItemJob(any())).thenThrow(InternalServerError.class); + + this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString( + registerJobWithoutDepthAndAspect()))) + .andExpect(status().is5xxServerError()); + } + + @Test + void shouldReturn500WhenGetSemanticModelsFails() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + + when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); + + this.mockMvc.perform(get("/irs/aspectmodels")) + .andExpect(status().is5xxServerError()); + } + + @Test + void shouldReturn400WhenProvidingBadInput() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + + when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); + + this.mockMvc.perform(get("/irs/aspectmodels")) + .andExpect(status().isBadRequest()); + } + + @Test + void shouldReturn400WhenCatchingIllegalStateException() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + + when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); + + this.mockMvc.perform(get("/irs/aspectmodels")) + .andExpect(status().isBadRequest()); + } + + @Test + void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + + when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); + + this.mockMvc.perform(get("/irs/aspectmodels")) + .andExpect(status().isBadRequest()); + } + + @Test + void shouldReturn403WhenRightsAreMissing() throws Exception { + authenticateWith(IrsRoles.VIEW_IRS); + + when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); + + this.mockMvc.perform(get("/irs/aspectmodels")) + .andExpect(status().isForbidden()); + } } \ No newline at end of file From 3e383a01962253d60708dc3b48015e9c78064bf4 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 14:54:06 +0100 Subject: [PATCH 23/59] feat(impl):[#259] test --- .../tractusx/irs/controllers/IrsExceptionHandlerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index 4d3ea008b1..8b967c67a6 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -47,7 +47,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -@WebMvcTest(IrsController.class) +@WebMvcTest(value = { IrsController.class, IrsExceptionHandler.class }) @Import(SecurityConfiguration.class) class IrsExceptionHandlerTest extends ControllerTest { From cb5781acd0e428b8be71830317b90990d99e46ad Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 15:01:56 +0100 Subject: [PATCH 24/59] feat(impl):[#259] test --- .../MockMvcRestExceptionConfiguration.java | 72 +++++++++++++++++++ .../controllers/IrsExceptionHandlerTest.java | 5 +- 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java new file mode 100644 index 0000000000..8570fe9b43 --- /dev/null +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java @@ -0,0 +1,72 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.util.WebUtils; + +@TestConfiguration +public class MockMvcRestExceptionConfiguration implements WebMvcConfigurer { + + private final BasicErrorController errorController; + + public MockMvcRestExceptionConfiguration(final BasicErrorController basicErrorController) { + this.errorController = basicErrorController; + } + + @Override + public void addInterceptors(final InterceptorRegistry registry) { + registry.addInterceptor(new HandlerInterceptor() { + @Override + public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, + final Object handler, final Exception ex) throws Exception { + + final int status = response.getStatus(); + + if (status >= 400) { + request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, status); + request.setAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, status); + request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, request.getRequestURI().toString()); + // The original exception is already saved as an attribute request + Exception exception = (Exception) request.getAttribute(DispatcherServlet.EXCEPTION_ATTRIBUTE); + if (exception != null) { + request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, exception); + request.setAttribute(WebUtils.ERROR_MESSAGE_ATTRIBUTE, exception.getMessage()); + } + new ObjectMapper().writeValue(response.getOutputStream(), + MockMvcRestExceptionConfiguration.this.errorController.error(request).getBody()); + } + } + }); + } +} \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index 8b967c67a6..e31253195d 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -33,6 +33,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.eclipse.tractusx.irs.ControllerTest; +import org.eclipse.tractusx.irs.MockMvcRestExceptionConfiguration; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; @@ -47,8 +48,8 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -@WebMvcTest(value = { IrsController.class, IrsExceptionHandler.class }) -@Import(SecurityConfiguration.class) +@WebMvcTest(value = { IrsController.class }) +@Import(value = { SecurityConfiguration.class, MockMvcRestExceptionConfiguration.class }) class IrsExceptionHandlerTest extends ControllerTest { @MockBean From 08c3c2de58731b7368ed607b8cbbfaa007638051 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 15 Dec 2023 15:17:20 +0100 Subject: [PATCH 25/59] feat(impl):[#259] test --- .../MockMvcRestExceptionConfiguration.java | 72 ------------------- .../controllers/IrsExceptionHandlerTest.java | 5 +- 2 files changed, 2 insertions(+), 75 deletions(-) delete mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java deleted file mode 100644 index 8570fe9b43..0000000000 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/MockMvcRestExceptionConfiguration.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021,2022,2023 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH AG - * Copyright (c) 2021,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.irs; - -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.RequestDispatcher; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.web.servlet.DispatcherServlet; -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.util.WebUtils; - -@TestConfiguration -public class MockMvcRestExceptionConfiguration implements WebMvcConfigurer { - - private final BasicErrorController errorController; - - public MockMvcRestExceptionConfiguration(final BasicErrorController basicErrorController) { - this.errorController = basicErrorController; - } - - @Override - public void addInterceptors(final InterceptorRegistry registry) { - registry.addInterceptor(new HandlerInterceptor() { - @Override - public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, - final Object handler, final Exception ex) throws Exception { - - final int status = response.getStatus(); - - if (status >= 400) { - request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, status); - request.setAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, status); - request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, request.getRequestURI().toString()); - // The original exception is already saved as an attribute request - Exception exception = (Exception) request.getAttribute(DispatcherServlet.EXCEPTION_ATTRIBUTE); - if (exception != null) { - request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, exception); - request.setAttribute(WebUtils.ERROR_MESSAGE_ATTRIBUTE, exception.getMessage()); - } - new ObjectMapper().writeValue(response.getOutputStream(), - MockMvcRestExceptionConfiguration.this.errorController.error(request).getBody()); - } - } - }); - } -} \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index e31253195d..fea80cf3cc 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -33,7 +33,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.eclipse.tractusx.irs.ControllerTest; -import org.eclipse.tractusx.irs.MockMvcRestExceptionConfiguration; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; @@ -48,8 +47,8 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -@WebMvcTest(value = { IrsController.class }) -@Import(value = { SecurityConfiguration.class, MockMvcRestExceptionConfiguration.class }) +@WebMvcTest(value = { IrsController.class, IrsExceptionHandler.class }) +@Import(value = { SecurityConfiguration.class }) class IrsExceptionHandlerTest extends ControllerTest { @MockBean From 4521a75e1697161391d2c1d6b6f0fc700da44389 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 18 Dec 2023 15:45:55 +0100 Subject: [PATCH 26/59] feat(impl):[#259] check rest assured --- irs-api/pom.xml | 6 + .../irs/controllers/IrsControllerTest.java | 211 +++++++++--------- .../controllers/IrsExceptionHandlerTest.java | 68 +++--- 3 files changed, 153 insertions(+), 132 deletions(-) diff --git a/irs-api/pom.xml b/irs-api/pom.xml index fef1c4530f..91ee09f483 100644 --- a/irs-api/pom.xml +++ b/irs-api/pom.xml @@ -203,6 +203,12 @@ ${wiremock-standalone.version} test + + io.rest-assured + rest-assured + 5.4.0 + test + commons-validator commons-validator diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java index dc8510cee1..3c1d0ab74f 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsControllerTest.java @@ -23,23 +23,25 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.controllers; +import static io.restassured.RestAssured.given; import static java.lang.String.format; import static org.eclipse.tractusx.irs.util.TestMother.registerJob; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithDepthAndAspect; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithUrl; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithoutDepthAndAspect; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.PARTIAL_CONTENT; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -49,8 +51,11 @@ import java.util.stream.Stream; import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; import jakarta.servlet.http.HttpServletRequest; import org.eclipse.tractusx.irs.ControllerTest; +import org.eclipse.tractusx.irs.TestConfig; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.component.Job; import org.eclipse.tractusx.irs.component.JobHandle; @@ -60,33 +65,39 @@ import org.eclipse.tractusx.irs.component.RegisterJob; import org.eclipse.tractusx.irs.component.enums.Direction; import org.eclipse.tractusx.irs.component.enums.JobState; -import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.semanticshub.AspectModel; import org.eclipse.tractusx.irs.semanticshub.AspectModels; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; import org.eclipse.tractusx.irs.services.SemanticHubService; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.BDDMockito; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.support.PagedListHolder; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.server.ResponseStatusException; -@WebMvcTest(IrsController.class) -@Import(SecurityConfiguration.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "digitalTwinRegistry.type=central" }) +@ActiveProfiles(profiles = { "test", "local" }) +@Import(TestConfig.class) +@ExtendWith({ MockitoExtension.class, SpringExtension.class }) class IrsControllerTest extends ControllerTest { private final UUID jobId = UUID.randomUUID(); - @Autowired - private MockMvc mockMvc; @Autowired private ObjectMapper objectMapper; @@ -95,6 +106,15 @@ class IrsControllerTest extends ControllerTest { @MockBean private SemanticHubService semanticHubService; + @LocalServerPort + private int port; + + @BeforeEach + public void configureRestAssured() { + RestAssured.baseURI = "http://localhost"; + RestAssured.port = port; + } + private static Stream corruptedJobs() { return Stream.of(registerJobWithDepthAndAspect(110, null), registerJob("invalidGlobalAssetId", 0, null, false, false, Direction.DOWNWARD), @@ -103,72 +123,59 @@ private static Stream corruptedJobs() { } @Test - void initiateJobForGlobalAssetId() throws Exception { + void initiateJobForGlobalAssetId() { authenticateWith(IrsRoles.VIEW_IRS); final UUID returnedJob = UUID.randomUUID(); - when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build()); - + Mockito.when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build()); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().isCreated()) - .andExpect(content().string(containsString(returnedJob.toString()))); + given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs") + .then().statusCode(CREATED.value()).body("id", is(returnedJob.toString())); } @Test - void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() throws Exception { - when(authenticationService.getAuthentication(any(HttpServletRequest.class))) + void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() { + Mockito.when(authenticationService.getAuthentication(any(HttpServletRequest.class))) .thenThrow(new BadCredentialsException("Wrong ApiKey")); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().isUnauthorized()); + given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs") + .then().statusCode(UNAUTHORIZED.value()); } @Test - void shouldReturnForbiddenStatusWhenRequiredAuthorityIsMissing() throws Exception { + void shouldReturnForbiddenStatusWhenRequiredAuthorityIsMissing() { authenticateWith("view_irs_wrong_authority"); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().isForbidden()); + given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs") + .then().statusCode(FORBIDDEN.value()); } @ParameterizedTest @MethodSource("corruptedJobs") - void shouldReturnBadRequestWhenRegisterJobBodyNotValid(final RegisterJob registerJob) throws Exception { + void shouldReturnBadRequestWhenRegisterJobBodyNotValid(final RegisterJob registerJob) { authenticateWith(IrsRoles.VIEW_IRS); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString(registerJob))) - .andExpect(status().isBadRequest()); + given().port(port).contentType(ContentType.JSON).body(registerJob).post("/irs/jobs") + .then().statusCode(BAD_REQUEST.value()); } @Test - void shouldReturnBadRequestWhenRegisterJobHasWrongCallbackUrl() throws Exception { + void shouldReturnBadRequestWhenRegisterJobHasWrongCallbackUrl() { authenticateWith(IrsRoles.VIEW_IRS); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithUrl("hhh://example.com")))) - .andExpect(status().isBadRequest()); + given().port(port).contentType(ContentType.JSON).body(registerJobWithUrl("hhh://example.com")).post("/irs/jobs") + .then().statusCode(BAD_REQUEST.value()); } @Test - void shouldAcceptCorrectCallbackUrl() throws Exception { + void shouldAcceptCorrectCallbackUrl() { authenticateWith(IrsRoles.VIEW_IRS); final UUID returnedJob = UUID.randomUUID(); - when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build()); + Mockito.when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build()); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithUrl("https://example.com")))) - .andExpect(status().isCreated()); + given().port(port).contentType(ContentType.JSON).body(registerJobWithUrl("https://example.com")).post("/irs/jobs") + .then().statusCode(CREATED.value()); } @Test @@ -184,74 +191,72 @@ void getJobsByState() throws Exception { final String returnJobAsString = objectMapper.writeValueAsString(returnedJob); - when(service.getJobsByState(any(), any())).thenReturn( + Mockito.when(service.getJobsByState(any(), any())).thenReturn( new PageResult(new PagedListHolder<>(List.of(returnedJob)))); - this.mockMvc.perform(get("/irs/jobs")) - .andExpect(status().isOk()) - .andExpect(content().string(containsString(returnJobAsString))) - .andExpect(content().string(containsString(returnedJob.getId().toString()))) - .andExpect(content().string(containsString(returnedJob.getState().toString()))) - .andExpect(content().string(containsString(returnedJob.getStartedOn() - .format(DateTimeFormatter.ofPattern( - "yyyy-MM-dd'T'HH:mm:ss.SSS"))))) - .andExpect(content().string(containsString(returnedJob.getCompletedOn() - .format(DateTimeFormatter.ofPattern( - "yyyy-MM-dd'T'HH:mm:ss.SSS"))))); + given().port(port).get("/irs/jobs") + .then().statusCode(OK.value()) + .body(containsString(returnJobAsString)) + .body(containsString(returnedJob.getId().toString())) + .body(containsString(returnedJob.getState().toString())) + .body(containsString(returnedJob.getStartedOn().format(DateTimeFormatter.ofPattern( + "yyyy-MM-dd'T'HH:mm:ss.SSS")))) + .body(containsString(returnedJob.getCompletedOn().format(DateTimeFormatter.ofPattern( + "yyyy-MM-dd'T'HH:mm:ss.SSS")))); } @Test - void cancelJobById() throws Exception { + void cancelJobById() { authenticateWith(IrsRoles.VIEW_IRS); final Job canceledJob = Job.builder().id(jobId).state(JobState.CANCELED).build(); - when(this.service.cancelJobById(jobId)).thenReturn(canceledJob); + Mockito.when(this.service.cancelJobById(jobId)).thenReturn(canceledJob); - this.mockMvc.perform(put("/irs/jobs/" + jobId)).andExpect(status().isOk()); + given().port(port).put("/irs/jobs/" + jobId) + .then().statusCode(OK.value()); } @Test - void cancelJobById_throwEntityNotFoundException() throws Exception { + void cancelJobById_throwEntityNotFoundException() { authenticateWith(IrsRoles.VIEW_IRS); - given(this.service.cancelJobById(jobId)).willThrow( + BDDMockito.given(this.service.cancelJobById(jobId)).willThrow( new ResponseStatusException(HttpStatus.NOT_FOUND, "No job exists with id " + jobId)); - this.mockMvc.perform(put("/irs/jobs/" + jobId)) - .andExpect(status().isNotFound()) - .andExpect(result -> assertTrue(result.getResolvedException() instanceof ResponseStatusException)); + given().port(port).put("/irs/jobs/" + jobId) + .then().statusCode(NOT_FOUND.value()); } @Test - void getJobWithMalformedIdShouldReturnBadRequest() throws Exception { + void getJobWithMalformedIdShouldReturnBadRequest() { authenticateWith(IrsRoles.VIEW_IRS); final String jobIdMalformed = UUID.randomUUID() + "MALFORMED"; - this.mockMvc.perform(get("/irs/jobs/" + jobIdMalformed)).andExpect(status().isBadRequest()); + given().port(port).get("/irs/jobs/" + jobIdMalformed) + .then().statusCode(BAD_REQUEST.value()); } @Test - void shouldReturnBadRequestWhenRegisterJobWithMalformedAspectJson() throws Exception { + void shouldReturnBadRequestWhenRegisterJobWithMalformedAspectJson() { authenticateWith(IrsRoles.VIEW_IRS); - when(service.registerItemJob(any())).thenThrow(IllegalArgumentException.class); + Mockito.when(service.registerItemJob(any())).thenThrow(IllegalArgumentException.class); final String requestBody = "{ \"aspects\": [ \"MALFORMED\" ], \"globalAssetId\": \"urn:uuid:8a61c8db-561e-4db0-84ec-a693fc5ffdf6\" }"; - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON).content(requestBody)) - .andExpect(status().isBadRequest()); + given().port(port).contentType(ContentType.JSON).body(requestBody).post("/irs/jobs") + .then().statusCode(BAD_REQUEST.value()); } @Test - void shouldReturnBadRequestWhenCancelingAlreadyCompletedJob() throws Exception { + void shouldReturnBadRequestWhenCancelingAlreadyCompletedJob() { authenticateWith(IrsRoles.VIEW_IRS); - given(this.service.cancelJobById(jobId)).willThrow(new IllegalStateException( + BDDMockito.given(this.service.cancelJobById(jobId)).willThrow(new IllegalStateException( format("Cannot transition from state %s to %s", JobState.COMPLETED, JobState.CANCELED))); - this.mockMvc.perform(put("/irs/jobs/" + jobId)) - .andExpect(status().isBadRequest()) - .andExpect(result -> assertTrue(result.getResolvedException() instanceof IllegalStateException)); + given().port(port).put("/irs/jobs/" + jobId) + .then().statusCode(BAD_REQUEST.value()); } @Test @@ -271,50 +276,48 @@ void shouldReturnAspectModels() throws Exception { .models(List.of(assemblyPartRelationship)) .build(); - given(this.semanticHubService.getAllAspectModels()).willReturn(aspectModels); - final String aspectModelResponseAsString = objectMapper.writeValueAsString(aspectModels); + BDDMockito.given(this.semanticHubService.getAllAspectModels()).willReturn(aspectModels); + + final AspectModels response = given().port(port).get("/irs/aspectmodels") + .then().statusCode(OK.value()).and().extract().response().as(AspectModels.class); - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isOk()) - .andExpect(content().string(containsString(aspectModelResponseAsString))); + assertEquals(aspectModels, response); } @Test - void shouldReturnForbiddenStatusForAspectModelsWhenRequiredAuthorityIsMissing() throws Exception { + void shouldReturnForbiddenStatusForAspectModelsWhenRequiredAuthorityIsMissing() { authenticateWith("view_irs_wrong_authority"); - this.mockMvc.perform(get("/irs/aspectmodels").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().isForbidden()); + given().port(port).get("/irs/aspectmodels") + .then().statusCode(FORBIDDEN.value()); } @Test - void shouldReturnPartialWhenJobCompleted() throws Exception { + void shouldReturnPartialWhenJobCompleted() { authenticateWith(IrsRoles.VIEW_IRS); final Jobs runningJob = Jobs.builder().job(Job.builder().id(jobId).state(JobState.RUNNING).build()).build(); - final boolean shouldIncludePartial = Boolean.TRUE; - final boolean shouldNotIncludePartial = Boolean.FALSE; - when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(runningJob); + Mockito.when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(runningJob); - this.mockMvc.perform(get("/irs/jobs/" + jobId).queryParam("returnUncompletedJob", String.valueOf(shouldIncludePartial))).andExpect(status().isPartialContent()); - this.mockMvc.perform(get("/irs/jobs/" + jobId).queryParam("returnUncompletedJob", String.valueOf(shouldNotIncludePartial))).andExpect(status().isPartialContent()); + given().port(port).queryParam("returnUncompletedJob", true).get("/irs/jobs/" + jobId) + .then().statusCode(PARTIAL_CONTENT.value()); + given().port(port).queryParam("returnUncompletedJob", false).get("/irs/jobs/" + jobId) + .then().statusCode(PARTIAL_CONTENT.value()); } @Test - void shouldReturnOkWhenJobCompleted() throws Exception { + void shouldReturnOkWhenJobCompleted() { authenticateWith(IrsRoles.VIEW_IRS); final Jobs completedJob = Jobs.builder().job(Job.builder().id(jobId).state(JobState.COMPLETED).build()).build(); - final boolean shouldIncludePartial = Boolean.TRUE; - final boolean shouldNotIncludePartial = Boolean.FALSE; - when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(completedJob); + Mockito.when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(completedJob); - this.mockMvc.perform(get("/irs/jobs/" + jobId).queryParam("returnUncompletedJob", String.valueOf(shouldIncludePartial))).andExpect(status().isOk()); - this.mockMvc.perform(get("/irs/jobs/" + jobId).queryParam("returnUncompletedJob", String.valueOf(shouldNotIncludePartial))).andExpect(status().isOk()); + given().port(port).queryParam("returnUncompletedJob", true).get("/irs/jobs/" + jobId) + .then().statusCode(OK.value()); + given().port(port).queryParam("returnUncompletedJob", false).get("/irs/jobs/" + jobId) + .then().statusCode(OK.value()); } } \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java index fea80cf3cc..127dd91a76 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/controllers/IrsExceptionHandlerTest.java @@ -23,32 +23,40 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.controllers; +import static io.restassured.RestAssured.given; import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithoutDepthAndAspect; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.web.client.HttpServerErrorException.InternalServerError; -import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; import org.eclipse.tractusx.irs.ControllerTest; +import org.eclipse.tractusx.irs.TestConfig; import org.eclipse.tractusx.irs.common.auth.IrsRoles; -import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.services.IrsItemGraphQueryService; import org.eclipse.tractusx.irs.services.SemanticHubService; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Import; -import org.springframework.http.MediaType; import org.springframework.security.access.AccessDeniedException; -import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -@WebMvcTest(value = { IrsController.class, IrsExceptionHandler.class }) -@Import(value = { SecurityConfiguration.class }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "digitalTwinRegistry.type=central" }) +@ActiveProfiles(profiles = { "test", "local" }) +@Import(TestConfig.class) +@ExtendWith({ MockitoExtension.class, SpringExtension.class }) class IrsExceptionHandlerTest extends ControllerTest { @MockBean @@ -56,19 +64,23 @@ class IrsExceptionHandlerTest extends ControllerTest { @MockBean private SemanticHubService semanticHubService; - @Autowired - private MockMvc mockMvc; + @LocalServerPort + private int port; + + @BeforeEach + public void configureRestAssured() { + RestAssured.baseURI = "http://localhost"; + RestAssured.port = port; + } @Test - void handleAll() throws Exception { + void handleAll() { authenticateWith(IrsRoles.VIEW_IRS); when(service.registerItemJob(any())).thenThrow(InternalServerError.class); - this.mockMvc.perform(post("/irs/jobs").contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString( - registerJobWithoutDepthAndAspect()))) - .andExpect(status().is5xxServerError()); + given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs") + .then().statusCode(INTERNAL_SERVER_ERROR.value()); } @Test @@ -77,8 +89,8 @@ void shouldReturn500WhenGetSemanticModelsFails() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(InternalServerError.class); - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().is5xxServerError()); + given().port(port).get("/irs/aspectmodels") + .then().statusCode(INTERNAL_SERVER_ERROR.value()); } @Test @@ -87,8 +99,8 @@ void shouldReturn400WhenProvidingBadInput() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(IllegalArgumentException.class); - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isBadRequest()); + given().port(port).get("/irs/aspectmodels") + .then().statusCode(BAD_REQUEST.value()); } @Test @@ -97,8 +109,8 @@ void shouldReturn400WhenCatchingIllegalStateException() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(IllegalStateException.class); - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isBadRequest()); + given().port(port).get("/irs/aspectmodels") + .then().statusCode(BAD_REQUEST.value()); } @Test @@ -107,8 +119,8 @@ void shouldReturn400WhenCatchingMethodArgumentTypeMismatchException() throws Exc when(semanticHubService.getAllAspectModels()).thenThrow(MethodArgumentTypeMismatchException.class); - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isBadRequest()); + given().port(port).get("/irs/aspectmodels") + .then().statusCode(BAD_REQUEST.value()); } @Test @@ -117,7 +129,7 @@ void shouldReturn403WhenRightsAreMissing() throws Exception { when(semanticHubService.getAllAspectModels()).thenThrow(AccessDeniedException.class); - this.mockMvc.perform(get("/irs/aspectmodels")) - .andExpect(status().isForbidden()); + given().port(port).get("/irs/aspectmodels") + .then().statusCode(FORBIDDEN.value()); } } \ No newline at end of file From 483f5ac8bcaaf0e4497cb845f78dc3170352878b Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 18 Dec 2023 15:57:35 +0100 Subject: [PATCH 27/59] feat(impl):[#259] update deps --- DEPENDENCIES | 1 + .../EssRecursiveControllerTest.java | 44 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index e4fcebe9dc..8aad831afb 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -166,6 +166,7 @@ maven/mavencentral/io.rest-assured/json-path/5.3.2, Apache-2.0, approved, #9261 maven/mavencentral/io.rest-assured/rest-assured-common/5.3.0, Apache-2.0, approved, #9264 maven/mavencentral/io.rest-assured/rest-assured-common/5.3.2, Apache-2.0, approved, #9264 maven/mavencentral/io.rest-assured/rest-assured/5.3.0, Apache-2.0, approved, #9262 +maven/mavencentral/io.rest-assured/rest-assured/5.4.0, Apache-2.0, approved, #12040 maven/mavencentral/io.rest-assured/xml-path/5.3.0, Apache-2.0, approved, #9267 maven/mavencentral/io.rest-assured/xml-path/5.3.2, Apache-2.0, approved, #9267 maven/mavencentral/io.suzaku/boopickle_2.13/1.3.3, Apache-2.0, approved, clearlydefined diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java index 7d08cde90f..4fa56521ab 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/EssRecursiveControllerTest.java @@ -23,46 +23,58 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.ess.controller; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static io.restassured.RestAssured.given; +import static org.springframework.http.HttpStatus.CREATED; import java.util.List; -import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; import org.eclipse.tractusx.irs.ControllerTest; +import org.eclipse.tractusx.irs.TestConfig; import org.eclipse.tractusx.irs.common.auth.IrsRoles; -import org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification; import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationHeader; import org.eclipse.tractusx.irs.edc.client.model.notification.InvestigationNotificationContent; import org.eclipse.tractusx.irs.ess.service.EssRecursiveService; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Import; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@WebMvcTest(EssRecursiveController.class) -@Import(SecurityConfiguration.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "digitalTwinRegistry.type=central" }) +@ActiveProfiles(profiles = { "test", "local" }) +@Import(TestConfig.class) +@ExtendWith({ MockitoExtension.class, SpringExtension.class }) class EssRecursiveControllerTest extends ControllerTest { private final String path = "/ess/notification/receive-recursive"; - @Autowired - private MockMvc mockMvc; - @MockBean private EssRecursiveService essRecursiveService; + @LocalServerPort + private int port; + + @BeforeEach + public void configureRestAssured() { + RestAssured.baseURI = "http://localhost"; + RestAssured.port = port; + } + @Test void shouldHandleRecursiveBpnInvestigationByNotification() throws Exception { authenticateWith(IrsRoles.VIEW_IRS); - this.mockMvc.perform(post(path).contentType(MediaType.APPLICATION_JSON) - .content(new ObjectMapper().writeValueAsString(prepareNotification()))) - .andExpect(status().isCreated()); + given().port(port).contentType(ContentType.JSON).body(prepareNotification()).post(path) + .then().statusCode(CREATED.value()); } private EdcNotification prepareNotification() { From f5dacd6b55dcc3384b7ceb3bba2ecee2da8b863c Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 18 Dec 2023 16:23:44 +0100 Subject: [PATCH 28/59] feat(impl):[#259] unit test --- .../ApiKeyAuthenticationFilterTest.java | 30 --------- .../security/AuthenticationServiceTest.java | 64 +++++++++++++++++++ 2 files changed, 64 insertions(+), 30 deletions(-) delete mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java create mode 100644 irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java deleted file mode 100644 index 57ee7e5223..0000000000 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthenticationFilterTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2021,2022,2023 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH AG - * Copyright (c) 2021,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.irs.configuration.security; - -import static org.junit.jupiter.api.Assertions.*; - -class ApiKeyAuthenticationFilterTest { - -} \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java new file mode 100644 index 0000000000..3c9ef03c1c --- /dev/null +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java @@ -0,0 +1,64 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.configuration.security; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.eclipse.tractusx.irs.common.auth.IrsRoles; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.AuthorityUtils; + +class AuthenticationServiceTest { + + private final ApiKeysConfiguration apiKeysConfiguration = mock(ApiKeysConfiguration.class); + + private final AuthenticationService authenticationService = new AuthenticationService(apiKeysConfiguration); + + @Test + void shouldReturnApiKeyAuthentication() { + // given + final MockHttpServletRequest request = new MockHttpServletRequest(); + final String apiKey = "12345"; + request.addHeader("X-API-KEY", apiKey); + when(apiKeysConfiguration.authorityOf(apiKey)).thenReturn(ApiKeyAuthority.of(apiKey, AuthorityUtils.createAuthorityList(IrsRoles.ADMIN_IRS))); + + // when + final Authentication authentication = authenticationService.getAuthentication(request); + + // then + assertThat(authentication.getPrincipal()).isEqualTo(apiKey); + assertThat(authentication.getAuthorities()).hasSize(1); + } + + @Test + void shouldThrowExceptionWhenXApiKeyHeaderIsMissing() { + assertThrows(BadCredentialsException.class, () -> authenticationService.getAuthentication(new MockHttpServletRequest())); + } +} \ No newline at end of file From 3448166926a3bdaf69cacd90e06d91d7e0d59e98 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 18 Dec 2023 22:28:40 +0100 Subject: [PATCH 29/59] feat(impl):[#259] fix code smells --- .../irs/configuration/security/ApiKeyAuthentication.java | 2 ++ .../irs/configuration/security/AuthenticationServiceTest.java | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java index ec7db45d07..a455cf3459 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeyAuthentication.java @@ -23,11 +23,13 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.configuration.security; +import lombok.EqualsAndHashCode; import org.springframework.security.authentication.AbstractAuthenticationToken; /** * Api key authentication representation */ +@EqualsAndHashCode public class ApiKeyAuthentication extends AbstractAuthenticationToken { private final ApiKeyAuthority apiKeyAuthority; diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java index 3c9ef03c1c..2495ba89b2 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java @@ -59,6 +59,8 @@ void shouldReturnApiKeyAuthentication() { @Test void shouldThrowExceptionWhenXApiKeyHeaderIsMissing() { - assertThrows(BadCredentialsException.class, () -> authenticationService.getAuthentication(new MockHttpServletRequest())); + final MockHttpServletRequest noApiKeyRequest = new MockHttpServletRequest(); + + assertThrows(BadCredentialsException.class, () -> authenticationService.getAuthentication(noApiKeyRequest)); } } \ No newline at end of file From 4751b2cc7634677a8fac8b11edddb74e62c1db40 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Tue, 19 Dec 2023 09:59:04 +0100 Subject: [PATCH 30/59] feat(impl):[#259] documentation part --- charts/irs-helm/values.yaml | 4 +- .../docs/administration/configuration.adoc | 11 +++-- .../arc42/cross-cutting/safety-security.adoc | 40 +------------------ irs-api/src/main/resources/application.yml | 4 +- 4 files changed, 13 insertions(+), 46 deletions(-) diff --git a/charts/irs-helm/values.yaml b/charts/irs-helm/values.yaml index 3e066f347d..2471cb8285 100644 --- a/charts/irs-helm/values.yaml +++ b/charts/irs-helm/values.yaml @@ -105,8 +105,8 @@ readinessProbe: # IRS Configuration # ##################### irsUrl: # "https://" -apiKeyAdmin: # Api key to access API with admin role -apiKeyRegular: # Api key to access API with regular/view role +apiKeyAdmin: # +apiKeyRegular: # ingress: enabled: false diff --git a/docs/src/docs/administration/configuration.adoc b/docs/src/docs/administration/configuration.adoc index deea250238..cd43d249f9 100644 --- a/docs/src/docs/administration/configuration.adoc +++ b/docs/src/docs/administration/configuration.adoc @@ -24,6 +24,12 @@ include::../../../../charts/irs-helm/values.yaml[lines=104..302] ==== The hostname where the IRS will be made available. +==== +Api key to access API with admin role. + +==== +Api key to access API with regular/view role. + === To expose the IRS service, you need to add an ingress for the default port 8080. You can do this by adding this to ingress: @@ -64,9 +70,6 @@ The URL of the BPDM service. The IRS uses this service to fetch business partner ==== The URL of the OAuth2 token API. Used by the IRS for token creation to authenticate with other services. -==== -The URL of the OAuth2 JWK Set. Used by the IRS to validate tokens when the IRS API is called. - ==== The hostname where Grafana will be made available. @@ -86,7 +89,7 @@ When IRS calls EDC Discovery Service to fetch connector endpoints for BPNLs, the This parameter define how long cache is maintained before it is cleared. Data is in ISO 8601. == OAuth2 Configuration -OAuth2 protocol is used by IRS to protect the APIs and other resources. This means it is possible to configure and use any identity and access management tool that provides OAuth 2.0 functionality. +Previously, OAuth2 protocol was used by IRS to protect the APIs and other resources. As reference, latest IRS version that supported OAuth2 protocol was 4.3.0, which can be found here: https://github.com/catenax-ng/tx-item-relationship-service/releases/tag/4.3.0. === Semantic Model Provisioning The IRS can retrieve semantic models in two ways: diff --git a/docs/src/docs/arc42/cross-cutting/safety-security.adoc b/docs/src/docs/arc42/cross-cutting/safety-security.adoc index 6d10d3c4e1..55dd654fc5 100644 --- a/docs/src/docs/arc42/cross-cutting/safety-security.adoc +++ b/docs/src/docs/arc42/cross-cutting/safety-security.adoc @@ -4,13 +4,8 @@ === IRS API -The IRS is secured using OAuth2.0 / Open ID Connect. -Every request to the IRS API requires a valid bearer token. -JWT token should also contain two claims: +The IRS API is secured using API Keys (tokens that a client provides when invoking API calls). IRS identifies API clients based on the provided token inside 'X-API-KEY' request header, and then checks the token with configuration. API Keys can be configured with helm configuration entries - check Administration Guide to know how. Every request to the IRS API requires a valid 'X-API-KEY' header to be successfully authenticated. -- 'bpn' which is equal to the configuration value from `API_ALLOWED_BPN` property -- 'resource_access' with the specific 'Cl20-CX-IRS' key for C-X environments. (The keys are configurable. For more details see chapter "IRS OAuth2 JWT Token"). -The list of values will be converted to roles by IRS. Currently, IRS API handles two roles: *'admin_irs'* and *'view_irs'.* A valid token with the *'admin_irs'* role can access any endpoint exposed by the IRS API, while a token with the *'view_irs'* role does not have access to policies endpoints and can operate only on resources it owns. That means that he only has access to the resources he has created, e.g. jobs and batches. This behavior is shown in the table below. @@ -40,40 +35,9 @@ Social Standards | Register investigation job | POST /ess/bpn/investigations Legend: x = full access to all resources, (x) = access to the resources he owns -=== IRS OAuth2 JWT Token - -IRS expects the JWT access token to have the following structure to be able to extract role information: - -[source,json] ----- -{ -... - "resource_access": { - "Cl20-CX-IRS": { - "roles": [ - "view_irs", - "admin_irs" - ] - } - }, -... -} ----- - -The field names can be configured via application.yaml: - -[source,yaml] ----- -# OAuth2 JWT token parse config. This configures the structure IRS expects when parsing the IRS role of an access token. -oauth: - resourceClaim: "resource_access" # Name of the JWT claim for roles - irsNamespace: "Cl20-CX-IRS" # Namespace for the IRS roles - roles: "roles" # Name of the list of roles within the IRS namespace ----- - === IRS as DTR client -The IRS acts as a client for the Digital Twin Registry (DTR), which is also secured using OAuth2.0 / Open ID Connect. +The IRS acts as a client for the Digital Twin Registry (DTR), which is secured using OAuth2.0 / Open ID Connect. The IRS uses client credentials to authenticate requests to the DTR. Due to this, the IRS account needs to have access to every item in the DTR, unrelated to the permissions of the account calling the IRS API. diff --git a/irs-api/src/main/resources/application.yml b/irs-api/src/main/resources/application.yml index 4132ba837f..de162077c3 100644 --- a/irs-api/src/main/resources/application.yml +++ b/irs-api/src/main/resources/application.yml @@ -97,8 +97,8 @@ irs: # Application config security: api: keys: - admin: ${API_KEY_ADMIN} - regular: ${API_KEY_REGULAR} + admin: ${API_KEY_ADMIN} # API Key to access IRS API with admin role + regular: ${API_KEY_REGULAR} # API Key to access IRS API with view role blobstore: endpoint: "${MINIO_URL}" # S3 compatible API endpoint (e.g. Minio) From 1fdf14faebc23eda4dd8343f98eed98ccffd396f Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Tue, 19 Dec 2023 14:12:05 +0100 Subject: [PATCH 31/59] feat(impl):[#259] update insomnia collection to use apiKeys --- local/testing/IRS_Request_Collection.json | 1089 +++++++++---------- local/testing/IRS_TEMPLATE_environment.json | 2 + 2 files changed, 515 insertions(+), 576 deletions(-) diff --git a/local/testing/IRS_Request_Collection.json b/local/testing/IRS_Request_Collection.json index 4720b2e97a..bbd58754c7 100644 --- a/local/testing/IRS_Request_Collection.json +++ b/local/testing/IRS_Request_Collection.json @@ -1,29 +1,29 @@ { "_type": "export", "__export_format": 4, - "__export_date": "2023-10-03T14:17:54.580Z", + "__export_date": "2023-12-19T13:10:44.232Z", "__export_source": "insomnia.desktop.app:v2023.5.8", "resources": [ { - "_id": "req_0d87b4e10fb44787826d9283f86230b2", - "parentId": "fld_be8c2610cff74eb59ed09055773d60be", - "modified": 1687243172179, - "created": 1687243056648, - "url": "{{IRS_HOST}}/irs/policies", - "name": "Get all policies", + "_id": "req_09113cc4a55e4db0b7b3cf40b8b6d02c", + "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", + "modified": 1702990529632, + "created": 1687243204155, + "url": "{{IRS_HOST}}/irs/policies/{% prompt 'policyId', '', 'traceability-test', '', false, true %}", + "name": "Delete policy", "description": "", - "method": "GET", + "method": "DELETE", "body": {}, "parameters": [], "headers": [], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.ADMIN_ID }}", - "clientSecret": "{{ _.ADMIN_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.ADMIN_API_KEY }}", + "addTo": "header" }, - "metaSortKey": -1687243056648, + "metaSortKey": -1685602897140.75, "isPrivate": false, "settingStoreCookies": true, "settingSendCookies": true, @@ -34,8 +34,8 @@ "_type": "request" }, { - "_id": "fld_a9821240386945ec8f185fab7c7456bc", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_0195759b9c384a03ac70f2fe63701b55", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1687243055015, "created": 1687243055015, "name": "Policy Store", @@ -46,7 +46,7 @@ "_type": "request_group" }, { - "_id": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", "modified": 1691572726194, "created": 1680682418636, @@ -68,38 +68,9 @@ "_type": "workspace" }, { - "_id": "req_a0fd3fecf398435eb2eaecd58ce49e61", - "parentId": "fld_a9821240386945ec8f185fab7c7456bc", - "modified": 1687243241313, - "created": 1687243204155, - "url": "{{IRS_HOST}}/irs/policies/{% prompt 'policyId', '', 'traceability-test', '', false, true %}", - "name": "Delete policy", - "description": "", - "method": "DELETE", - "body": {}, - "parameters": [], - "headers": [], - "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.ADMIN_ID }}", - "clientSecret": "{{ _.ADMIN_SECRET }}" - }, - "metaSortKey": -1685602897140.75, - "isPrivate": false, - "settingStoreCookies": true, - "settingSendCookies": true, - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingFollowRedirects": "global", - "_type": "request" - }, - { - "_id": "req_0d95630e3b284521a29914cbad3d6336", - "parentId": "fld_a9821240386945ec8f185fab7c7456bc", - "modified": 1693576028823, + "_id": "req_6f2d62a44ccc491cad22dfcc5b157e04", + "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", + "modified": 1702990565006, "created": 1693576003390, "url": "{{IRS_HOST}}/irs/policies/{% prompt 'id', '', 'traceability-test', '', false, true %}", "name": "Update policy", @@ -117,11 +88,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.ADMIN_ID }}", - "clientSecret": "{{ _.ADMIN_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.ADMIN_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1684874704117.875, "isPrivate": false, @@ -134,9 +105,9 @@ "_type": "request" }, { - "_id": "req_b98662fb4f0c476cb8569015d2886457", - "parentId": "fld_a9821240386945ec8f185fab7c7456bc", - "modified": 1687243190523, + "_id": "req_f232d8b29b8e48528496f449145193f9", + "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", + "modified": 1702990569590, "created": 1687243182397, "url": "{{IRS_HOST}}/irs/policies", "name": "Register policy", @@ -154,11 +125,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.ADMIN_ID }}", - "clientSecret": "{{ _.ADMIN_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.ADMIN_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1683962737633.5, "isPrivate": false, @@ -171,8 +142,8 @@ "_type": "request" }, { - "_id": "req_d3262b8c87c04ba5a7e375b65292e496", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_cfebb971b6574425bcda3123aa358466", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1691502818583, "created": 1680682418619, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/shell-descriptors/{% prompt 'aasIdentifier', '', _.GLOBAL_ASSET_ID, '', false, true %}", @@ -209,8 +180,8 @@ "_type": "request" }, { - "_id": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1691504187689, "created": 1680682418630, "name": "Digital Twin Registry", @@ -221,8 +192,8 @@ "_type": "request_group" }, { - "_id": "req_9756d034d3c64d12bfba7708299f9550", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_2665052f708b40a7a0ff9810458142be", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1690529037286, "created": 1690529035794, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/shell-descriptors", @@ -259,8 +230,8 @@ "_type": "request" }, { - "_id": "req_e1cc20a33b7b4e39a67455e0cd066843", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_8874f22975f84acaa3f9c7598a1b9c4d", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1690366224607, "created": 1680682418609, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells", @@ -338,8 +309,8 @@ "_type": "request" }, { - "_id": "req_12330e717b5649629e051622db00a848", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_ed371c67ceb74535928495b3f082a05e", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1690366542261, "created": 1680682418595, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells", @@ -374,8 +345,8 @@ "_type": "request" }, { - "_id": "req_1bba1f291816490098ac164753a1ab1c", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_d62d73a234b04b94bea554e266dedfe7", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1691061418395, "created": 1680682418581, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells", @@ -410,8 +381,8 @@ "_type": "request" }, { - "_id": "req_ea94bfdec10f449ba82559681a64037d", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_d536ae7dec104219b4f638accf73f4e7", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1691500553894, "created": 1680682418570, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells/query", @@ -447,8 +418,8 @@ "_type": "request" }, { - "_id": "req_c90fd02dd0874beab32e0dd6a32680b1", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_fc2a0a60847f47e4bc868689e02e3c82", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1691571903257, "created": 1691408320970, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells/query", @@ -484,8 +455,8 @@ "_type": "request" }, { - "_id": "req_49381cd212ab46aaa69917647db696be", - "parentId": "fld_aedfd7a2f8b240fd8a0d4237e3106c84", + "_id": "req_3e1614f342cc4c71b0f3420e10b8a1d0", + "parentId": "fld_c6b2a98cadb9413ab6eaa95d006a05ed", "modified": 1690366857910, "created": 1689167429413, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/shell-descriptors/{% prompt 'id', '', '', '', false, true %}", @@ -530,9 +501,9 @@ "_type": "request" }, { - "_id": "req_6876042c0fd442129709052f593eac17", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572360476, + "_id": "req_5343969b9bf347789011f1b12a302cc5", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991054859, "created": 1680682418551, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.0.0 [Register Job]", @@ -550,11 +521,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418551, "isPrivate": false, @@ -567,8 +538,8 @@ "_type": "request" }, { - "_id": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_99c35c51cb3143518e93f7efa74c3a49", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418562, "created": 1680682418562, "name": "IRS Test Collection", @@ -579,9 +550,9 @@ "_type": "request_group" }, { - "_id": "req_fa164b4c409b40db827aff0e79a41878", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572904486, + "_id": "req_787b826634504d14b0725f55f346a80b", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991058493, "created": 1680682418539, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.1.0 [Register Job globalAssetId ]", @@ -599,11 +570,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418539, "isPrivate": false, @@ -616,9 +587,9 @@ "_type": "request" }, { - "_id": "req_627740b85e2b44afbede59bee38efb55", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572915877, + "_id": "req_9ec7dfc15e934fee8bd2b2d22b9af2e9", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991063641, "created": 1680682418524, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.1.1 [Register Job globalAssetId ]", @@ -636,11 +607,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418524, "isPrivate": false, @@ -653,9 +624,9 @@ "_type": "request" }, { - "_id": "req_5915b9d5fd834fc88abf5b2dcf5d4e14", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572926461, + "_id": "req_bce1d4b4865d481a9fbcc34f04a6f218", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991067797, "created": 1680682418514, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.2.0 [Register Job with depth and bomLifecycle asBuilt]", @@ -673,11 +644,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418514, "isPrivate": false, @@ -690,9 +661,9 @@ "_type": "request" }, { - "_id": "req_50b0a15282cb4d9eb74d022bc331bf07", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572936024, + "_id": "req_e41a57c0151b4bb189133061751364e8", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991071709, "created": 1680682418504, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.2.1 [Register Job with depth and bomLifecycle asPlanned]", @@ -710,11 +681,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418504, "isPrivate": false, @@ -727,9 +698,9 @@ "_type": "request" }, { - "_id": "req_8b66e84b065e4631b480a48ba57a054f", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1695042911082, + "_id": "req_7f697d7f3e55410aaebce0eccb694f0a", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991076696, "created": 1695042901876, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.2.2 [Register Job with depth and bomLifecycle asSpecified]", @@ -747,11 +718,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418496, "isPrivate": false, @@ -764,9 +735,9 @@ "_type": "request" }, { - "_id": "req_67a54df7c551456bb988d5433d15a3f3", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572943357, + "_id": "req_2b725578779e412c8103ffe6a1f88e70", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991080833, "created": 1680682418488, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.0 [Register Job with aspect SerialPart]", @@ -784,11 +755,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418488, "isPrivate": false, @@ -801,9 +772,9 @@ "_type": "request" }, { - "_id": "req_df79b6f9718740739fb2956a5e793ee9", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572949775, + "_id": "req_7042132a15f44a24ab8f1aa41cba781e", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991084713, "created": 1680682418479, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.1 [Register Job with aspect SerialPart and SingleLevelBomAsBuilt]", @@ -821,11 +792,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418479, "isPrivate": false, @@ -838,9 +809,9 @@ "_type": "request" }, { - "_id": "req_ea02d5cd06b14599b748a7a5c7074597", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572957454, + "_id": "req_39864c9dceb24feebf3744441f3252b0", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991088495, "created": 1680682418469, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.2 [Register Job with aspect MaterialForRecycling and BatteryPass]", @@ -858,11 +829,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418469, "isPrivate": false, @@ -875,9 +846,9 @@ "_type": "request" }, { - "_id": "req_de68bf2f27af483ea3d57c2faa382c92", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572965207, + "_id": "req_ed37b0171546433c8a8170945ed698fe", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991094498, "created": 1680682418460, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.3 [Register Job with aspect type Batch and CertificateOfDestruction]", @@ -895,11 +866,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418460, "isPrivate": false, @@ -912,9 +883,9 @@ "_type": "request" }, { - "_id": "req_32a42ffab57e468891cb3738e0cbd2f6", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572975641, + "_id": "req_5e42af9e4d0d4bfda16f8912d10bfdcb", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991098918, "created": 1680682418451, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.4 [Register Job with aspect SerialPart and AddressAspect]", @@ -932,11 +903,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418451, "isPrivate": false, @@ -949,9 +920,9 @@ "_type": "request" }, { - "_id": "req_fcd677768e4749e6890e742c5535cf20", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572985624, + "_id": "req_64119ae49dba4513845e87d9bfaf75e7", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991103182, "created": 1680682418442, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.5 [Register Job with aspect PartAsPlanned]", @@ -969,11 +940,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418442, "isPrivate": false, @@ -986,9 +957,9 @@ "_type": "request" }, { - "_id": "req_7aea0fe27d264ccaae4dabca55908a18", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572678250, + "_id": "req_a13c1a3e1ce2493fb064407aebf87845", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991107672, "created": 1680682418432, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.6 [Register Job with upward direction]", @@ -1006,11 +977,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418432, "isPrivate": false, @@ -1023,9 +994,9 @@ "_type": "request" }, { - "_id": "req_418468c2c71944c183e14a118dad3ba1", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1695192994847, + "_id": "req_a9d4e40c141e4d77a1f0b5d1bde21c27", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991113717, "created": 1695192937155, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.7 [Register Job with aspect JustInSequencePart]", @@ -1043,11 +1014,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418428, "isPrivate": false, @@ -1060,9 +1031,9 @@ "_type": "request" }, { - "_id": "req_1745c53de4f14d8e9458f7095e7a9bd9", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1695192982633, + "_id": "req_92b6e18037c841729ab5fc14ef55f23d", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991120609, "created": 1695192971825, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.3.8 [Register Job with aspect TractionBatteryCode]", @@ -1080,11 +1051,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418426, "isPrivate": false, @@ -1097,9 +1068,9 @@ "_type": "request" }, { - "_id": "req_1f462787c52b4241a9d4906ddfe7940a", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691574126936, + "_id": "req_1991d08340764ef1af526011a8929aa5", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991125292, "created": 1680682418424, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.4.0 [Register Job with invalid or not exisiting aspect type]", @@ -1117,11 +1088,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418424, "isPrivate": false, @@ -1134,9 +1105,9 @@ "_type": "request" }, { - "_id": "req_f1385d39b501424caebc7067b1b809aa", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691574130454, + "_id": "req_84340ba6eb254659ba0f9e9ee128aefc", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991130711, "created": 1680682418414, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.4.1 [Register Job with invalid or not exisiting aspect type]", @@ -1154,11 +1125,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418414, "isPrivate": false, @@ -1171,9 +1142,9 @@ "_type": "request" }, { - "_id": "req_55c8aaff89644752833d4118fc3ff830", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691574133572, + "_id": "req_8d98fd4edb7b49199fba171f9d72dd9e", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991137603, "created": 1680682418401, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.5.0 [Register Job with all aspect type]", @@ -1191,11 +1162,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418401, "isPrivate": false, @@ -1208,9 +1179,9 @@ "_type": "request" }, { - "_id": "req_69728c86c252433c865341fc37da469a", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691574328481, + "_id": "req_6ca35ef4aec8455797a7bebae102a1b5", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991145487, "created": 1680682418392, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.6.0 [Register Job with BPN lookup]", @@ -1228,11 +1199,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418392, "isPrivate": false, @@ -1245,9 +1216,9 @@ "_type": "request" }, { - "_id": "req_beb0d36b302f44559ff1bc4e6734a537", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691574334421, + "_id": "req_2c184f2fecea46fe905f3df24d9160a6", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991149742, "created": 1683184048412, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.7.0 [Register Job with invalid policy]", @@ -1265,11 +1236,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418386.5, "isPrivate": false, @@ -1282,9 +1253,9 @@ "_type": "request" }, { - "_id": "req_fd07a6b6d4a8403db523585b610bf24a", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1693562089788, + "_id": "req_bac623bb6747471999c1aabdf30acbcd", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991154342, "created": 1693493383337, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.8.0 [Register Job with data integrity success]", @@ -1302,11 +1273,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418382.375, "isPrivate": false, @@ -1319,9 +1290,9 @@ "_type": "request" }, { - "_id": "req_f18b57a3b69348708c80adda421a8de5", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1693566189520, + "_id": "req_4f28e46c77f942b6bea4fdf589be4ca1", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991159838, "created": 1693493584873, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.8.1 [Register Job with data integrity wrong hash]", @@ -1339,11 +1310,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418381.6875, "isPrivate": false, @@ -1356,9 +1327,9 @@ "_type": "request" }, { - "_id": "req_a70bf616e5a24b71b13967f1d186977d", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1693566192319, + "_id": "req_6f72851efd3840e4ac5dddf85ea485df", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991164094, "created": 1693493594373, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.8.2 [Register Job with data integrity wrong signature]", @@ -1376,11 +1347,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418381.3438, "isPrivate": false, @@ -1393,9 +1364,9 @@ "_type": "request" }, { - "_id": "req_d043eb6376b74f8391dd76eeb2c7a8da", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1693566195101, + "_id": "req_c99503b01abe41f792dccf5a1da33c17", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991168363, "created": 1693493604521, "url": "{{IRS_HOST}}/irs/jobs", "name": "1.8.3 [Register Job with data integrity integrity aspect missing]", @@ -1413,11 +1384,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418381.1719, "isPrivate": false, @@ -1430,9 +1401,9 @@ "_type": "request" }, { - "_id": "req_dbb0d4a0d96c40249e5cb92fab9a2d0e", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691571995584, + "_id": "req_a5276cce96634693a65b355c2dd1d7d3", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991173689, "created": 1680682418381, "url": "{{IRS_HOST}}/irs/jobs", "name": "2.0.0 [Search for completed Jobs]", @@ -1453,11 +1424,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418381, "isPrivate": false, @@ -1470,9 +1441,9 @@ "_type": "request" }, { - "_id": "req_92e80cc8681e4c90bea0403b289955a6", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691571999161, + "_id": "req_d0768a3e244a4634b69a4d26dc85d23b", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991177973, "created": 1680682418372, "url": "{{IRS_HOST}}/irs/jobs", "name": "2.0.1 [Search for Jobs in error state]", @@ -1493,11 +1464,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418372, "isPrivate": false, @@ -1510,9 +1481,9 @@ "_type": "request" }, { - "_id": "req_871b00bc6448477d8db16cd8bbbf0b53", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572006985, + "_id": "req_9319b2847acf48c98d771d7e318315a6", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991182139, "created": 1680682418358, "url": "{{IRS_HOST}}/irs/jobs", "name": "2.0.2 [Search for Jobs in initial state]", @@ -1533,11 +1504,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418358, "isPrivate": false, @@ -1550,9 +1521,9 @@ "_type": "request" }, { - "_id": "req_96b1fac11f9c4f4fa6b54ac4eb624790", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572010448, + "_id": "req_96fc195d9d8647f1b5538e3901cd7968", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991186114, "created": 1680682418348, "url": "{{IRS_HOST}}/irs/jobs", "name": "2.0.3 [Search for all Jobs in JobStore]", @@ -1567,11 +1538,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418348, "isPrivate": false, @@ -1584,9 +1555,9 @@ "_type": "request" }, { - "_id": "req_1fffeb148a6b45e78178b06add79b01f", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572013890, + "_id": "req_6f68e1e65bc042079e73460fece779a0", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991190326, "created": 1680682418339, "url": "{{IRS_HOST}}/irs/jobs", "name": "2.1.0 [Search for running Jobs]", @@ -1607,11 +1578,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418339, "isPrivate": false, @@ -1624,9 +1595,9 @@ "_type": "request" }, { - "_id": "req_193d95ec37f2484faf57ee77eb357528", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572169302, + "_id": "req_67bf27f456f94b578e781c83a58eed4d", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991196283, "created": 1680682418325, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", "name": "3.0.0 [Search for given jobId with uncomplete]", @@ -1647,11 +1618,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418325, "isPrivate": false, @@ -1664,9 +1635,9 @@ "_type": "request" }, { - "_id": "req_9bc4c2adfa114f45add0ca894813ad42", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572020954, + "_id": "req_e763a14926bc42b6b3cf15a33dbb6262", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991200399, "created": 1680682418316, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", "name": "3.1.0 [Search for given jobId]", @@ -1681,11 +1652,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418316, "isPrivate": false, @@ -1698,9 +1669,9 @@ "_type": "request" }, { - "_id": "req_e493fba73d7a47fe9a7c8932530337fa", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572140559, + "_id": "req_b6d7199b149042c9b77df6f57379641e", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991205447, "created": 1680682418307, "url": "{{IRS_HOST}}/irs/jobs/test", "name": "3.1.1 [Search for invalid jobId]", @@ -1715,11 +1686,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418307, "isPrivate": false, @@ -1732,9 +1703,9 @@ "_type": "request" }, { - "_id": "req_e07fffc2ca084f29ba5ed283b0f1ac48", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572133946, + "_id": "req_7074d238bdfd4ffd9910160d2917a4d1", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991214202, "created": 1680682418297, "url": "{{IRS_HOST}}/irs/jobs/00000000-0000-0000-0000-000000000000", "name": "3.1.2 [Search for unknown jobId]", @@ -1749,11 +1720,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418297, "isPrivate": false, @@ -1766,9 +1737,9 @@ "_type": "request" }, { - "_id": "req_ae4b145a965e4280b1c7e2cc8e300fec", - "parentId": "fld_16ae74914cc44a8d8d2f9304ae33f98a", - "modified": 1691572032383, + "_id": "req_9d3b808daa9f4ea5a2683ebcde47703b", + "parentId": "fld_99c35c51cb3143518e93f7efa74c3a49", + "modified": 1702991218362, "created": 1680682418280, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", "name": "6.0.0 [Cancel Job for given jobId]", @@ -1783,11 +1754,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418280, "isPrivate": false, @@ -1800,8 +1771,8 @@ "_type": "request" }, { - "_id": "req_3d1821920e254c2aba58dadf2f78eb76", - "parentId": "fld_21deb0c7ffae4da8973c95277bf03da1", + "_id": "req_7a029e9de6814c03928255f9a1982004", + "parentId": "fld_a94b368ce3e84a7488a4f63ad635a162", "modified": 1683630958934, "created": 1682672699249, "url": "{{ _.BPN_DISCOVERY }}/api/administration/connectors/bpnDiscovery/search", @@ -1838,8 +1809,8 @@ "_type": "request" }, { - "_id": "fld_21deb0c7ffae4da8973c95277bf03da1", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_a94b368ce3e84a7488a4f63ad635a162", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1683630931664, "created": 1683630887514, "name": "Discovery", @@ -1850,8 +1821,8 @@ "_type": "request_group" }, { - "_id": "req_c3662319534748e9b612767fd09d4ca8", - "parentId": "fld_21deb0c7ffae4da8973c95277bf03da1", + "_id": "req_d1dbbb7587b246c1b0196358496357f9", + "parentId": "fld_a94b368ce3e84a7488a4f63ad635a162", "modified": 1683630963691, "created": 1683031718699, "url": "{{ _.DISCOVERY_FINDER }}/api/administration/connectors/discovery/search", @@ -1888,8 +1859,8 @@ "_type": "request" }, { - "_id": "req_0e546b5d6c0f4541a6fac63c1d893498", - "parentId": "fld_21deb0c7ffae4da8973c95277bf03da1", + "_id": "req_3210d8eeace1496f98cb810353f5b825", + "parentId": "fld_a94b368ce3e84a7488a4f63ad635a162", "modified": 1691567913468, "created": 1683560906453, "url": "{{ _.EDC_DISCOVERY }}/api/administration/connectors/discovery", @@ -1926,9 +1897,9 @@ "_type": "request" }, { - "_id": "req_a192b4ad61964bf6b67c675643e7e7ba", - "parentId": "fld_1848735731fd4d88811e9f8d1817eeb6", - "modified": 1691567746933, + "_id": "req_a6c1b73c7d2d407699913aabe4af51c5", + "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "modified": 1702991293070, "created": 1680682418265, "url": "{{IRS_HOST}}/irs/jobs", "name": "Register Job", @@ -1946,11 +1917,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418265, "isPrivate": false, @@ -1963,8 +1934,8 @@ "_type": "request" }, { - "_id": "fld_1848735731fd4d88811e9f8d1817eeb6", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418273, "created": 1680682418273, "name": "IRS Basic API Calls", @@ -1975,9 +1946,9 @@ "_type": "request_group" }, { - "_id": "req_9b0e07548239476c90d11680d6b6708c", - "parentId": "fld_1848735731fd4d88811e9f8d1817eeb6", - "modified": 1680686256003, + "_id": "req_07674ad6ec7147568bc8339deaca335d", + "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "modified": 1702991288793, "created": 1680682418257, "url": "{{IRS_HOST}}/irs/jobs", "name": "Search for all Jobs in JobStore", @@ -1992,11 +1963,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418257, "isPrivate": false, @@ -2009,9 +1980,9 @@ "_type": "request" }, { - "_id": "req_f3afcc4ee068463da501a91ac13299ef", - "parentId": "fld_1848735731fd4d88811e9f8d1817eeb6", - "modified": 1691567830017, + "_id": "req_9e02c92e769c4ad9bf5d53f5d9c2a6de", + "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "modified": 1702991284435, "created": 1680682418247, "url": "{{IRS_HOST}}/irs/jobs", "name": "Search for Jobs for given state", @@ -2046,11 +2017,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418247, "isPrivate": false, @@ -2063,9 +2034,9 @@ "_type": "request" }, { - "_id": "req_2a2ddcde35b242d89d8f403da790869b", - "parentId": "fld_1848735731fd4d88811e9f8d1817eeb6", - "modified": 1691567881065, + "_id": "req_7c35241474cf41d1a6cc2864afc7313e", + "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "modified": 1702991280208, "created": 1690384427379, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", "name": "Get Job for jobId", @@ -2086,11 +2057,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418238, "isPrivate": false, @@ -2103,9 +2074,9 @@ "_type": "request" }, { - "_id": "req_4baeca1b42c54f9da0e3c80fe99f25ce", - "parentId": "fld_1848735731fd4d88811e9f8d1817eeb6", - "modified": 1691567884778, + "_id": "req_39681ec4183f4a818cef42e8c78d994a", + "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "modified": 1702991276045, "created": 1680682418229, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", "name": "Cancel Job for jobId", @@ -2120,11 +2091,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418229, "isPrivate": false, @@ -2137,9 +2108,9 @@ "_type": "request" }, { - "_id": "req_b70e24c7208646acac2471ac4869f7dc", - "parentId": "fld_1848735731fd4d88811e9f8d1817eeb6", - "modified": 1690365987561, + "_id": "req_f7475fa73c934aa898e09d0204cfc7da", + "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", + "modified": 1702991272198, "created": 1682498338739, "url": "{{IRS_HOST}}/irs/aspectmodels", "name": "Get all available Aspect Models", @@ -2154,11 +2125,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418179, "isPrivate": false, @@ -2171,8 +2142,8 @@ "_type": "request" }, { - "_id": "req_f37d5de67a72409b93523b2dbb643c3a", - "parentId": "fld_4bb1e94d94264daa959e9378a3ea93d3", + "_id": "req_2912d111f43643828b16baa54c2fcc95", + "parentId": "fld_be446bc05f624985a6a9211e55ee1c7d", "modified": 1691504888870, "created": 1680682418213, "url": "{{ _.SEMANTIC_HUB_URL }}/hub/api/v1/models", @@ -2213,8 +2184,8 @@ "_type": "request" }, { - "_id": "fld_4bb1e94d94264daa959e9378a3ea93d3", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_be446bc05f624985a6a9211e55ee1c7d", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418222, "created": 1680682418222, "name": "Semantics Hub", @@ -2225,8 +2196,8 @@ "_type": "request_group" }, { - "_id": "req_c380161c8ac1481bb230e34d6d2bb2ef", - "parentId": "fld_4bb1e94d94264daa959e9378a3ea93d3", + "_id": "req_87800d1dbb74434d9d1a6a844e252799", + "parentId": "fld_be446bc05f624985a6a9211e55ee1c7d", "modified": 1691504864710, "created": 1680682418204, "url": "{{ _.SEMANTIC_HUB_URL }}/hub/api/v1/models/urn%3Abamm%3Aio.catenax.serial_part_typization%3A1.0.0%23SerialPartTypization", @@ -2254,8 +2225,8 @@ "_type": "request" }, { - "_id": "req_4d6d3cde8e564122ba7da812ba5d60ad", - "parentId": "fld_4bb1e94d94264daa959e9378a3ea93d3", + "_id": "req_44e6f1dd9d544129a4454272b948b76c", + "parentId": "fld_be446bc05f624985a6a9211e55ee1c7d", "modified": 1691504802561, "created": 1680682418192, "url": "{{ _.SEMANTIC_HUB_URL }}/hub/api/v1/models/urn%3Abamm%3Aio.catenax.serial_part_typization%3A1.0.0%23SerialPartTypization/json-schema", @@ -2283,8 +2254,8 @@ "_type": "request" }, { - "_id": "req_550db8730d764aaaad53c25956475f8f", - "parentId": "fld_b8389a897e144a9bae1d42c8437cf137", + "_id": "req_af09068bf6df4299a86059178155f80c", + "parentId": "fld_365f72e79184426595b3ddd237ab04be", "modified": 1681718801853, "created": 1680682418174, "url": "{{ _.BPDM_URL }}/v1/api/catena/business-partner/{% prompt 'BPN', '', '', '', false, true %}", @@ -2318,8 +2289,8 @@ "_type": "request" }, { - "_id": "fld_b8389a897e144a9bae1d42c8437cf137", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_365f72e79184426595b3ddd237ab04be", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418184, "created": 1680682418184, "name": "Business partner data management", @@ -2330,9 +2301,9 @@ "_type": "request_group" }, { - "_id": "req_652cf8ddc2b94dedb2c21c55a5e1643b", - "parentId": "fld_c7dab8f730bb4cf38993366d008e9e8c", - "modified": 1681717263599, + "_id": "req_e3f5a1c9c48c43e28f6f0989a22283d1", + "parentId": "fld_632cbac21e8b4ad6bc9129682997a72d", + "modified": 1702991347797, "created": 1680682418157, "url": "{{IRS_HOST}}/esr/esr-statistics/{% prompt 'globalAssetId', 'Provide global asset ID or use default', _.GLOBAL_ASSET_ID, '', false, true %}/{% prompt 'BOM Lifecycle', '', '', '', false, true %}/{% prompt 'Certificate', '', '', '', false, true %}/submodel", "name": "Get Esr Statistics", @@ -2347,11 +2318,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418158, "isPrivate": false, @@ -2364,8 +2335,8 @@ "_type": "request" }, { - "_id": "fld_c7dab8f730bb4cf38993366d008e9e8c", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_632cbac21e8b4ad6bc9129682997a72d", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418167, "created": 1680682418167, "name": "ESR Spike", @@ -2376,9 +2347,9 @@ "_type": "request_group" }, { - "_id": "req_cbe1d8a34c5a4b78a9e94e2b22049ca7", - "parentId": "fld_54d58b9eb7d9460e9e1b3ce1fdd27532", - "modified": 1696342652388, + "_id": "req_20d530394909498d8815bca896b5f1c1", + "parentId": "fld_6e5c69f5335d44ea8c3d9deb8945596c", + "modified": 1702991361578, "created": 1680682418143, "url": "{{IRS_HOST}}/ess/bpn/investigations", "name": "Register Job Investigation", @@ -2396,11 +2367,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418143, "isPrivate": false, @@ -2413,8 +2384,8 @@ "_type": "request" }, { - "_id": "fld_54d58b9eb7d9460e9e1b3ce1fdd27532", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_6e5c69f5335d44ea8c3d9deb8945596c", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418151, "created": 1680682418151, "name": "ESS Spike", @@ -2425,9 +2396,9 @@ "_type": "request_group" }, { - "_id": "req_840fb7da94fa482aa52c8f97fc05b310", - "parentId": "fld_54d58b9eb7d9460e9e1b3ce1fdd27532", - "modified": 1681717309378, + "_id": "req_9d9e0fb370444917be5a38b557030073", + "parentId": "fld_6e5c69f5335d44ea8c3d9deb8945596c", + "modified": 1702991370481, "created": 1680682418134, "url": "{{IRS_HOST}}/ess/bpn/investigations/{% prompt 'Job ID', '', '', '', false, true %}", "name": "Search for investigation by jobId", @@ -2442,11 +2413,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418134, "isPrivate": false, @@ -2459,9 +2430,9 @@ "_type": "request" }, { - "_id": "req_a88fd80bc95349088039a21c4e841af9", - "parentId": "fld_6bfeda181e9f46b4b85bb345457e97f9", - "modified": 1691504578204, + "_id": "req_0ebc01e95f94455bb1b0c87f90bcab06", + "parentId": "fld_acf689d4003a47898ddbe195039a59d4", + "modified": 1702991381651, "created": 1680682418118, "url": "{{IRS_HOST}}/irs/orders", "name": "Register Batch Order", @@ -2479,11 +2450,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418118, "isPrivate": false, @@ -2496,8 +2467,8 @@ "_type": "request" }, { - "_id": "fld_6bfeda181e9f46b4b85bb345457e97f9", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_acf689d4003a47898ddbe195039a59d4", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1680682418128, "created": 1680682418128, "name": "Batch Processing", @@ -2508,9 +2479,9 @@ "_type": "request_group" }, { - "_id": "req_df3c4c4901924ac7b2aaba87a7bfe690", - "parentId": "fld_6bfeda181e9f46b4b85bb345457e97f9", - "modified": 1696342658242, + "_id": "req_14c9c29c846e4ba8a66d27ced0b899f6", + "parentId": "fld_acf689d4003a47898ddbe195039a59d4", + "modified": 1702991390349, "created": 1696342619602, "url": "{{IRS_HOST}}/irs/ess/orders", "name": "Register ESS Batch Order", @@ -2528,11 +2499,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418113.5, "isPrivate": false, @@ -2545,43 +2516,9 @@ "_type": "request" }, { - "_id": "req_ee1cc65156a04cf3a3a07987e393df48", - "parentId": "fld_23fae21795994f76a61c93c8c8699b7d", - "modified": 1697020037992, - "created": 1697017836306, - "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Job ID', '', '', '', false, true %}", - "name": "Cancel order job for given orderId", - "description": "Cancel either regular or ess order job", - "method": "PUT", - "body": {}, - "parameters": [], - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" - }, - "metaSortKey": -1680682418111.25, - "isPrivate": false, - "settingStoreCookies": true, - "settingSendCookies": true, - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingFollowRedirects": "global", - "_type": "request" - }, - { - "_id": "req_daeca07fd8be473b9688e8653cf8940d", - "parentId": "fld_6bfeda181e9f46b4b85bb345457e97f9", - "modified": 1681717455311, + "_id": "req_c42c94e761c24426878cf3cd88e301b1", + "parentId": "fld_acf689d4003a47898ddbe195039a59d4", + "modified": 1702991398473, "created": 1680682418109, "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}", "name": "Search for given orderId", @@ -2596,11 +2533,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418109, "isPrivate": false, @@ -2613,9 +2550,9 @@ "_type": "request" }, { - "_id": "req_e711ec22b32f40b8a42dc11923145239", - "parentId": "fld_6bfeda181e9f46b4b85bb345457e97f9", - "modified": 1681717669066, + "_id": "req_3e41dd9d2c1a4a9b880ba63ec4dd312b", + "parentId": "fld_acf689d4003a47898ddbe195039a59d4", + "modified": 1702991409664, "created": 1680682418099, "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}/batches/{% prompt 'Batch ID', '', '', '', false, true %}", "name": "Search for given orderId and batchId", @@ -2630,11 +2567,11 @@ } ], "authentication": { - "type": "oauth2", - "grantType": "client_credentials", - "accessTokenUrl": "{{ _.OAUTH2_TOKEN_URL }}", - "clientId": "{{ _.CLIENT_ID }}", - "clientSecret": "{{ _.CLIENT_SECRET }}" + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" }, "metaSortKey": -1680682418099, "isPrivate": false, @@ -2647,8 +2584,8 @@ "_type": "request" }, { - "_id": "req_839742b4f8ce43d7b5ae69ba5a14d97a", - "parentId": "fld_fb3faef0045744f1ad69a211005b9087", + "_id": "req_384b37b316254ad1bfe39474877374b7", + "parentId": "fld_c1542e78ff7e4c36839c5cb7ca56e7c6", "modified": 1690472186478, "created": 1678358655308, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/catalog/request", @@ -2684,8 +2621,8 @@ "_type": "request" }, { - "_id": "fld_fb3faef0045744f1ad69a211005b9087", - "parentId": "fld_f8dea31e10f445708d36c2244897cf08", + "_id": "fld_c1542e78ff7e4c36839c5cb7ca56e7c6", + "parentId": "fld_8b90eb2a99354ecdb14805791a34fbaa", "modified": 1690362660167, "created": 1690362660167, "name": "Catalog", @@ -2696,8 +2633,8 @@ "_type": "request_group" }, { - "_id": "fld_f8dea31e10f445708d36c2244897cf08", - "parentId": "fld_34550c646cf24dd592e4fcb218d0d169", + "_id": "fld_8b90eb2a99354ecdb14805791a34fbaa", + "parentId": "fld_cefec9f9528a43a185f2267e8ee4c0d5", "modified": 1690363778601, "created": 1675675609576, "name": "EDC-Requests", @@ -2708,8 +2645,8 @@ "_type": "request_group" }, { - "_id": "req_cc9b4eed1663402ebd5472ce519b83c6", - "parentId": "fld_fb3faef0045744f1ad69a211005b9087", + "_id": "req_640982624e044311806c5b5af6ba908a", + "parentId": "fld_c1542e78ff7e4c36839c5cb7ca56e7c6", "modified": 1691500654267, "created": 1685521485278, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/catalog/request", @@ -2745,8 +2682,8 @@ "_type": "request" }, { - "_id": "req_868e9bff0cfe46a69e552a3ede820079", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_8c3dffcfb17040558c3c96b5a6fe0d07", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1691578280640, "created": 1675675609557, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations", @@ -2782,8 +2719,8 @@ "_type": "request" }, { - "_id": "fld_bd70e484a29f4b76a6ee0750f33ff878", - "parentId": "fld_f8dea31e10f445708d36c2244897cf08", + "_id": "fld_f277ccd7006d4c5981445ea5824d5e80", + "parentId": "fld_8b90eb2a99354ecdb14805791a34fbaa", "modified": 1684146626847, "created": 1684146519491, "name": "Negotiation", @@ -2794,8 +2731,8 @@ "_type": "request_group" }, { - "_id": "req_412f266365f34990a1b26daebad9f45d", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_eda28efb347a4b889574b6d4efbfc2d8", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1690362123962, "created": 1675675609549, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations/{% prompt 'id', '', '', '', false, true %}", @@ -2828,8 +2765,8 @@ "_type": "request" }, { - "_id": "req_ed0bd6ec35a243fb804701c52e502c1d", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_7812c8281cfd45bca643079b91d09696", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1690362117725, "created": 1685444139708, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations/{% prompt 'id', '', '', '', false, true %}/cancel", @@ -2857,8 +2794,8 @@ "_type": "request" }, { - "_id": "req_452421dea5734da2868081f18a75e6fe", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_d03f85528e3842d3996379ad603bc59c", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1690361721223, "created": 1681911985730, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations/request", @@ -2894,8 +2831,8 @@ "_type": "request" }, { - "_id": "req_7852cfb1b84d4ef585c3b674703e7f1e", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_d7fbd989cc994daa95309f4ddd6f881a", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1691578311420, "created": 1675675609541, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/transferprocesses", @@ -2931,8 +2868,8 @@ "_type": "request" }, { - "_id": "req_899e227f501b40259260d3dcb95eaca1", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_9e9929d09f944df7ad5a2caff837bea7", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1691503370103, "created": 1679993996270, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/transferprocesses/{% prompt 'id', '', '', '', false, true %}", @@ -2965,8 +2902,8 @@ "_type": "request" }, { - "_id": "req_362e6ed4968e4ac8b619c86091f3b73d", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_593cc5984c8e4fc983193582d2ca91da", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1690361795179, "created": 1675675609525, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/transferprocesses/request", @@ -3002,8 +2939,8 @@ "_type": "request" }, { - "_id": "req_1ee05f63f5484782802d69c3fd243321", - "parentId": "fld_bd70e484a29f4b76a6ee0750f33ff878", + "_id": "req_a733261194a845e4b83881e53d7c2c21", + "parentId": "fld_f277ccd7006d4c5981445ea5824d5e80", "modified": 1690361763512, "created": 1681910653593, "url": "{{CONSUMER_CONTROLPLANE}}/management/v2/contractagreements/request", @@ -3039,8 +2976,8 @@ "_type": "request" }, { - "_id": "req_f243a1f0fc1b44d6b56ec8b870009292", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_29f76c4a062d4454adb221a2e579a1ea", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362947546, "created": 1681907482278, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets", @@ -3076,8 +3013,8 @@ "_type": "request" }, { - "_id": "fld_e8032633835c44fdbc7d9560a86c7418", - "parentId": "fld_f8dea31e10f445708d36c2244897cf08", + "_id": "fld_05a20c665a3d49568079f982c40d923c", + "parentId": "fld_8b90eb2a99354ecdb14805791a34fbaa", "modified": 1684146621298, "created": 1684146457388, "name": "Provider", @@ -3088,8 +3025,8 @@ "_type": "request_group" }, { - "_id": "req_a0b4406e7f684608b27e134d96773527", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_43c51a693ddb4498846e4711e684bc40", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362407763, "created": 1685444139630, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets/{% prompt 'id', '', '', '', false, true %}", @@ -3117,8 +3054,8 @@ "_type": "request" }, { - "_id": "req_199174c5910d48098078adb952355b0b", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_8956d72e30364f2dbb8171daecd01f33", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362438115, "created": 1685444139625, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets/request", @@ -3154,8 +3091,8 @@ "_type": "request" }, { - "_id": "req_d953ff0384684fdcb7ac68aab5b599e9", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_023a617fd5af41d782a2715fe5d81706", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362400081, "created": 1685444139636, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets/{% prompt 'id', '', '', '', false, true %}", @@ -3183,8 +3120,8 @@ "_type": "request" }, { - "_id": "req_3c2f9830ee4d4ce889f4355fc739e800", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_a6217da8bcfb4f60b3f54ccae9ef6657", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362581978, "created": 1685444139641, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions", @@ -3220,8 +3157,8 @@ "_type": "request" }, { - "_id": "req_b647a877abad40499106f0597ec3c6e9", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_b951acf896b54364a912cb609440ce2d", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362549290, "created": 1685444139647, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3249,8 +3186,8 @@ "_type": "request" }, { - "_id": "req_6856fb9a7df2479594a10b5f7e5f5222", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_a2c87a2e2ec64753a8d09ce6a9bcde78", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362591799, "created": 1685444139653, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions/request", @@ -3286,8 +3223,8 @@ "_type": "request" }, { - "_id": "req_764f4b4d89ae404987e5dfeb096042b9", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_2bcbcdb6b42c4271bc6e3c01d08c4799", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362559324, "created": 1685444139659, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3315,8 +3252,8 @@ "_type": "request" }, { - "_id": "req_240c7fb162414bb1b1afaa4ae0ae4c91", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_18d8ac1065e74df58d46c70423298692", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690363080444, "created": 1685444139665, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions", @@ -3352,8 +3289,8 @@ "_type": "request" }, { - "_id": "req_6e828c55562f411894f470ecf3b34f0d", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_58945d6b76824b07886e2e055341d319", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690362691392, "created": 1685444139672, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3381,8 +3318,8 @@ "_type": "request" }, { - "_id": "req_5c2ea72a67064a44997bef55fdccb321", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_95d0490f4cd34a88b0cb459b28532b94", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690363126919, "created": 1685444139678, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions/request", @@ -3418,8 +3355,8 @@ "_type": "request" }, { - "_id": "req_bf5e0064bb994fafaf4343cab248395e", - "parentId": "fld_e8032633835c44fdbc7d9560a86c7418", + "_id": "req_8387ed4780104d18b357d9abe6f20f66", + "parentId": "fld_05a20c665a3d49568079f982c40d923c", "modified": 1690363136216, "created": 1685444139684, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3470,7 +3407,7 @@ { "_id": "jar_d2b7eb1621841465ea24b73343568b286aa8ac9a", "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", - "modified": 1696335454338, + "modified": 1702554690714, "created": 1680782486851, "name": "Default Jar", "cookies": [ @@ -3486,8 +3423,8 @@ ], "hostOnly": true, "creation": "2023-04-06T13:30:18.499Z", - "lastAccessed": "2023-10-03T12:17:34.338Z", - "id": "8321371195331124" + "lastAccessed": "2023-12-14T11:51:30.713Z", + "id": "05576732916905858" } ], "_type": "cookie_jar" @@ -3513,4 +3450,4 @@ "_type": "api_spec" } ] -} +} \ No newline at end of file diff --git a/local/testing/IRS_TEMPLATE_environment.json b/local/testing/IRS_TEMPLATE_environment.json index 70a5ba5206..a6b7306e1a 100644 --- a/local/testing/IRS_TEMPLATE_environment.json +++ b/local/testing/IRS_TEMPLATE_environment.json @@ -3,6 +3,8 @@ "OAUTH2_TOKEN_URL": "", "CLIENT_ID": "", "CLIENT_SECRET": "", + "ADMIN_API_KEY": "", + "REGULAR_API_KEY": "", "DIGITAL_TWIN_REGISTRY": "", "GLOBAL_ASSET_ID": "", "BPN": "", From f96b7ba2677cc4d7b38845f9a6e83c3d1c71929d Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Tue, 19 Dec 2023 14:36:19 +0100 Subject: [PATCH 32/59] feat(impl):[#259] review comments --- docs/src/docs/administration/configuration.adoc | 2 +- irs-api/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/docs/administration/configuration.adoc b/docs/src/docs/administration/configuration.adoc index cd43d249f9..63774dae18 100644 --- a/docs/src/docs/administration/configuration.adoc +++ b/docs/src/docs/administration/configuration.adoc @@ -89,7 +89,7 @@ When IRS calls EDC Discovery Service to fetch connector endpoints for BPNLs, the This parameter define how long cache is maintained before it is cleared. Data is in ISO 8601. == OAuth2 Configuration -Previously, OAuth2 protocol was used by IRS to protect the APIs and other resources. As reference, latest IRS version that supported OAuth2 protocol was 4.3.0, which can be found here: https://github.com/catenax-ng/tx-item-relationship-service/releases/tag/4.3.0. +Previously, OAuth2 protocol was used by IRS to protect the APIs and other resources. As reference, latest IRS version that supported OAuth2 protocol was 4.3.0, which can be found here: https://github.com/eclipse-tractusx/item-relationship-service/releases/tag/4.3.0. === Semantic Model Provisioning The IRS can retrieve semantic models in two ways: diff --git a/irs-api/pom.xml b/irs-api/pom.xml index 91ee09f483..0311677617 100644 --- a/irs-api/pom.xml +++ b/irs-api/pom.xml @@ -206,7 +206,7 @@ io.rest-assured rest-assured - 5.4.0 + ${rest-assured.version} test diff --git a/pom.xml b/pom.xml index 8529dfd266..6209740883 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.9.5 2.1.0 8.5.6 - 5.3.0 + 5.4.0 4.2.0 5.9.2 7.11.1 From 3ff7a7adbaf8c1a2ee380ee59f0a502541ad6349 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Tue, 19 Dec 2023 15:24:15 +0100 Subject: [PATCH 33/59] feat(impl):[#259] update deps --- DEPENDENCIES | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 8aad831afb..569f262a10 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -161,14 +161,13 @@ maven/mavencentral/io.prometheus/simpleclient_common/0.16.0, Apache-2.0, approve maven/mavencentral/io.prometheus/simpleclient_tracer_common/0.16.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.prometheus/simpleclient_tracer_otel/0.16.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.prometheus/simpleclient_tracer_otel_agent/0.16.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/io.rest-assured/json-path/5.3.0, Apache-2.0, approved, #9261 maven/mavencentral/io.rest-assured/json-path/5.3.2, Apache-2.0, approved, #9261 -maven/mavencentral/io.rest-assured/rest-assured-common/5.3.0, Apache-2.0, approved, #9264 +maven/mavencentral/io.rest-assured/json-path/5.4.0, Apache-2.0, approved, #12042 maven/mavencentral/io.rest-assured/rest-assured-common/5.3.2, Apache-2.0, approved, #9264 -maven/mavencentral/io.rest-assured/rest-assured/5.3.0, Apache-2.0, approved, #9262 +maven/mavencentral/io.rest-assured/rest-assured-common/5.4.0, Apache-2.0, approved, #12039 maven/mavencentral/io.rest-assured/rest-assured/5.4.0, Apache-2.0, approved, #12040 -maven/mavencentral/io.rest-assured/xml-path/5.3.0, Apache-2.0, approved, #9267 maven/mavencentral/io.rest-assured/xml-path/5.3.2, Apache-2.0, approved, #9267 +maven/mavencentral/io.rest-assured/xml-path/5.4.0, Apache-2.0, approved, #12038 maven/mavencentral/io.suzaku/boopickle_2.13/1.3.3, Apache-2.0, approved, clearlydefined maven/mavencentral/io.swagger.core.v3/swagger-annotations-jakarta/2.2.15, Apache-2.0, approved, #5947 maven/mavencentral/io.swagger.core.v3/swagger-annotations/2.2.16, Apache-2.0, approved, #11362 From 7a3c62656837b144c3997cebe0919166cda7328b Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Wed, 20 Dec 2023 11:36:50 +0100 Subject: [PATCH 34/59] feat(impl):[#259] remove owned field from Job --- docs/src/api/irs-api.yaml | 9 ---- .../irs/configuration/OpenApiExamples.java | 7 ---- .../irs/connector/job/JobOrchestrator.java | 8 ++-- .../tractusx/irs/ess/service/EssService.java | 8 ---- .../services/IrsItemGraphQueryService.java | 19 +-------- .../tractusx/irs/IrsApplicationTests.java | 2 +- .../tractusx/irs/IrsFunctionalTest.java | 1 - .../connector/job/JobOrchestratorTest.java | 14 +++---- .../irs/ess/service/EssServiceTest.java | 25 ++++------- .../IrsItemGraphQueryServiceTest.java | 42 ++----------------- .../eclipse/tractusx/irs/util/TestMother.java | 1 - .../eclipse/tractusx/irs/component/Job.java | 6 --- 12 files changed, 24 insertions(+), 118 deletions(-) diff --git a/docs/src/api/irs-api.yaml b/docs/src/api/irs-api.yaml index 1a7849be24..67879e47ea 100644 --- a/docs/src/api/irs-api.yaml +++ b/docs/src/api/irs-api.yaml @@ -992,7 +992,6 @@ components: globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0 id: e5347c88-a921-11ec-b909-0242ac120002 lastModifiedOn: 2022-02-03T14:48:54.709Z - owner: "" parameter: aspects: - SerialPart @@ -1043,7 +1042,6 @@ components: globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0 id: e5347c88-a921-11ec-b909-0242ac120002 lastModifiedOn: 2022-02-03T14:48:54.709Z - owner: "" parameter: aspects: - SerialPart @@ -1166,7 +1164,6 @@ components: globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0 id: e5347c88-a921-11ec-b909-0242ac120002 lastModifiedOn: 2022-02-03T14:48:54.709Z - owner: "" parameter: aspects: - SerialPart @@ -1317,7 +1314,6 @@ components: globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0 id: e5347c88-a921-11ec-b909-0242ac120002 lastModifiedOn: 2022-02-03T14:48:54.709Z - owner: "" parameter: aspects: - SerialPart @@ -1355,7 +1351,6 @@ components: globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0 id: e5347c88-a921-11ec-b909-0242ac120002 lastModifiedOn: 2022-02-03T14:48:54.709Z - owner: "" parameter: aspects: - SerialPart @@ -1470,7 +1465,6 @@ components: globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0 id: e5347c88-a921-11ec-b909-0242ac120002 lastModifiedOn: 2022-02-03T14:48:54.709Z - owner: "" parameter: aspects: - SerialPart @@ -1918,9 +1912,6 @@ components: type: string format: date-time example: 2022-02-03T14:48:54.709Z - owner: - type: string - description: The IRS api consumer. parameter: $ref: '#/components/schemas/JobParameter' startedOn: diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/OpenApiExamples.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/OpenApiExamples.java index 18ded7e627..07e90bae69 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/OpenApiExamples.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/OpenApiExamples.java @@ -175,7 +175,6 @@ private Example createFailedJobResult() { .id(UUID.fromString(JOB_ID)) .globalAssetId(createGAID(GLOBAL_ASSET_ID)) .state(JobState.ERROR) - .owner("") .createdOn(EXAMPLE_ZONED_DATETIME) .startedOn(EXAMPLE_ZONED_DATETIME) .lastModifiedOn(EXAMPLE_ZONED_DATETIME) @@ -192,7 +191,6 @@ private Example createPartialJobResult() { .id(UUID.fromString(JOB_ID)) .globalAssetId(createGAID(GLOBAL_ASSET_ID)) .state(JobState.RUNNING) - .owner("") .createdOn(EXAMPLE_ZONED_DATETIME) .startedOn(EXAMPLE_ZONED_DATETIME) .lastModifiedOn(EXAMPLE_ZONED_DATETIME) @@ -235,12 +233,10 @@ private Example createCompleteJobResult() { .id(UUID.fromString(JOB_ID)) .globalAssetId(createGAID(GLOBAL_ASSET_ID)) .state(JobState.COMPLETED) - .owner("") .createdOn(EXAMPLE_ZONED_DATETIME) .startedOn(EXAMPLE_ZONED_DATETIME) .lastModifiedOn(EXAMPLE_ZONED_DATETIME) .completedOn(EXAMPLE_ZONED_DATETIME) - .owner("") .summary(createSummary()) .parameter(createJobParameter()) .exception(createJobException()) @@ -259,12 +255,10 @@ private Example createCompleteEssJobResult() { .id(UUID.fromString(JOB_ID)) .globalAssetId(createGAID(GLOBAL_ASSET_ID)) .state(JobState.COMPLETED) - .owner("") .createdOn(EXAMPLE_ZONED_DATETIME) .startedOn(EXAMPLE_ZONED_DATETIME) .lastModifiedOn(EXAMPLE_ZONED_DATETIME) .completedOn(EXAMPLE_ZONED_DATETIME) - .owner("") .summary(createSummary()) .parameter(createJobParameter()) .exception(createJobException()) @@ -484,7 +478,6 @@ private Example createCanceledJobResult() { .id(UUID.fromString(JOB_ID)) .globalAssetId(createGAID(GLOBAL_ASSET_ID)) .state(JobState.CANCELED) - .owner("") .createdOn(EXAMPLE_ZONED_DATETIME) .startedOn(EXAMPLE_ZONED_DATETIME) .lastModifiedOn(EXAMPLE_ZONED_DATETIME) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/job/JobOrchestrator.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/job/JobOrchestrator.java index 1f3db74077..72c4419967 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/job/JobOrchestrator.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/job/JobOrchestrator.java @@ -110,11 +110,10 @@ public JobOrchestrator(final TransferProcessManager processManager, final * @param globalAssetId root id * @param jobData additional data for the job to be managed by the {@link JobStore}. * @param batchId batch id - * @param owner owner * @return response. */ - public JobInitiateResponse startJob(final String globalAssetId, final JobParameter jobData, final UUID batchId, final String owner) { - final Job job = createJob(globalAssetId, jobData, owner); + public JobInitiateResponse startJob(final String globalAssetId, final JobParameter jobData, final UUID batchId) { + final Job job = createJob(globalAssetId, jobData); final var multiJob = MultiTransferJob.builder().job(job).batchId(Optional.ofNullable(batchId)).build(); jobStore.create(multiJob); @@ -281,7 +280,7 @@ private TransferInitiateResponse startTransfer(final MultiTransferJob job, return response; } - private Job createJob(final String globalAssetId, final JobParameter jobData, final String owner) { + private Job createJob(final String globalAssetId, final JobParameter jobData) { if (StringUtils.isEmpty(globalAssetId)) { throw new JobException("GlobalAsset Identifier cannot be null or empty string"); } @@ -292,7 +291,6 @@ private Job createJob(final String globalAssetId, final JobParameter jobData, fi .createdOn(ZonedDateTime.now(ZoneOffset.UTC)) .lastModifiedOn(ZonedDateTime.now(ZoneOffset.UTC)) .state(JobState.UNSAVED) - .owner(owner) .parameter(jobData) .build(); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java index e260de0ccb..a3336877ac 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java @@ -87,14 +87,6 @@ public Jobs getIrsJob(final String jobId) { if (job.isPresent()) { final BpnInvestigationJob bpnInvestigationJob = job.get(); - if (!securityHelperService.isAdmin() && !bpnInvestigationJob.getJobSnapshot() - .getJob() - .getOwner() - .equals(securityHelperService.getClientIdForViewIrs())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN, - "Cannot access investigation job with id " + jobId + " due to missing privileges."); - } - return updateState(bpnInvestigationJob); } else { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No investigation job exists with id " + jobId); diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java index e04a8fa644..7c144ed53b 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java @@ -147,12 +147,7 @@ public PageResult getJobsByState(@NonNull final List states, final Pag } private List filterJobs(final @NotNull List states) { - final List jobs = states.isEmpty() ? jobStore.findAll() : jobStore.findByStates(states); - if (securityHelperService.isAdmin()) { - return jobs; - } else { - return jobs.stream().filter(multiJob -> multiJob.getJob().getOwner().equals(securityHelperService.getClientIdForViewIrs())).toList(); - } + return states.isEmpty() ? jobStore.findAll() : jobStore.findByStates(states); } private PagedListHolder paginateAndSortResults(final Pageable pageable, @@ -190,7 +185,7 @@ public JobHandle registerItemJob(final @NonNull RegisterJob request, final UUID validateAspectTypeValues(params.getAspects()); final JobInitiateResponse jobInitiateResponse = orchestrator.startJob(request.getKey().getGlobalAssetId(), - params, batchId, owner); + params, batchId); meterRegistryService.incrementNumberOfCreatedJobs(); if (jobInitiateResponse.getStatus().equals(ResponseStatus.OK)) { @@ -230,11 +225,6 @@ public Job cancelJobById(final @NonNull UUID jobId) { final String idAsString = String.valueOf(jobId); final Optional canceled = this.jobStore.cancelJob(idAsString); - canceled.ifPresent(cancelledJob -> { - if (!securityHelperService.isAdmin() && !cancelledJob.getJob().getOwner().equals(securityHelperService.getClientIdForViewIrs())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Cannot access and cancel job with id " + jobId + " due to missing privileges."); - } - }); canceled.ifPresent(cancelledJob -> applicationEventPublisher.publishEvent( new JobProcessingFinishedEvent(cancelledJob.getJobIdString(), cancelledJob.getJob().getState().name(), cancelledJob.getJobParameter().getCallbackUrl(), cancelledJob.getBatchId()))); @@ -250,11 +240,6 @@ public Jobs getJobForJobId(final UUID jobId, final boolean includePartialResults if (multiTransferJob.isPresent()) { final MultiTransferJob multiJob = multiTransferJob.get(); - - if (!securityHelperService.isAdmin() && !multiJob.getJob().getOwner().equals(securityHelperService.getClientIdForViewIrs())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Cannot access job with id " + jobId + " due to missing privileges."); - } - return getJobForJobId(multiJob, includePartialResults); } else { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No job exists with id " + jobId); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsApplicationTests.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsApplicationTests.java index 5f14c3426a..e387822b3b 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsApplicationTests.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsApplicationTests.java @@ -96,7 +96,7 @@ void shouldStoreBlobResultWhenRunningJob() throws Exception { .aspects(List.of()) .build(); - final JobInitiateResponse response = jobOrchestrator.startJob("rootitemid", jobParameter, null, "owner"); + final JobInitiateResponse response = jobOrchestrator.startJob("rootitemid", jobParameter, null); assertThat(response.getStatus()).isEqualTo(ResponseStatus.OK); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java index 0a51ec40a3..e1d07cf7f5 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java @@ -123,7 +123,6 @@ void shouldStartJobAndRetrieveResult() { assertThat(finishedJob.get().getJob()).isNotNull(); assertThat(finishedJob.get().getJob().getSummary()).isNotNull(); assertThat(finishedJob.get().getJob().getParameter()).isNotNull(); - assertThat(finishedJob.get().getJob().getOwner()).isNotBlank(); } @Test diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/connector/job/JobOrchestratorTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/connector/job/JobOrchestratorTest.java index e417687f32..9565275c62 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/connector/job/JobOrchestratorTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/connector/job/JobOrchestratorTest.java @@ -92,8 +92,6 @@ class JobOrchestratorTest { TransferInitiateResponse okResponse2 = generate.okResponse(); TransferProcess transfer = generate.transfer(); - private static final String owner = "owner"; - @Test void startJob_storesJobWithDataAndState() { MultiTransferJob job2 = startJob(); @@ -146,7 +144,7 @@ void startJob_WithZeroDataRequest_CompletesJob() { // Arrange when(handler.initiate(any(MultiTransferJob.class))).thenReturn(Stream.empty()); - var response = sut.startJob(job.getGlobalAssetId(), job.getJob().getParameter(), null, owner); + var response = sut.startJob(job.getGlobalAssetId(), job.getJob().getParameter(), null); var newJob = getStartedJob(); // Assert @@ -166,7 +164,7 @@ void startJob_WithSuccessfulTransferStarts_ReturnsOk() { when(processManager.initiateRequest(eq(dataRequest), any(), any(), eq(jobParameter()))).thenReturn(okResponse); // Act - var response = sut.startJob(job.getGlobalAssetId(), job.getJob().getParameter(), null, owner); + var response = sut.startJob(job.getGlobalAssetId(), job.getJob().getParameter(), null); // Assert var newJob = getStartedJob(); @@ -183,7 +181,7 @@ void startJob_WhenTransferStartUnsuccessful_Abort(ResponseStatus status) { generate.response(status)); // Act - var response = sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null, owner); + var response = sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null); // Assert verify(processManager).initiateRequest(eq(dataRequest), any(), any(), eq(jobParameter())); @@ -203,7 +201,7 @@ void startJob_WhenHandlerInitiateThrows_StopJob() { when(handler.initiate(any(MultiTransferJob.class))).thenThrow(new RuntimeException()); // Act - var response = sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null, owner); + var response = sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null); // Assert verify(jobStore).create(jobCaptor.capture()); @@ -225,7 +223,7 @@ void startJob_WhenHandlerJobExceptioWithParamter_StopJob() { when(handler.initiate(any(MultiTransferJob.class))).thenThrow(new JobException("Cannot process the request")); // Act - var response = sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null, owner); + var response = sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null); // Assert verify(jobStore).create(jobCaptor.capture()); @@ -393,7 +391,7 @@ private Object byCompletingJob() { } private MultiTransferJob startJob() { - sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null, owner); + sut.startJob(job.getGlobalAssetId(), job.getJobParameter(), null); return getStartedJob(); } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java index c5eab5527d..c14bb816c4 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java @@ -38,7 +38,6 @@ import java.util.Optional; import java.util.UUID; -import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.eclipse.tractusx.irs.common.auth.SecurityHelperService; import org.eclipse.tractusx.irs.component.GlobalAssetIdentification; import org.eclipse.tractusx.irs.component.Job; @@ -90,7 +89,6 @@ void shouldSuccessfullyStartJobAndReturnWithExtendedSubmodelList() { .job(Job.builder() .state(JobState.COMPLETED) .id(createdJobId) - .owner(IrsRoles.VIEW_IRS) .globalAssetId(GlobalAssetIdentification.of(globalAssetId)) .build()) .submodels(new ArrayList<>()) @@ -116,7 +114,6 @@ void shouldUpdateJobSnapshotIfNotificationFound() { final String notificationId = UUID.randomUUID().toString(); final String notificationId2 = UUID.randomUUID().toString(); final UUID jobId = UUID.randomUUID(); - final String owner = securityHelperService.getClientIdClaim(); final ResponseNotificationContent resultNo = ResponseNotificationContent.builder().result("No").hops(0).bpn("bot-impacted-bpn").build(); final EdcNotificationHeader header1 = EdcNotificationHeader.builder() @@ -138,7 +135,7 @@ void shouldUpdateJobSnapshotIfNotificationFound() { .build(); final BpnInvestigationJob bpnInvestigationJob = new BpnInvestigationJob( - Jobs.builder().job(Job.builder().id(jobId).owner(owner).build()).build(), + Jobs.builder().job(Job.builder().id(jobId).build()).build(), new ArrayList<>()).withUnansweredNotifications(List.of(new Notification(notificationId, "bpn"), new Notification(notificationId2, "bpn"))); bpnInvestigationJobCache.store(jobId, bpnInvestigationJob); @@ -176,7 +173,6 @@ void shouldReturnCorrectFirstLevelImpactedSupplierBpnAndHopsNumberWhenImpactedSu final UUID jobId = UUID.randomUUID(); final UUID jobId2 = UUID.randomUUID(); final UUID jobId3 = UUID.randomUUID(); - final String owner = securityHelperService.getClientIdClaim(); final String bpnLevel0 = "bpn-level-0"; final String bpnLevel1 = "bpn-level-1"; @@ -203,17 +199,17 @@ void shouldReturnCorrectFirstLevelImpactedSupplierBpnAndHopsNumberWhenImpactedSu .build(); final BpnInvestigationJob bpnInvestigationJob = new BpnInvestigationJob( - Jobs.builder().job(Job.builder().id(jobId).owner(owner).build()).build(), + Jobs.builder().job(Job.builder().id(jobId).build()).build(), new ArrayList<>()).withUnansweredNotifications(List.of(new Notification(notificationId, bpnLevel1))); bpnInvestigationJobCache.store(jobId, bpnInvestigationJob); final BpnInvestigationJob bpnInvestigationJob2 = new BpnInvestigationJob( - Jobs.builder().job(Job.builder().id(jobId2).owner(owner).build()).build(), + Jobs.builder().job(Job.builder().id(jobId2).build()).build(), new ArrayList<>()).withUnansweredNotifications(List.of(new Notification(notificationId2, bpnLevel2))); bpnInvestigationJobCache.store(jobId2, bpnInvestigationJob2); final BpnInvestigationJob bpnInvestigationJob3 = new BpnInvestigationJob( - Jobs.builder().job(Job.builder().id(jobId3).owner(owner).build()).build(), + Jobs.builder().job(Job.builder().id(jobId3).build()).build(), new ArrayList<>()); bpnInvestigationJobCache.store(jobId3, bpnInvestigationJob3); @@ -239,11 +235,10 @@ void shouldReturnCorrectFirstLevelImpactedSupplierBpnAndHopsNumberWhenImpactedSu void shouldKeepJobInRunningIfNotificationIsOpen() { final String notificationId = UUID.randomUUID().toString(); final UUID jobId = UUID.randomUUID(); - final String owner = securityHelperService.getClientIdClaim(); when(securityHelperService.isAdmin()).thenReturn(true); final BpnInvestigationJob bpnInvestigationJob = new BpnInvestigationJob( - Jobs.builder().job(Job.builder().id(jobId).owner(owner).build()).build(), + Jobs.builder().job(Job.builder().id(jobId).build()).build(), new ArrayList<>()).withUnansweredNotifications(Collections.singletonList(new Notification(notificationId, "bpn"))); bpnInvestigationJobCache.store(jobId, bpnInvestigationJob); @@ -263,11 +258,10 @@ void shouldThrowResponseStatusExceptionWhenIdDoesntExists() { void shouldCompleteJobIfAllNotificationsSentWereAnswered() { // Arrange final String notificationId = UUID.randomUUID().toString(); - final String owner = securityHelperService.getClientIdClaim(); when(securityHelperService.isAdmin()).thenReturn(true); final UUID jobId = UUID.randomUUID(); - final Jobs jobSnapshot = job(jobId, owner); + final Jobs jobSnapshot = job(jobId); final EdcNotification answeredNotification = EdcNotification.builder() .header(EdcNotificationHeader.builder() .notificationId( @@ -294,11 +288,10 @@ void shouldCompleteJobIfAllNotificationsSentWereAnswered() { @Test void shouldCompleteJobIfFinalNotificationWasReceived() { // Arrange - final String owner = securityHelperService.getClientIdClaim(); when(securityHelperService.isAdmin()).thenReturn(true); final UUID jobId = UUID.randomUUID(); - final Jobs jobSnapshot = job(jobId, owner); + final Jobs jobSnapshot = job(jobId); final String notificationId = UUID.randomUUID().toString(); final BpnInvestigationJob bpnInvestigationJob = new BpnInvestigationJob(jobSnapshot, null).update(jobSnapshot, SupplyChainImpacted.NO).withUnansweredNotifications(List.of(new Notification(notificationId, "bpn"))); @@ -324,8 +317,8 @@ void shouldCompleteJobIfFinalNotificationWasReceived() { assertThat(jobAfterNotificationReceive.getJob().getState()).isEqualTo(JobState.COMPLETED); } - private Jobs job(final UUID jobId, final String owner) { - final Job job = Job.builder().id(jobId).owner(owner).build(); + private Jobs job(final UUID jobId) { + final Job job = Job.builder().id(jobId).build(); return Jobs.builder().job(job).build(); } } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceTest.java index 9f015bf94d..000c39ccba 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceTest.java @@ -29,8 +29,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -42,7 +40,8 @@ import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; -import org.eclipse.tractusx.irs.common.auth.IrsRoles; +import org.eclipse.tractusx.irs.common.persistence.BlobPersistence; +import org.eclipse.tractusx.irs.common.persistence.BlobPersistenceException; import org.eclipse.tractusx.irs.component.Job; import org.eclipse.tractusx.irs.component.Jobs; import org.eclipse.tractusx.irs.component.PageResult; @@ -50,8 +49,6 @@ import org.eclipse.tractusx.irs.component.enums.JobState; import org.eclipse.tractusx.irs.connector.job.JobStore; import org.eclipse.tractusx.irs.connector.job.MultiTransferJob; -import org.eclipse.tractusx.irs.common.persistence.BlobPersistence; -import org.eclipse.tractusx.irs.common.persistence.BlobPersistenceException; import org.eclipse.tractusx.irs.semanticshub.AspectModel; import org.eclipse.tractusx.irs.semanticshub.AspectModels; import org.eclipse.tractusx.irs.semanticshub.SemanticsHubFacade; @@ -67,11 +64,6 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.web.server.ResponseStatusException; @ExtendWith(MockitoExtension.class) @@ -98,7 +90,6 @@ class IrsItemGraphQueryServiceTest { @Test void registerItemJobWithoutDepthShouldBuildFullTree() throws Exception { // given - setupSecurityContextWithRole(IrsRoles.ADMIN_IRS); final var jobId = UUID.randomUUID(); final AASTransferProcess transfer1 = generate.aasTransferProcess(); givenTransferResultIsStored(transfer1); @@ -135,8 +126,6 @@ private byte[] toBlob(final Object transfer) { @Test void cancelJobById() { - setupSecurityContextWithRole(IrsRoles.ADMIN_IRS); - final Job job = generate.fakeJob(JobState.CANCELED); final MultiTransferJob multiTransferJob = MultiTransferJob.builder().job(job).build(); @@ -148,18 +137,6 @@ void cancelJobById() { assertEquals(canceledJob.getState().name(), JobState.CANCELED.name()); } - @Test - void shouldThrowForbiddenExceptionWhenCancelingAnotherOwnerJob() { - setupSecurityContextWithRole(IrsRoles.VIEW_IRS); - - final Job job = generate.fakeJob(JobState.CANCELED); - - final MultiTransferJob multiTransferJob = MultiTransferJob.builder().job(job).build(); - when(jobStore.cancelJob(jobId.toString())).thenReturn(Optional.ofNullable(multiTransferJob)); - - assertThrows(ResponseStatusException.class, () -> testee.cancelJobById(jobId)); - } - @Test void cancelJobById_throwEntityNotFoundException() { when(jobStore.cancelJob(jobId.toString())).thenThrow( @@ -170,7 +147,6 @@ void cancelJobById_throwEntityNotFoundException() { @Test void shouldReturnFoundJobs() { - setupSecurityContextWithRole(IrsRoles.ADMIN_IRS); final List states = List.of(JobState.COMPLETED); final MultiTransferJob multiTransferJob = MultiTransferJob.builder() .job(generate.fakeJob(JobState.COMPLETED)) @@ -194,7 +170,6 @@ void shouldReturnFoundJobs() { @Test void shouldTakeAllJobsWhenBothListEmpty() { final List states = List.of(); - final List jobStates = List.of(); testee.getJobsByState(states, Pageable.ofSize(10)); @@ -227,21 +202,10 @@ void shouldThrowExceptionForUnknownAspectTypes() throws SchemaNotFoundException } @Test - void shouldThrowExceptionWhenLookupBpnAndBpdmEndpointUrlIsMissing() throws SchemaNotFoundException { + void shouldThrowExceptionWhenLookupBpnAndBpdmEndpointUrlIsMissing() { final Executable executable = () -> testee.registerItemJob(registerJobWithLookupBPNs()); assertThrows(ResponseStatusException.class, executable); } - private static void setupSecurityContextWithRole(final String irsRole) { - JwtAuthenticationToken jwtAuthenticationToken = mock(JwtAuthenticationToken.class); - Jwt token = mock(Jwt.class); - when(jwtAuthenticationToken.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority(irsRole))); - lenient().when(jwtAuthenticationToken.getToken()).thenReturn(token); - lenient().when(token.getClaim("clientId")).thenReturn("test-client-id"); - SecurityContext securityContext = mock(SecurityContext.class); - when(securityContext.getAuthentication()).thenReturn(jwtAuthenticationToken); - SecurityContextHolder.setContext(securityContext); - } - } \ No newline at end of file diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/util/TestMother.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/util/TestMother.java index 09cdaf4212..9b01459399 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/util/TestMother.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/util/TestMother.java @@ -273,7 +273,6 @@ public Job fakeJob(final JobState state) { .state(state) .createdOn(ZonedDateTime.now(ZoneId.of("UTC"))) .startedOn(ZonedDateTime.now(ZoneId.of("UTC"))) - .owner(faker.lorem().characters()) .lastModifiedOn(ZonedDateTime.now(ZoneId.of("UTC"))) .parameter(jobParameter()) .completedOn(ZonedDateTime.now(ZoneId.of("UTC"))) diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Job.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Job.java index af1f037c9b..95843ba8be 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Job.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Job.java @@ -100,12 +100,6 @@ public class Job { @JsonAlias("jobCompleted") private ZonedDateTime completedOn; - /** - * Owner of the job - */ - @Schema(description = "The IRS api consumer.") - private String owner; - @Schema(description = "Summary of the job with statistics of the job processing.", implementation = Summary.class) private Summary summary; From 0b4f6675b7f6854ca44c4d2a7e06f82e9ea7aac0 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Wed, 20 Dec 2023 11:49:44 +0100 Subject: [PATCH 35/59] feat(impl):[#259] remove owned field from Batches --- .../tractusx/irs/connector/batch/Batch.java | 5 -- .../irs/connector/batch/BatchOrder.java | 2 - .../tractusx/irs/ess/service/EssService.java | 6 +- .../irs/services/BatchOrderEventListener.java | 6 +- .../irs/services/CreationBatchService.java | 7 +- .../services/IrsItemGraphQueryService.java | 4 +- .../irs/services/QueryBatchService.java | 9 --- .../irs/ess/service/EssServiceTest.java | 2 +- .../services/BatchOrderEventListenerTest.java | 16 +--- .../services/CreationBatchServiceTest.java | 2 +- .../irs/services/QueryBatchServiceTest.java | 7 +- .../common/auth/SecurityHelperService.java | 39 +--------- .../auth/SecurityHelperServiceTest.java | 77 ++----------------- 13 files changed, 27 insertions(+), 155 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/Batch.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/Batch.java index 340bed63d6..f057bf6eac 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/Batch.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/Batch.java @@ -92,9 +92,4 @@ public class Batch { @Setter private ZonedDateTime completedOn; - /** - * Owner - */ - private String owner; - } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/BatchOrder.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/BatchOrder.java index 9d47f918f0..f28b9e0214 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/BatchOrder.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/connector/batch/BatchOrder.java @@ -67,8 +67,6 @@ public class BatchOrder { private String callbackUrl; - private String owner; - private List incidentBPNSs; private JobType jobType; diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java index a3336877ac..419fb15148 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EssService.java @@ -64,12 +64,12 @@ public class EssService { private final EssRecursiveNotificationHandler recursiveNotificationHandler; public JobHandle startIrsJob(final RegisterBpnInvestigationJob request) { - return startIrsJob(request, null, securityHelperService.getClientIdClaim()); + return startIrsJob(request, null); } - public JobHandle startIrsJob(final RegisterBpnInvestigationJob request, final UUID batchId, final String owner) { + public JobHandle startIrsJob(final RegisterBpnInvestigationJob request, final UUID batchId) { final JobHandle jobHandle = irsItemGraphQueryService.registerItemJob( - bpnInvestigations(request.getKey(), request.getBomLifecycle()), batchId, owner); + bpnInvestigations(request.getKey(), request.getBomLifecycle()), batchId); final UUID createdJobId = jobHandle.getId(); final Optional multiTransferJob = jobStore.find(createdJobId.toString()); diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/BatchOrderEventListener.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/BatchOrderEventListener.java index 97adc7b007..74d81b0770 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/BatchOrderEventListener.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/BatchOrderEventListener.java @@ -121,7 +121,7 @@ private void startBatch(final BatchOrder batchOrder, final Batch batch) { .map(identificationKey -> createRegisterJob(batchOrder, identificationKey)) .map(registerJob -> createJobProgress( irsItemGraphQueryService.registerItemJob(registerJob, - batch.getBatchId(), batch.getOwner()), + batch.getBatchId()), registerJob.getKey())) .toList()); } else if (batchOrder.getJobType().equals(BatchOrder.JobType.ESS)) { @@ -129,8 +129,8 @@ private void startBatch(final BatchOrder batchOrder, final Batch batch) { .map(identificationKey -> createRegisterBpnInvestigationBatchOrder( batchOrder, identificationKey)) .map(registerJob -> createJobProgress( - essService.startIrsJob(registerJob, batch.getBatchId(), - batch.getOwner()), registerJob.getKey())) + essService.startIrsJob(registerJob, batch.getBatchId()), + registerJob.getKey())) .toList()); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/CreationBatchService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/CreationBatchService.java index 7a7df52b6f..a7e4c0851d 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/CreationBatchService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/CreationBatchService.java @@ -77,7 +77,6 @@ public UUID create(final RegisterBatchOrder request) { .timeout(request.getTimeout()) .jobTimeout(request.getJobTimeout()) .callbackUrl(request.getCallbackUrl()) - .owner(securityHelperService.getClientIdClaim()) .jobType(BatchOrder.JobType.REGULAR) .build(); @@ -93,7 +92,6 @@ public UUID create(final RegisterBpnInvestigationBatchOrder request) { .timeout(request.getTimeout()) .jobTimeout(request.getJobTimeout()) .callbackUrl(request.getCallbackUrl()) - .owner(securityHelperService.getClientIdClaim()) .incidentBPNSs(request.getIncidentBPNSs()) .jobType(BatchOrder.JobType.ESS) .build(); @@ -105,7 +103,7 @@ private UUID createAndStore(final Set keys, final in batchOrderStore.save(batchOrder.getBatchOrderId(), batchOrder); final List batches = createBatches(List.copyOf(keys), - batchSize, batchOrder.getBatchOrderId(), securityHelperService.getClientIdClaim()); + batchSize, batchOrder.getBatchOrderId()); batches.forEach(batch -> { batchStore.save(batch.getBatchId(), batch); jobEventLinkedQueueListener.addQueueForBatch(batch.getBatchId(), batch.getJobProgressList().size()); @@ -116,7 +114,7 @@ private UUID createAndStore(final Set keys, final in return batchOrder.getBatchOrderId(); } - public List createBatches(final List keys, final int batchSize, final UUID batchOrderId, final String owner) { + public List createBatches(final List keys, final int batchSize, final UUID batchOrderId) { final List> globalAssetIdsBatches = Lists.partition(keys, batchSize); final AtomicInteger batchNumber = new AtomicInteger(1); @@ -130,7 +128,6 @@ public List createBatches(final List keys, fi .batchTotal(globalAssetIdsBatches.size()) .batchUrl(buildBatchUrl(batchOrderId, batchId)) .batchState(ProcessingState.INITIALIZED) - .owner(owner) .jobProgressList(batch.stream() .map(identificationKey -> JobProgress.builder() .identificationKey(identificationKey) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java index 7c144ed53b..0be7192918 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java @@ -169,10 +169,10 @@ private PagedListHolder paginateAndSortResults(final Pageable p @Override public JobHandle registerItemJob(final @NonNull RegisterJob request) { - return this.registerItemJob(request, null, securityHelperService.getClientIdClaim()); + return this.registerItemJob(request, null); } - public JobHandle registerItemJob(final @NonNull RegisterJob request, final UUID batchId, final String owner) { + public JobHandle registerItemJob(final @NonNull RegisterJob request, final UUID batchId) { final var params = JobParameter.create(request); if (params.getDirection().equals(Direction.UPWARD) && !params.getBomLifecycle().equals(BomLifecycle.AS_BUILT)) { // Currently not supported variant diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/QueryBatchService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/QueryBatchService.java index 6f6a6b1bc3..2551e0a787 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/QueryBatchService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/QueryBatchService.java @@ -65,10 +65,6 @@ public BatchOrderResponse findOrderById(final UUID batchOrderId) { "Cannot find Batch Order with id: " + batchOrderId)); - if (!securityHelperService.isAdmin() && !batchOrder.getOwner().equals(securityHelperService.getClientIdForViewIrs())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Cannot access Batch Order with id " + batchOrderId + " due to missing privileges."); - } - final List batches = batchStore.findAll() .stream() .filter(batch -> batch.getBatchOrderId().equals(batchOrderId)) @@ -89,11 +85,6 @@ public BatchResponse findBatchById(final UUID batchOrderId, final UUID batchId) "Cannot find Batch with orderId: " + batchOrderId + " and id: " + batchId)); - if (!securityHelperService.isAdmin() && !batchResponse.getOwner().equals(securityHelperService.getClientIdForViewIrs())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Cannot access Batch with orderId: " + batchOrderId - + " and id: " + batchId + " due to missing privileges."); - } - final Integer totalJobs = batchStore.findAll() .stream() .filter(batch -> batch.getBatchOrderId().equals(batchOrderId)) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java index c14bb816c4..aa07a5337c 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EssServiceTest.java @@ -95,7 +95,7 @@ void shouldSuccessfullyStartJobAndReturnWithExtendedSubmodelList() { .shells(new ArrayList<>()) .build(); - when(irsItemGraphQueryService.registerItemJob(any(RegisterJob.class), any(), any())).thenReturn(JobHandle.builder().id(createdJobId).build()); + when(irsItemGraphQueryService.registerItemJob(any(RegisterJob.class), any())).thenReturn(JobHandle.builder().id(createdJobId).build()); when(jobStore.find(createdJobId.toString())).thenReturn(Optional.of(MultiTransferJob.builder().job(expectedResponse.getJob()).build())); when(irsItemGraphQueryService.getJobForJobId(any(MultiTransferJob.class), eq(true))).thenReturn(expectedResponse); when(securityHelperService.isAdmin()).thenReturn(true); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/BatchOrderEventListenerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/BatchOrderEventListenerTest.java index 06134f8dd6..bd19bd85d6 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/BatchOrderEventListenerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/BatchOrderEventListenerTest.java @@ -83,7 +83,6 @@ void shouldStartFirstBatch() { // given final int numberOfJobs = 10; final int timeout = 60; - final String owner = "TestUser"; final BatchOrder batchOrder = BatchOrder.builder() .batchOrderId(BATCH_ORDER_ID) .batchOrderState(ProcessingState.INITIALIZED) @@ -91,7 +90,6 @@ void shouldStartFirstBatch() { .timeout(timeout) .jobTimeout(timeout) .lookupBPNs(Boolean.TRUE) - .owner(owner) .jobType(BatchOrder.JobType.REGULAR) .build(); final Batch firstBatch = Batch.builder() @@ -99,7 +97,6 @@ void shouldStartFirstBatch() { .batchState(ProcessingState.PARTIAL) .batchNumber(1) .batchOrderId(BATCH_ORDER_ID) - .owner(owner) .jobProgressList(createJobProgressList()) .build(); final Batch secondBatch = Batch.builder() @@ -107,10 +104,9 @@ void shouldStartFirstBatch() { .batchState(ProcessingState.PARTIAL) .batchNumber(2) .batchOrderId(BATCH_ORDER_ID) - .owner(owner) .build(); - given(irsItemGraphQueryService.registerItemJob(any(), any(), eq(owner))).willReturn( + given(irsItemGraphQueryService.registerItemJob(any(), any())).willReturn( JobHandle.builder().id(UUID.randomUUID()).build()); batchOrderStore.save(BATCH_ORDER_ID, batchOrder); @@ -119,7 +115,7 @@ void shouldStartFirstBatch() { // when eventListener.handleBatchOrderRegisteredEvent(new BatchOrderRegisteredEvent(BATCH_ORDER_ID)); // then - verify(irsItemGraphQueryService, times(numberOfJobs)).registerItemJob(any(), eq(FIRST_BATCH_ID), eq(owner)); + verify(irsItemGraphQueryService, times(numberOfJobs)).registerItemJob(any(), eq(FIRST_BATCH_ID)); verify(timeoutScheduler, times(1)).registerBatchTimeout(FIRST_BATCH_ID, timeout); verify(timeoutScheduler, times(1)).registerJobsTimeout(anyList(), eq(timeout)); } @@ -129,7 +125,6 @@ void shouldStartNextBatchWhenPreviousFinished() { // given final int numberOfJobs = 10; final int timeout = 60; - final String owner = "TestUser"; final BatchOrder batchOrder = BatchOrder.builder() .batchOrderId(BATCH_ORDER_ID) .batchOrderState(ProcessingState.INITIALIZED) @@ -137,7 +132,6 @@ void shouldStartNextBatchWhenPreviousFinished() { .timeout(timeout) .jobTimeout(timeout) .lookupBPNs(Boolean.TRUE) - .owner(owner) .jobType(BatchOrder.JobType.ESS) .build(); final Batch firstBatch = Batch.builder() @@ -145,7 +139,6 @@ void shouldStartNextBatchWhenPreviousFinished() { .batchState(ProcessingState.PARTIAL) .batchNumber(1) .batchOrderId(BATCH_ORDER_ID) - .owner(owner) .build(); final Batch secondBatch = Batch.builder() .batchId(SECOND_BATCH_ID) @@ -153,10 +146,9 @@ void shouldStartNextBatchWhenPreviousFinished() { .batchNumber(2) .batchOrderId(BATCH_ORDER_ID) .jobProgressList(createJobProgressList()) - .owner(owner) .build(); - given(essService.startIrsJob(any(), any(), eq(owner))).willReturn( + given(essService.startIrsJob(any(), any())).willReturn( JobHandle.builder().id(UUID.randomUUID()).build()); batchOrderStore.save(BATCH_ORDER_ID, batchOrder); @@ -165,7 +157,7 @@ void shouldStartNextBatchWhenPreviousFinished() { // when eventListener.handleBatchProcessingFinishedEvent(new BatchProcessingFinishedEvent(BATCH_ORDER_ID, FIRST_BATCH_ID, ProcessingState.PARTIAL, ProcessingState.COMPLETED, 1, "")); // then - verify(essService, times(numberOfJobs)).startIrsJob(any(), eq(SECOND_BATCH_ID), eq(owner)); + verify(essService, times(numberOfJobs)).startIrsJob(any(), eq(SECOND_BATCH_ID)); verify(timeoutScheduler, times(1)).registerBatchTimeout(SECOND_BATCH_ID, timeout); verify(timeoutScheduler, times(1)).registerJobsTimeout(anyList(), eq(timeout)); } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/CreationBatchServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/CreationBatchServiceTest.java index 3bb1842974..6b6cedd056 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/CreationBatchServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/CreationBatchServiceTest.java @@ -127,7 +127,7 @@ void shouldSplitIdentificationKeysIdIntoBatches() throws MalformedURLException { given(irsConfiguration.getApiUrl()).willReturn(new URL(EXAMPLE_URL)); // when - final List batches = service.createBatches(globalAssetIds, batchSize, UUID.randomUUID(), securityHelperService.getClientIdClaim()); + final List batches = service.createBatches(globalAssetIds, batchSize, UUID.randomUUID()); // then assertThat(batches).hasSize(7); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/QueryBatchServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/QueryBatchServiceTest.java index 7a35818863..957fc563c3 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/QueryBatchServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/QueryBatchServiceTest.java @@ -70,7 +70,6 @@ void shouldFindBatchOrder() { // given final UUID batchOrderId = UUID.randomUUID(); batchOrderStore.save(batchOrderId, createBatchOrder(batchOrderId)); - when(securityHelperService.getClientIdForViewIrs()).thenReturn(owner); final UUID batchId = UUID.randomUUID(); batchStore.save(batchId, createBatch(batchId, batchOrderId)); @@ -111,8 +110,6 @@ void shouldFindBatch() { batchStore.save(batchId, createBatch(batchId, batchOrderId)); batchStore.save(secondBatchId, createBatch(secondBatchId, batchOrderId)); - when(securityHelperService.getClientIdForViewIrs()).thenReturn(owner); - // when final BatchResponse response = service.findBatchById(batchOrderId, batchId); @@ -141,11 +138,11 @@ void shouldFindBatchWithAdminRole() { } private BatchOrder createBatchOrder(final UUID batchOrderId) { - return BatchOrder.builder().batchOrderId(batchOrderId).owner(owner).build(); + return BatchOrder.builder().batchOrderId(batchOrderId).build(); } private Batch createBatch(final UUID batchId, final UUID batchOrderId) { - return Batch.builder().batchId(batchId).batchOrderId(batchOrderId).owner(owner) + return Batch.builder().batchId(batchId).batchOrderId(batchOrderId) .jobProgressList(List.of( JobProgress.builder().jobId(UUID.randomUUID()).build(), JobProgress.builder().jobId(UUID.randomUUID()).build(), diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperService.java b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperService.java index 8ea1071d00..ed90ccc43d 100644 --- a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperService.java +++ b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperService.java @@ -25,13 +25,11 @@ import java.util.Collections; import java.util.List; -import java.util.Optional; +import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Service; /** @@ -40,34 +38,15 @@ @Service public final class SecurityHelperService { - private static final String UNKNOWN = "Unknown"; - private static final String CLIENT_ID = "clientId"; - private static final String BPN = "bpn"; - - public String getClientIdClaim() { - return getClaimOrUnknown(CLIENT_ID); - } - - public String getBpnClaim() { - return getClaimOrUnknown(BPN); - } - public boolean isAdmin() { return getIrsRoles().contains(IrsRoles.ADMIN_IRS); } - public String getClientIdForViewIrs() { - if (getIrsRoles().contains(IrsRoles.VIEW_IRS)) { - return getClientIdClaim(); - } - return ""; - } - private List getIrsRoles() { final Authentication authentication = getAuthenticationFromSecurityContext(); - if (authentication instanceof JwtAuthenticationToken jwtAuthenticationToken) { - return jwtAuthenticationToken.getAuthorities() + if (authentication instanceof AbstractAuthenticationToken authenticationToken) { + return authenticationToken.getAuthorities() .stream() .map(GrantedAuthority::getAuthority) .toList(); @@ -75,18 +54,6 @@ private List getIrsRoles() { return Collections.emptyList(); } - private String getClaimOrUnknown(final String claimName) { - final Authentication authentication = getAuthenticationFromSecurityContext(); - - if (authentication instanceof JwtAuthenticationToken jwtAuthenticationToken) { - final Jwt token = jwtAuthenticationToken.getToken(); - - return Optional.ofNullable(token.getClaim(claimName)).map(Object::toString).orElse(UNKNOWN); - } - - return UNKNOWN; - } - private Authentication getAuthenticationFromSecurityContext() { return SecurityContextHolder.getContext().getAuthentication(); } diff --git a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperServiceTest.java b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperServiceTest.java index 1d2cd0b105..c7bdd77233 100644 --- a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperServiceTest.java +++ b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/auth/SecurityHelperServiceTest.java @@ -26,79 +26,23 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.springframework.security.oauth2.jwt.JwtClaimNames.SUB; -import java.time.Instant; import java.util.List; -import java.util.Map; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; class SecurityHelperServiceTest { - private final String CLIENT_ID = "sa-cl6-cx-2"; - private final String BPN = "BPNL00000001CRHK"; - final SecurityHelperService securityHelperService = new SecurityHelperService(); - @Test - void shouldReturnUnknownWhenNoAuthentication() { - // given - SecurityContextHolder.setContext(Mockito.mock(SecurityContext.class)); - - // when - final String clientIdClaim = securityHelperService.getClientIdClaim(); - - // then - assertThat(clientIdClaim).isEqualTo("Unknown"); - } - - @Test - void shouldReturnClientIdClaimWhenJwtAuthentication() { - // given - thereIsJwtAuthentication(IrsRoles.VIEW_IRS); - - // when - final String clientIdClaim = securityHelperService.getClientIdClaim(); - - // then - assertThat(clientIdClaim).isEqualTo(CLIENT_ID); - } - - @Test - void shouldReturnBpnClaimWhenJwtAuthentication() { - // given - thereIsJwtAuthentication(IrsRoles.VIEW_IRS); - - // when - final String bpnClaim = securityHelperService.getBpnClaim(); - - // then - assertThat(bpnClaim).isEqualTo(BPN); - } - - @Test - void shouldReturnClientIdWhenJwtAuthenticationAndViewIrsRole() { - // given - thereIsJwtAuthentication(IrsRoles.VIEW_IRS); - - // when - final String bpnClaim = securityHelperService.getClientIdForViewIrs(); - - // then - assertThat(bpnClaim).isEqualTo(CLIENT_ID); - } - @Test void shouldReturnTrueWhenAdminRolePresentInToken() { // given - thereIsJwtAuthentication(IrsRoles.ADMIN_IRS); + thereIsAuthentication(IrsRoles.ADMIN_IRS); // when final Boolean isAdmin = securityHelperService.isAdmin(); @@ -107,21 +51,12 @@ void shouldReturnTrueWhenAdminRolePresentInToken() { assertThat(isAdmin).isTrue(); } - private void thereIsJwtAuthentication(final String irsRole) { - final JwtAuthenticationToken jwtAuthenticationToken = mock(JwtAuthenticationToken.class); - final Jwt token = mock(Jwt.class); - when(jwtAuthenticationToken.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority(irsRole))); - when(jwtAuthenticationToken.getToken()).thenReturn(token); - when(token.getClaim("clientId")).thenReturn(CLIENT_ID); - when(token.getClaim("bpn")).thenReturn(BPN); + private void thereIsAuthentication(final String irsRole) { + UsernamePasswordAuthenticationToken authenticationToken = mock(UsernamePasswordAuthenticationToken.class); + when(authenticationToken.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority(irsRole))); SecurityContext securityContext = mock(SecurityContext.class); - when(securityContext.getAuthentication()).thenReturn(jwtAuthenticationToken); + when(securityContext.getAuthentication()).thenReturn(authenticationToken); SecurityContextHolder.setContext(securityContext); } - Jwt jwt() { - return new Jwt("token", Instant.now(), Instant.now().plusSeconds(30), Map.of("alg", "none"), - Map.of(SUB, CLIENT_ID, "clientId", CLIENT_ID, "bpn", BPN)); - } - } From 809840a88d36724f535361e32a468ff2c01bf526 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Wed, 20 Dec 2023 11:57:29 +0100 Subject: [PATCH 36/59] feat(impl):[#259] remove owned field from Batches --- .../tractusx/irs/services/IrsItemGraphQueryService.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java index 0be7192918..d413c6f066 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java @@ -44,7 +44,8 @@ import org.eclipse.tractusx.irs.aaswrapper.job.ItemDataRequest; import org.eclipse.tractusx.irs.aaswrapper.job.RequestMetric; import org.eclipse.tractusx.irs.common.JobProcessingFinishedEvent; -import org.eclipse.tractusx.irs.common.auth.SecurityHelperService; +import org.eclipse.tractusx.irs.common.persistence.BlobPersistence; +import org.eclipse.tractusx.irs.common.persistence.BlobPersistenceException; import org.eclipse.tractusx.irs.component.AsyncFetchedItems; import org.eclipse.tractusx.irs.component.Bpn; import org.eclipse.tractusx.irs.component.FetchedItems; @@ -69,8 +70,6 @@ import org.eclipse.tractusx.irs.connector.job.MultiTransferJob; import org.eclipse.tractusx.irs.connector.job.ResponseStatus; import org.eclipse.tractusx.irs.connector.job.TransferProcess; -import org.eclipse.tractusx.irs.common.persistence.BlobPersistence; -import org.eclipse.tractusx.irs.common.persistence.BlobPersistenceException; import org.eclipse.tractusx.irs.semanticshub.AspectModel; import org.eclipse.tractusx.irs.semanticshub.SemanticsHubFacade; import org.eclipse.tractusx.irs.services.validation.SchemaNotFoundException; @@ -112,8 +111,6 @@ public class IrsItemGraphQueryService implements IIrsItemGraphQueryService { private final String bpdmUrl; - private final SecurityHelperService securityHelperService; - public IrsItemGraphQueryService(final JobOrchestrator orchestrator, final JobStore jobStore, @Qualifier(JOB_BLOB_PERSISTENCE) final BlobPersistence blobStore, final MeterRegistryService meterRegistryService, final SemanticsHubFacade semanticsHubFacade, @@ -126,7 +123,6 @@ public IrsItemGraphQueryService(final JobOrchestrator Date: Wed, 20 Dec 2023 13:32:33 +0100 Subject: [PATCH 37/59] feat(impl):[#259] review comments --- CHANGELOG.md | 2 +- charts/irs-helm/templates/configmap-spring-app-config.yaml | 2 ++ charts/irs-helm/values.yaml | 1 + docs/src/docs/arc42/cross-cutting/safety-security.adoc | 2 +- .../irs/configuration/security/AuthenticationService.java | 5 ----- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cef97d594..3437d8cb38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Authentication was redesigned to use API keys, instead of OAuth2 protocol. The api key has to be sent as a X-API-KEY request header. IRS is supporting two types of API keys - one for admin and one for regular/view usage. Use new ``apiKeyAdmin`` and ``apiKeyRegular`` config entries to set up API keys. ### Removed -- Removed ``oauth.resourceClaim``, ``oauth.irsNamespace``,``oauth.roles``,``oauth2.jwkSetUri``,``bpn`` config entries +- Removed ``oauth.resourceClaim``, ``oauth.irsNamespace``,``oauth.roles``,``oauth2.jwkSetUri`` config entries ## [4.3.0] - 2023-12-08 ### Added diff --git a/charts/irs-helm/templates/configmap-spring-app-config.yaml b/charts/irs-helm/templates/configmap-spring-app-config.yaml index 7032da7f92..fcc9001eb4 100644 --- a/charts/irs-helm/templates/configmap-spring-app-config.yaml +++ b/charts/irs-helm/templates/configmap-spring-app-config.yaml @@ -147,6 +147,8 @@ data: {{- end }} {{- end }} + apiAllowedBpn: {{ tpl (.Values.bpn | default "") . | quote }} + {{- if .Values.config.content }} {{- tpl (toYaml .Values.config.content) . | nindent 4 }} {{- end }} diff --git a/charts/irs-helm/values.yaml b/charts/irs-helm/values.yaml index 2471cb8285..e1df017942 100644 --- a/charts/irs-helm/values.yaml +++ b/charts/irs-helm/values.yaml @@ -105,6 +105,7 @@ readinessProbe: # IRS Configuration # ##################### irsUrl: # "https://" +bpn: # BPN for this IRS instance; only users with this BPN are allowed to access the API apiKeyAdmin: # apiKeyRegular: # ingress: diff --git a/docs/src/docs/arc42/cross-cutting/safety-security.adoc b/docs/src/docs/arc42/cross-cutting/safety-security.adoc index 55dd654fc5..1d37d2a0fa 100644 --- a/docs/src/docs/arc42/cross-cutting/safety-security.adoc +++ b/docs/src/docs/arc42/cross-cutting/safety-security.adoc @@ -4,7 +4,7 @@ === IRS API -The IRS API is secured using API Keys (tokens that a client provides when invoking API calls). IRS identifies API clients based on the provided token inside 'X-API-KEY' request header, and then checks the token with configuration. API Keys can be configured with helm configuration entries - check Administration Guide to know how. Every request to the IRS API requires a valid 'X-API-KEY' header to be successfully authenticated. +The IRS API is secured using API Keys (tokens that a client provides when invoking API calls). IRS identifies API clients based on the provided token inside 'X-API-KEY' request header, and then checks the token with configuration. API Keys can be configured with helm configuration entries - check Administration Guide to know how to do this. Every request to the IRS API requires a valid 'X-API-KEY' header to be successfully authenticated. Currently, IRS API handles two roles: *'admin_irs'* and *'view_irs'.* A valid token with the *'admin_irs'* role can access any endpoint exposed by the IRS API, while a token with the *'view_irs'* role does not have access to policies endpoints and can operate only on resources it owns. That means that he only has access to the resources he has created, e.g. jobs and batches. diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java index aafebcfc39..13f64ff538 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationService.java @@ -23,10 +23,8 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.configuration.security; -import com.apicatalog.jsonld.StringUtils; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; @@ -43,9 +41,6 @@ public class AuthenticationService { public Authentication getAuthentication(final HttpServletRequest request) { final String apiKeyHeader = request.getHeader(AUTH_TOKEN_HEADER_NAME); - if (StringUtils.isBlank(apiKeyHeader)) { - throw new BadCredentialsException("Wrong ApiKey"); - } return new ApiKeyAuthentication(apiKeysConfiguration.authorityOf(apiKeyHeader)); } From 20eff994d4503816675b3e8b6c1d946892e15512 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Wed, 20 Dec 2023 13:58:10 +0100 Subject: [PATCH 38/59] feat(irs-registry-client):[#256] corrections after review --- CHANGELOG.md | 3 +-- .../EndpointDataReferenceCacheService.java | 4 ++-- .../decentral/DecentralDigitalTwinRegistryService.java | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1267843ccc..b606bd9ca7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - +- Added EDR token cache to reuse token after contract negotiation - Added cache mechanism in DiscoveryFinderClientImpl for findDiscoveryEndpoints ## [4.3.0] - 2023-12-08 ### Added - Added support for `hasAlternatives` property in SingleLevelBomAsBuilt aspect -- Added EDR token cache to reuse token after contract negotiation ### Changed - Updated edc dependencies to 0.2.1 diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java index 2b044a0b39..8d0aad4b38 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java @@ -56,7 +56,7 @@ public class EndpointDataReferenceCacheService { * describing token status */ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId) { - final Optional endpointDataReferenceOptional = retrieveEndpointEndpointReferenceByAssetId( + final Optional endpointDataReferenceOptional = retrieveEndpointReferenceByAssetId( assetId); if (endpointDataReferenceOptional.isPresent()) { @@ -81,7 +81,7 @@ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId return new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW); } - private Optional retrieveEndpointEndpointReferenceByAssetId(final String assetId) { + private Optional retrieveEndpointReferenceByAssetId(final String assetId) { log.info("Retrieving dataReference from storage for assetId {}", assetId); return endpointDataReferenceStorage.get(assetId); } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 270225aa71..ec88b11da0 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -87,6 +87,7 @@ private Stream fetchShellDescriptors(final S final List descriptors = new ArrayList<>(); EndpointDataReference endpointDataReference = null; + for (final DigitalTwinRegistryKey key : keys) { endpointDataReference = renewIfNecessary(endpointDataReference, connectorEndpoints); descriptors.add(fetchShellDescriptor(endpointDataReference, key)); From 63db1a308471af9d4058fc2633654c4e71e52cca Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Wed, 20 Dec 2023 14:04:57 +0100 Subject: [PATCH 39/59] feat(impl):[#259] fix test --- .../irs/configuration/security/AuthenticationServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java index 2495ba89b2..2da36ef1b1 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/configuration/security/AuthenticationServiceTest.java @@ -60,6 +60,7 @@ void shouldReturnApiKeyAuthentication() { @Test void shouldThrowExceptionWhenXApiKeyHeaderIsMissing() { final MockHttpServletRequest noApiKeyRequest = new MockHttpServletRequest(); + when(apiKeysConfiguration.authorityOf(noApiKeyRequest.getHeader("X-API-KEY"))).thenThrow(new BadCredentialsException("Wrong ApiKey")); assertThrows(BadCredentialsException.class, () -> authenticationService.getAuthentication(noApiKeyRequest)); } From e5de0317fb0a4f1697993e91df55e89d86cb7e39 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Wed, 20 Dec 2023 14:24:39 +0100 Subject: [PATCH 40/59] feat(irs-registry-client):[#256] added test --- .../EdcSubmodelClientLocalStubTest.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java new file mode 100644 index 0000000000..9a67a7791a --- /dev/null +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java @@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,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.irs.edc.client; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class EdcSubmodelClientLocalStubTest { + + @Mock + private SubmodelTestdataCreator testdataCreator; + + @InjectMocks + private EdcSubmodelClientLocalStub edcSubmodelClientLocalStub; + + @Test + void shouldThrowExceptionFor() { + // given + String assetId = "urn:uuid:c35ee875-5443-4a2d-bc14-fdacd64b9446"; + + // when + assertThrows(EdcClientException.class, () -> edcSubmodelClientLocalStub.getSubmodelRawPayload("", "", assetId)); + } +} \ No newline at end of file From 5a70bdb895554972f43a030af23837390c6c10a8 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Thu, 21 Dec 2023 10:34:24 +0100 Subject: [PATCH 41/59] feat(impl):[#259] use defaults --- charts/irs-helm/values.yaml | 4 ++-- .../irs/configuration/security/ApiKeysConfiguration.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/irs-helm/values.yaml b/charts/irs-helm/values.yaml index e1df017942..d35643204d 100644 --- a/charts/irs-helm/values.yaml +++ b/charts/irs-helm/values.yaml @@ -106,8 +106,8 @@ readinessProbe: ##################### irsUrl: # "https://" bpn: # BPN for this IRS instance; only users with this BPN are allowed to access the API -apiKeyAdmin: # -apiKeyRegular: # +apiKeyAdmin: "password" # Admin auth key, Should be changed! +apiKeyRegular: "password" # View auth key, Should be changed! ingress: enabled: false diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java index c8be770750..3d2aa46f11 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java @@ -42,7 +42,7 @@ @Setter class ApiKeysConfiguration { - private static final int MIN_API_KEY_SIZE = 20; + private static final int MIN_API_KEY_SIZE = 5; @NotBlank @Size(min = MIN_API_KEY_SIZE) From ea14314868e5735f409714bf9f39352f262cf48e Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Thu, 21 Dec 2023 10:40:04 +0100 Subject: [PATCH 42/59] feat(impl):[#259] use defaults --- charts/irs-helm/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/irs-helm/values.yaml b/charts/irs-helm/values.yaml index d35643204d..6e1d49c826 100644 --- a/charts/irs-helm/values.yaml +++ b/charts/irs-helm/values.yaml @@ -106,8 +106,8 @@ readinessProbe: ##################### irsUrl: # "https://" bpn: # BPN for this IRS instance; only users with this BPN are allowed to access the API -apiKeyAdmin: "password" # Admin auth key, Should be changed! -apiKeyRegular: "password" # View auth key, Should be changed! +apiKeyAdmin: "password" # Admin auth key, Should be changed! +apiKeyRegular: "password" # View auth key, Should be changed! ingress: enabled: false From c67b95cd0a5f03d010962a8a68c14b7bd9539330 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Tue, 2 Jan 2024 13:49:50 +0100 Subject: [PATCH 43/59] feat(impl):[TRI-259] update docs --- .../docs/administration/configuration.adoc | 2 +- .../arc42/cross-cutting/safety-security.adoc | 25 +++++++++---------- irs-api/src/main/resources/application.yml | 1 + 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/src/docs/administration/configuration.adoc b/docs/src/docs/administration/configuration.adoc index 63774dae18..5c4bbc6241 100644 --- a/docs/src/docs/administration/configuration.adoc +++ b/docs/src/docs/administration/configuration.adoc @@ -89,7 +89,7 @@ When IRS calls EDC Discovery Service to fetch connector endpoints for BPNLs, the This parameter define how long cache is maintained before it is cleared. Data is in ISO 8601. == OAuth2 Configuration -Previously, OAuth2 protocol was used by IRS to protect the APIs and other resources. As reference, latest IRS version that supported OAuth2 protocol was 4.3.0, which can be found here: https://github.com/eclipse-tractusx/item-relationship-service/releases/tag/4.3.0. +Previously, OAuth2 protocol was used by IRS to protect the APIs and other resources. As a reference, latest IRS version that supported OAuth2 protocol was 4.3.0, which can be found here: https://github.com/eclipse-tractusx/item-relationship-service/releases/tag/4.3.0. === Semantic Model Provisioning The IRS can retrieve semantic models in two ways: diff --git a/docs/src/docs/arc42/cross-cutting/safety-security.adoc b/docs/src/docs/arc42/cross-cutting/safety-security.adoc index 1d37d2a0fa..7a0458baf4 100644 --- a/docs/src/docs/arc42/cross-cutting/safety-security.adoc +++ b/docs/src/docs/arc42/cross-cutting/safety-security.adoc @@ -6,8 +6,7 @@ The IRS API is secured using API Keys (tokens that a client provides when invoking API calls). IRS identifies API clients based on the provided token inside 'X-API-KEY' request header, and then checks the token with configuration. API Keys can be configured with helm configuration entries - check Administration Guide to know how to do this. Every request to the IRS API requires a valid 'X-API-KEY' header to be successfully authenticated. -Currently, IRS API handles two roles: *'admin_irs'* and *'view_irs'.* A valid token with the *'admin_irs'* role can access any endpoint exposed by the IRS API, while a token with the *'view_irs'* role does not have access to policies endpoints and can operate only on resources it owns. -That means that he only has access to the resources he has created, e.g. jobs and batches. +Currently, IRS API handles two roles: *'admin_irs'* and *'view_irs'.* A valid token with the *'admin_irs'* role can access any endpoint exposed by the IRS API, including Policies management API. A valid token with the *'view_irs'* role does not have access to policies endpoints. This behavior is shown in the table below. ==== Rights and Roles Matrix of IRS @@ -19,21 +18,21 @@ This behavior is shown in the table below. | | Update policy | PUT /irs/policies/{policyId} | | x | | Delete policy | DELETE /irs/policies/{policyId} | | x | Aspect models | Get aspect models | GET /irs/aspectmodels | x | x -| Job processing | Register job | POST /irs/jobs | (x) | x -| | Get jobs | GET /irs/jobs | (x) | x -| | Get job | GET /irs/jobs/{jobId} | (x) | x -| | Cancel job | PUT /irs/jobs/{jobId} | (x) | x -| Batch processing | Register order | POST /irs/orders | (x) | x -| | Get order | GET /irs/orders/{orderId} | (x) | x -| | Cancel order | PUT /irs/orders/{orderId} | (x) | x -| | Get batch | GET /irs/orders/{orderId}/batches/{batchId} | (x) | x +| Job processing | Register job | POST /irs/jobs | x | x +| | Get jobs | GET /irs/jobs | x | x +| | Get job | GET /irs/jobs/{jobId} | x | x +| | Cancel job | PUT /irs/jobs/{jobId} | x | x +| Batch processing | Register order | POST /irs/orders | x | x +| | Get order | GET /irs/orders/{orderId} | x | x +| | Cancel order | PUT /irs/orders/{orderId} | x | x +| | Get batch | GET /irs/orders/{orderId}/batches/{batchId} | x | x | Environmental- and -Social Standards | Register investigation job | POST /ess/bpn/investigations | (x) | x -| | Get investigation job | GET /ess/bpn/investigations{id} | (x) | x +Social Standards | Register investigation job | POST /ess/bpn/investigations | x | x +| | Get investigation job | GET /ess/bpn/investigations{id} | x | x | | Accept notifications | POST /ess/notification/receive | x | x |=== -Legend: x = full access to all resources, (x) = access to the resources he owns +Legend: x = full access to all resources === IRS as DTR client diff --git a/irs-api/src/main/resources/application.yml b/irs-api/src/main/resources/application.yml index de162077c3..ecf233bb2b 100644 --- a/irs-api/src/main/resources/application.yml +++ b/irs-api/src/main/resources/application.yml @@ -241,3 +241,4 @@ ess: mockEdcResult: { } # Mocked BPN Investigation results mockRecursiveEdcAsset: # Mocked BPN Recursive Investigation results +apiAllowedBpn: ${API_ALLOWED_BPN:BPNL00000001CRHK} # BPN value that is allowed to access IRS API \ No newline at end of file From 6fe2d4b459b4ed9a71691ebec6eb4151e47790a4 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 8 Jan 2024 12:28:50 +0100 Subject: [PATCH 44/59] chore: commit hook should ignore merge requests for remote-tracking branches --- local/development/commit-msg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local/development/commit-msg b/local/development/commit-msg index b12c4a838e..0cdf739b1f 100644 --- a/local/development/commit-msg +++ b/local/development/commit-msg @@ -8,7 +8,7 @@ fi commitTitle="$(cat $1 | head -n1)" # ignore merge requests -if echo "$commitTitle" | grep -qE "^Merge branch '.*"; then +if echo "$commitTitle" | grep -qE "^Merge (remote-tracking )?branch '.*"; then echo "Commit hook: ignoring branch merge" exit 0 fi From 15aa240232dda21509770f6b196bf1bd43493482 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Tue, 9 Jan 2024 11:22:16 +0100 Subject: [PATCH 45/59] feat(irs):[#256] added documentation --- .../arc42/cross-cutting/under-the-hood.adoc | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc b/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc index 6dc27f9daf..fba7669989 100644 --- a/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc +++ b/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc @@ -108,3 +108,46 @@ When the EDC Discovery is requested to return the EDC connector endpoint URLs fo The time to live for both caches can be configured separately as described in the Administration Guide. Further information on Discovery Service can be found in the chapter "System scope and context". + +=== EDC + +EndpointDataReferenceStorage is in-memory local storage that holds records (EndpointDataReferences) by either assetId or contractAgreementId. + +When EDC gets EndpointDataReference describing endpoint serving data it uses EndpointDataReferenceStorage and query it by assetId. +This allows reuse of already existing EndpointDataReference if it is present, valid, and it's token is not expired, +rather than starting whole new contract negotiation process. + +In case token is expired the process is also shortened. We don't have to start new contract negotiation process, +since we can obtain required contractAgreementId from present authKey. This improves request processing time. + +[source, mermaid] +.... +sequenceDiagram + autonumber + participant EdcSubmodelClient + participant ContractNegotiationService + participant EndpointDataReferenceStorage + participant EdcCallbackController + participant EdcDataPlaneClient + EdcSubmodelClient ->> EndpointDataReferenceStorage: Get EDR Token for EDC asset id + EndpointDataReferenceStorage ->> EdcSubmodelClient: Return Optional + alt Token is present and not expired + EdcSubmodelClient ->> EdcSubmodelClient: Optional.get + else + alt Token is expired + EdcSubmodelClient ->> ContractNegotiationService: Renew EDR Token based on existing Token + else Token is not present + EdcSubmodelClient ->> ContractNegotiationService: Negotiate new EDR Token + end + ContractNegotiationService -->> EdcCallbackController: EDC flow + EdcCallbackController ->> EndpointDataReferenceStorage: Store EDR token by EDC asset id after EDC callback + loop While EDR Token is not present + EdcSubmodelClient ->> EndpointDataReferenceStorage: Poll for EDR Token + end + EndpointDataReferenceStorage ->> EdcSubmodelClient: Return EDR Token + end + EdcSubmodelClient ->> EdcDataPlaneClient: Get data(EDR Token, Dataplane URL) + EdcDataPlaneClient ->> EdcSubmodelClient: Return data +.... + + From bcda2e2d2077f767b4bb0a489ba17bb8346ee603 Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Wed, 10 Jan 2024 12:41:09 +0100 Subject: [PATCH 46/59] feat(irs):[#256] fixed problem with parsing authCode --- .../irs/edc/client/ContractNegotiationService.java | 7 ++++--- .../tractusx/irs/edc/client/EdcSubmodelClientImpl.java | 8 ++++---- .../irs/edc/client/ContractNegotiationServiceTest.java | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 344cd039a8..231c7792bf 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -94,11 +94,12 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca contractAgreementId = negotiationResponse.getContractAgreementId(); } case EXPIRED -> { - final String authKey = resultEndpointDataReferenceStatus.endpointDataReference().getAuthKey(); - if (authKey == null) { + final String authCode = resultEndpointDataReferenceStatus.endpointDataReference().getAuthCode(); + if (authCode == null) { throw new IllegalStateException("Missing information about AuthKey."); } - contractAgreementId = EDRAuthCode.fromAuthCodeToken(authKey).getCid(); + log.error("AuthCode to be parsed: " + authCode); + contractAgreementId = EDRAuthCode.fromAuthCodeToken(authCode).getCid(); log.info( "Cached endpoint data reference has expired token. Refreshing token without new contract negotiation for contractAgreementId: {}", Masker.mask(contractAgreementId)); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index eabf6315cd..703a2b1a50 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -234,11 +234,11 @@ private static String getStorageId(final EndpointDataReferenceStatus endpointDat if (response != null) { storageId = response.getContractAgreementId(); } else { - final String authKey = endpointDataReferenceStatus.endpointDataReference().getAuthKey(); - if (authKey == null) { - throw new IllegalStateException("Missing information about AuthKey."); + final String authCode = endpointDataReferenceStatus.endpointDataReference().getAuthCode(); + if (authCode == null) { + throw new IllegalStateException("Missing information about AuthCode."); } - storageId = EDRAuthCode.fromAuthCodeToken(authKey).getCid(); + storageId = EDRAuthCode.fromAuthCodeToken(authCode).getCid(); } return storageId; } diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java index 2748e84e0c..7c352dc529 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java @@ -226,11 +226,11 @@ void shouldNotStartNewNegotiationWhenTokenIsExpired() Response.builder().responseId("transferProcessId").build()); when(edcControlPlaneClient.getTransferProcess(any())).thenReturn( CompletableFuture.completedFuture(TransferProcessResponse.builder().build())); - final String encodedAuthKey = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE3MDA3NDc0NjMsImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.HDhEMOGVlwOTAFIKCCUzf_twg08K-rQwElNS2foinB9hRM-htLwoXayMtbXdXS4pFevRn1AXhzcxd5ur7gslJdsNohTiwVP0lXRd0cehWMpRKdDiUCLn4lh0A2fFTYpoX4WIXvqldAADxi0qDmZqLTZdSOqkM40t-Fq8esyFMrO_uC6GL8LUQMLML1HV6nqGkqp-VELEoOMTV1-aVQ-OEv0J24epjNyesx448v0yylhS_vxPmay1zeSJgDCwqzSuY5-EkyIfCN1XqbynMZiNtD2FLbAig0KTAL2rN6WMufSWMjgLUU0mhRbd9bWvqs3JKLVzvagQgS3hMTj5a-C2Tw"; + final String encodedAuthCode = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE3MDA3NDc0NjMsImRhZCI6IkFXanRhclZySVdtaVE4V1R4VGV2YVhUS1p5SERUZ3pkWG1oMWpkdTR3QUxkTTZVaEgyVHVCOXhhS2Z6TmJQQTZVQVhnVDc2NytPMTgwUXltMGNFdks0NGxzakZQbkROTFQwOEpBOGxvazg0a3hScktFdSswRDZFMmlzTUNPM1Zaa2ZmNDB1U2d6YmJVTDR1djNGNGYxdVp6RnRZT2VvcDdjOUFUc2k1WHhyaGZLdkdDOERrRi9idTBaQmY1US9nMy9xS3QwY0FmcW9TNUxWSlN1SVhKdUk4S2JNSldob2hLZ1NRb2tLMWxNQzVpSVRhbWZ2L0FvZUNXMnB1bkc1R0twM1NTak9Da1hJL3ZXQlRTNWVFTzRpYkwvL1JSZGdJdVp3K2dzcHVVMkFtYm04YzZFQjViQjlPYWhhYjRzRCtnTldDcWFZazZWQ1p4Ty9xaUlKT1RZVGo0b3pDVnovcE5VN0l6R1hBWjNaamtNRWRMbUJVclhDSFRtaU1GeGd5bkxQN2hBVmN5M2NOVGhIb0FtZDI1c2ZwbUdTeHViS1FmSHM2RUNFajByYS9lT001dHNqZ2l5N3JOOUhQT25zWFppL01yMWR1UDE4c0hGQmVLeWFNNkwveFN6TTlCUVplb0Z2TVE5VmlmSm1hMUQ5WklrNUhhTnBmc0RQSElBK0VLL0hGSG1mRWk1TGhoS3lVY3Q2VGpQb0VKa25WamJBSU01VXUzSW1oV3NFdkVLR3lvZXQ0UEhYeHBVWlhQWFdjSjd0dk8zZms3YjczOEVRVEV6Y29KTFdZd0wrRDZac1hJVjd4UzFOOTV4WDlqcU9aUjBuSGsxb3lmT21KUTg5UkpxZy91eE01L3lPcFJUWU01OWJGTzJBRWVDa0UwM0k2aUY0NE1xQU1VVzM4bGk4eDFkY3A0ajQ3Z0lKMlFrWTM5bHI1VXRpbEFzcjVZMkN5Nm5hcVFIeFU2TW1LS0RFdVQrUXdxTFZGYVB5SC9ZM2dTOFpZdlh3TlVOams4S2k4T2JFTTVUY25nUWxVK0Y0dE9BeTQ0bjNPckpWYlhIcVBud1N4L2ZmbTdKdVRnZjRlMVpPcThhdz09IiwiY2lkIjoiT1dZeFlqa3dZelV0TldFNVlTMDBaR1UyTFRoaVpXTXROalprWTJaaVlqTXdPREZtOmNtVm5hWE4wY25rdFlYTnpaWFE9Ok1XWXlZMll5TmpVdE56STROQzAwTnpFNUxXSTNOVGt0TWpSbFpqY3habU13WWpaaSJ9.HDhEMOGVlwOTAFIKCCUzf_twg08K-rQwElNS2foinB9hRM-htLwoXayMtbXdXS4pFevRn1AXhzcxd5ur7gslJdsNohTiwVP0lXRd0cehWMpRKdDiUCLn4lh0A2fFTYpoX4WIXvqldAADxi0qDmZqLTZdSOqkM40t-Fq8esyFMrO_uC6GL8LUQMLML1HV6nqGkqp-VELEoOMTV1-aVQ-OEv0J24epjNyesx448v0yylhS_vxPmay1zeSJgDCwqzSuY5-EkyIfCN1XqbynMZiNtD2FLbAig0KTAL2rN6WMufSWMjgLUU0mhRbd9bWvqs3JKLVzvagQgS3hMTj5a-C2Tw"; // when testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus( - EndpointDataReference.Builder.newInstance().authKey(encodedAuthKey).endpoint("").authCode("").build(), + EndpointDataReference.Builder.newInstance().authKey("").authCode(encodedAuthCode).endpoint("").build(), EndpointDataReferenceStatus.TokenStatus.EXPIRED)); // then From 5b47b1a9897fb7bb1f838c28cdc45198925fd54f Mon Sep 17 00:00:00 2001 From: Pawel Sosnowski Date: Wed, 10 Jan 2024 12:59:39 +0100 Subject: [PATCH 47/59] feat(irs):[#256] fixed documentation typo --- docs/src/docs/arc42/cross-cutting/under-the-hood.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc b/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc index fba7669989..aaa8440e10 100644 --- a/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc +++ b/docs/src/docs/arc42/cross-cutting/under-the-hood.adoc @@ -118,7 +118,7 @@ This allows reuse of already existing EndpointDataReference if it is present, va rather than starting whole new contract negotiation process. In case token is expired the process is also shortened. We don't have to start new contract negotiation process, -since we can obtain required contractAgreementId from present authKey. This improves request processing time. +since we can obtain required contractAgreementId from present authCode. This improves request processing time. [source, mermaid] .... From 6885af94053b0cfbf23f2a20bf0e96999bae01e6 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Thu, 11 Jan 2024 21:59:25 +0100 Subject: [PATCH 48/59] feat(impl):[#259] update insomnia --- local/testing/IRS_Request_Collection.json | 105 ++++++++++++++++++---- 1 file changed, 90 insertions(+), 15 deletions(-) diff --git a/local/testing/IRS_Request_Collection.json b/local/testing/IRS_Request_Collection.json index bbd58754c7..981fe7a2a7 100644 --- a/local/testing/IRS_Request_Collection.json +++ b/local/testing/IRS_Request_Collection.json @@ -1,21 +1,26 @@ { "_type": "export", "__export_format": 4, - "__export_date": "2023-12-19T13:10:44.232Z", + "__export_date": "2024-01-11T20:58:14.760Z", "__export_source": "insomnia.desktop.app:v2023.5.8", "resources": [ { - "_id": "req_09113cc4a55e4db0b7b3cf40b8b6d02c", + "_id": "req_5abf771bdc1048ff99f5ce39366febce", "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", - "modified": 1702990529632, - "created": 1687243204155, - "url": "{{IRS_HOST}}/irs/policies/{% prompt 'policyId', '', 'traceability-test', '', false, true %}", - "name": "Delete policy", + "modified": 1705006038830, + "created": 1705005887617, + "url": "{{IRS_HOST}}/irs/policies", + "name": "Get all policies", "description": "", - "method": "DELETE", + "method": "GET", "body": {}, "parameters": [], - "headers": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/2023.5.8" + } + ], "authentication": { "type": "apikey", "disabled": false, @@ -23,7 +28,7 @@ "value": "{{ _.ADMIN_API_KEY }}", "addTo": "header" }, - "metaSortKey": -1685602897140.75, + "metaSortKey": -1705005887617, "isPrivate": false, "settingStoreCookies": true, "settingSendCookies": true, @@ -67,6 +72,35 @@ "scope": "collection", "_type": "workspace" }, + { + "_id": "req_09113cc4a55e4db0b7b3cf40b8b6d02c", + "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", + "modified": 1702990529632, + "created": 1687243204155, + "url": "{{IRS_HOST}}/irs/policies/{% prompt 'policyId', '', 'traceability-test', '', false, true %}", + "name": "Delete policy", + "description": "", + "method": "DELETE", + "body": {}, + "parameters": [], + "headers": [], + "authentication": { + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.ADMIN_API_KEY }}", + "addTo": "header" + }, + "metaSortKey": -1685602897140.75, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, { "_id": "req_6f2d62a44ccc491cad22dfcc5b157e04", "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", @@ -107,7 +141,7 @@ { "_id": "req_f232d8b29b8e48528496f449145193f9", "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", - "modified": 1702990569590, + "modified": 1705006437142, "created": 1687243182397, "url": "{{IRS_HOST}}/irs/policies", "name": "Register policy", @@ -1899,7 +1933,7 @@ { "_id": "req_a6c1b73c7d2d407699913aabe4af51c5", "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", - "modified": 1702991293070, + "modified": 1705006665175, "created": 1680682418265, "url": "{{IRS_HOST}}/irs/jobs", "name": "Register Job", @@ -2036,7 +2070,7 @@ { "_id": "req_7c35241474cf41d1a6cc2864afc7313e", "parentId": "fld_fb03597a1ff8491f8e2ec1ee57891936", - "modified": 1702991280208, + "modified": 1703236659047, "created": 1690384427379, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", "name": "Get Job for jobId", @@ -2515,6 +2549,47 @@ "settingFollowRedirects": "global", "_type": "request" }, + { + "_id": "req_a92050648817457486cd7664e549e06e", + "parentId": "fld_acf689d4003a47898ddbe195039a59d4", + "modified": 1705006305365, + "created": 1705006139836, + "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}", + "name": "Cancel order job for given orderId", + "description": "", + "method": "PUT", + "body": { + "mimeType": "application/json", + "text": "{}" + }, + "parameters": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + }, + { + "name": "User-Agent", + "value": "insomnia/2023.5.8" + } + ], + "authentication": { + "type": "apikey", + "disabled": false, + "key": "X-API-KEY", + "value": "{{ _.REGULAR_API_KEY }}", + "addTo": "header" + }, + "metaSortKey": -1680682418111.25, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, { "_id": "req_c42c94e761c24426878cf3cd88e301b1", "parentId": "fld_acf689d4003a47898ddbe195039a59d4", @@ -3407,7 +3482,7 @@ { "_id": "jar_d2b7eb1621841465ea24b73343568b286aa8ac9a", "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", - "modified": 1702554690714, + "modified": 1703236544943, "created": 1680782486851, "name": "Default Jar", "cookies": [ @@ -3423,8 +3498,8 @@ ], "hostOnly": true, "creation": "2023-04-06T13:30:18.499Z", - "lastAccessed": "2023-12-14T11:51:30.713Z", - "id": "05576732916905858" + "lastAccessed": "2023-12-22T09:15:44.943Z", + "id": "44566206612081904" } ], "_type": "cookie_jar" From 981e10e8da2030717a017bac246690900ab149f4 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Thu, 11 Jan 2024 22:03:56 +0100 Subject: [PATCH 49/59] feat(impl):[#259] update insomnia --- local/testing/IRS_Request_Collection.json | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/local/testing/IRS_Request_Collection.json b/local/testing/IRS_Request_Collection.json index 981fe7a2a7..b11e5ff507 100644 --- a/local/testing/IRS_Request_Collection.json +++ b/local/testing/IRS_Request_Collection.json @@ -1,13 +1,13 @@ { "_type": "export", "__export_format": 4, - "__export_date": "2024-01-11T20:58:14.760Z", + "__export_date": "2024-01-11T21:02:36.140Z", "__export_source": "insomnia.desktop.app:v2023.5.8", "resources": [ { "_id": "req_5abf771bdc1048ff99f5ce39366febce", "parentId": "fld_0195759b9c384a03ac70f2fe63701b55", - "modified": 1705006038830, + "modified": 1705006817408, "created": 1705005887617, "url": "{{IRS_HOST}}/irs/policies", "name": "Get all policies", @@ -15,12 +15,7 @@ "method": "GET", "body": {}, "parameters": [], - "headers": [ - { - "name": "User-Agent", - "value": "insomnia/2023.5.8" - } - ], + "headers": [], "authentication": { "type": "apikey", "disabled": false, @@ -2552,7 +2547,7 @@ { "_id": "req_a92050648817457486cd7664e549e06e", "parentId": "fld_acf689d4003a47898ddbe195039a59d4", - "modified": 1705006305365, + "modified": 1705006936944, "created": 1705006139836, "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}", "name": "Cancel order job for given orderId", @@ -2566,11 +2561,8 @@ "headers": [ { "name": "Content-Type", - "value": "application/json" - }, - { - "name": "User-Agent", - "value": "insomnia/2023.5.8" + "value": "application/json", + "id": "pair_88db8badf4ea4a0d9968c769167407c8" } ], "authentication": { From ba2f869207ceb47d98964648773f815c72ae7910 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 12 Jan 2024 10:27:36 +0100 Subject: [PATCH 50/59] feat(impl):[#259] try fix --- .github/workflows/publish-documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-documentation.yaml b/.github/workflows/publish-documentation.yaml index f45114031d..caf476be3a 100644 --- a/.github/workflows/publish-documentation.yaml +++ b/.github/workflows/publish-documentation.yaml @@ -36,7 +36,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 20 - name: Cache maven packages uses: actions/cache@v3 From 1284585a1ce47ecde0b9c3a139da1540e5dd6120 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 12 Jan 2024 13:21:02 +0100 Subject: [PATCH 51/59] feat(impl):[#259] try fix --- .github/workflows/publish-documentation.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-documentation.yaml b/.github/workflows/publish-documentation.yaml index caf476be3a..b21dc78dd4 100644 --- a/.github/workflows/publish-documentation.yaml +++ b/.github/workflows/publish-documentation.yaml @@ -105,8 +105,8 @@ jobs: - name: MD linting run: | npm install markdownlint-cli2 - npx markdownlint-cli2-config docs/.markdownlint.yaml docs/target/generated-docs/adminguide.md - npx markdownlint-cli2-config docs/.markdownlint.yaml docs/target/generated-docs/arc42.md + npx markdownlint-cli2 --config docs/.markdownlint.yaml docs/target/generated-docs/adminguide.md + npx markdownlint-cli2 --config docs/.markdownlint.yaml docs/target/generated-docs/arc42.md - name: Move assets to target directory run: | From fe277ac5ceb022d2946f5c20cd408a9372770d93 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 12 Jan 2024 14:34:29 +0100 Subject: [PATCH 52/59] feat(impl):[#259] temporary keys --- irs-api/src/main/resources/application.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/irs-api/src/main/resources/application.yml b/irs-api/src/main/resources/application.yml index ecf233bb2b..fe590c46f4 100644 --- a/irs-api/src/main/resources/application.yml +++ b/irs-api/src/main/resources/application.yml @@ -97,8 +97,8 @@ irs: # Application config security: api: keys: - admin: ${API_KEY_ADMIN} # API Key to access IRS API with admin role - regular: ${API_KEY_REGULAR} # API Key to access IRS API with view role + admin: "8f976efe-ee07-4049-b851-07e38cc60baa" # API Key to access IRS API with admin role + regular: "4ec5a557-7c6d-48a4-af57-ab5016424c11" # API Key to access IRS API with view role blobstore: endpoint: "${MINIO_URL}" # S3 compatible API endpoint (e.g. Minio) From 08666d14c021c287450379f3db544b1ad9826301 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Fri, 12 Jan 2024 15:45:45 +0100 Subject: [PATCH 53/59] feat(impl):[#259] fix small bug --- .../irs/configuration/security/ApiKeysConfiguration.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java index 3d2aa46f11..0c13802eb6 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/security/ApiKeysConfiguration.java @@ -26,6 +26,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; import lombok.Setter; +import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.irs.common.auth.IrsRoles; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.security.authentication.BadCredentialsException; @@ -53,6 +54,10 @@ class ApiKeysConfiguration { private String regular; /* package */ ApiKeyAuthority authorityOf(final String apiKey) { + if (StringUtils.isBlank(apiKey)) { + throw new BadCredentialsException("Wrong ApiKey"); + } + if (apiKey.equals(admin)) { return ApiKeyAuthority.of(apiKey, AuthorityUtils.createAuthorityList(IrsRoles.ADMIN_IRS)); } else if (apiKey.equals(regular)) { From 7d831f6cfd1e9cefa873e76628547921dddf6aa0 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 15 Jan 2024 11:57:02 +0100 Subject: [PATCH 54/59] feat(impl):[#253] revert hardcoded keys --- irs-api/src/main/resources/application-local.yml | 10 +++++----- irs-api/src/main/resources/application.yml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/irs-api/src/main/resources/application-local.yml b/irs-api/src/main/resources/application-local.yml index ecf0b3c1cd..4c2ac820f6 100644 --- a/irs-api/src/main/resources/application-local.yml +++ b/irs-api/src/main/resources/application-local.yml @@ -21,11 +21,11 @@ irs: ttl: failed: PT1H completed: PT1H - security: - api: - keys: - admin: 01234567890123456789 - regular: 09876543210987654321 +# security: +# api: +# keys: +# admin: 01234567890123456789 +# regular: 09876543210987654321 spring: security: diff --git a/irs-api/src/main/resources/application.yml b/irs-api/src/main/resources/application.yml index fe590c46f4..ecf233bb2b 100644 --- a/irs-api/src/main/resources/application.yml +++ b/irs-api/src/main/resources/application.yml @@ -97,8 +97,8 @@ irs: # Application config security: api: keys: - admin: "8f976efe-ee07-4049-b851-07e38cc60baa" # API Key to access IRS API with admin role - regular: "4ec5a557-7c6d-48a4-af57-ab5016424c11" # API Key to access IRS API with view role + admin: ${API_KEY_ADMIN} # API Key to access IRS API with admin role + regular: ${API_KEY_REGULAR} # API Key to access IRS API with view role blobstore: endpoint: "${MINIO_URL}" # S3 compatible API endpoint (e.g. Minio) From c62bec0c158f9d36b148d867769c5c5d6a9497d0 Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 15 Jan 2024 11:57:50 +0100 Subject: [PATCH 55/59] feat(impl):[#253] revert hardcoded keys --- irs-api/src/main/resources/application-local.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/irs-api/src/main/resources/application-local.yml b/irs-api/src/main/resources/application-local.yml index 4c2ac820f6..ecf0b3c1cd 100644 --- a/irs-api/src/main/resources/application-local.yml +++ b/irs-api/src/main/resources/application-local.yml @@ -21,11 +21,11 @@ irs: ttl: failed: PT1H completed: PT1H -# security: -# api: -# keys: -# admin: 01234567890123456789 -# regular: 09876543210987654321 + security: + api: + keys: + admin: 01234567890123456789 + regular: 09876543210987654321 spring: security: From 48b5007586e5b1df2cb9a6f9a07345cfc8bc817f Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 15 Jan 2024 12:16:34 +0100 Subject: [PATCH 56/59] chore(release):[#XXX] release 4.3.1 --- CHANGELOG.md | 5 ++++- charts/irs-helm/CHANGELOG.md | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cda55d77e0..f75f8ac043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [4.3.1] - 2024-01-15 ### Added - Added EDR token cache to reuse token after contract negotiation - Added cache mechanism in DiscoveryFinderClientImpl for findDiscoveryEndpoints @@ -486,7 +488,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Unresolved - **Select Aspects you need** You are able to select the needed aspects for which you want to collect the correct endpoint information. -[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.0...HEAD +[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.1...HEAD +[4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.0...4.3.1 [4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.2.0...4.3.0 [4.2.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.1.0...4.2.0 [4.1.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.0.2...4.1.0 diff --git a/charts/irs-helm/CHANGELOG.md b/charts/irs-helm/CHANGELOG.md index b5e3fac343..6aa85f4c7b 100644 --- a/charts/irs-helm/CHANGELOG.md +++ b/charts/irs-helm/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [6.13.0] - 2024-01-15 +- Update IRS version to 4.3.1 + ## [6.12.0] - 2023-12-08 ### Changed - Changed configuration from `ess.managementPath` to options for each endpoint `ess.assetsPath` `ess.policydefinitionsPath` `ess.contractdefinitionsPath`. E.g. `ess.assetsPath: /management/v3/assets` From c232204d9570613d9981861ed6401d66e0fa8e8e Mon Sep 17 00:00:00 2001 From: "Krzysztof Massalski (Extern)" Date: Mon, 15 Jan 2024 13:25:46 +0100 Subject: [PATCH 57/59] chore(release):[#XXX] release 4.4.0 --- CHANGELOG.md | 6 +++--- charts/irs-helm/CHANGELOG.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f75f8ac043..a83cf7cff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [4.3.1] - 2024-01-15 +## [4.4.0] - 2024-01-15 ### Added - Added EDR token cache to reuse token after contract negotiation - Added cache mechanism in DiscoveryFinderClientImpl for findDiscoveryEndpoints @@ -488,8 +488,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Unresolved - **Select Aspects you need** You are able to select the needed aspects for which you want to collect the correct endpoint information. -[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.1...HEAD -[4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.0...4.3.1 +[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.4.0...HEAD +[4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.0...4.4.0 [4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.2.0...4.3.0 [4.2.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.1.0...4.2.0 [4.1.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.0.2...4.1.0 diff --git a/charts/irs-helm/CHANGELOG.md b/charts/irs-helm/CHANGELOG.md index 6aa85f4c7b..28169057dd 100644 --- a/charts/irs-helm/CHANGELOG.md +++ b/charts/irs-helm/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [6.13.0] - 2024-01-15 -- Update IRS version to 4.3.1 +- Update IRS version to 4.4.0 ## [6.12.0] - 2023-12-08 ### Changed From 6154d6cab6c88c17f99dbc91cabbad92b35eb100 Mon Sep 17 00:00:00 2001 From: ds-ext-kmassalski <100765908+ds-ext-kmassalski@users.noreply.github.com> Date: Mon, 15 Jan 2024 13:39:49 +0100 Subject: [PATCH 58/59] Update CHANGELOG.md Co-authored-by: Jaro Hartmann <57985712+ds-jhartmann@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a83cf7cff9..f8e71642ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -489,7 +489,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Select Aspects you need** You are able to select the needed aspects for which you want to collect the correct endpoint information. [Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.4.0...HEAD -[4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.0...4.4.0 +[4.4.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.3.0...4.4.0 [4.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.2.0...4.3.0 [4.2.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.1.0...4.2.0 [4.1.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.0.2...4.1.0 From 1f1724944a7125209b7a98f6823795512ff7dd24 Mon Sep 17 00:00:00 2001 From: ds-ext-kmassalski Date: Mon, 15 Jan 2024 13:05:04 +0000 Subject: [PATCH 59/59] chore(release): Prepare release for Helm version 6.13.0 --- charts/irs-helm/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/irs-helm/Chart.yaml b/charts/irs-helm/Chart.yaml index 04ae3c7555..aa86285f91 100644 --- a/charts/irs-helm/Chart.yaml +++ b/charts/irs-helm/Chart.yaml @@ -35,12 +35,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 6.12.0 +version: 6.13.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "4.3.0" +appVersion: "4.4.0" dependencies: - name: common repository: https://charts.bitnami.com/bitnami