From e7e189cf933d05aaae81c7bdd95b02f40acf3778 Mon Sep 17 00:00:00 2001 From: bscholtes1A <88310985+bscholtes1A@users.noreply.github.com> Date: Fri, 22 Jul 2022 16:36:17 +0200 Subject: [PATCH] Add integration test covering the case where Request parameters are provided when querying the Data Plane public API --- CHANGELOG.md | 2 +- .../DecentralizedIdentityService.java | 15 ++----- .../DecentralizedIdentityServiceTest.java | 9 +--- .../test/e2e/BackendServiceTestExtension.java | 2 +- .../e2e/ConsumerBackendServiceController.java | 44 +++++++------------ .../e2e/ProviderBackendApiController.java | 8 ++-- .../test/e2e/AbstractEndToEndTransfer.java | 43 +++++++++--------- .../test/e2e/Participant.java | 41 +++++++++++++++-- 8 files changed, 87 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0b2de6793b..b460c2a712e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ in the detailed section referring to by linking pull requests or issues. #### Added -* +* System test for client data pull with query parameters (#1180) #### Changed diff --git a/extensions/iam/decentralized-identity/identity-did-service/src/main/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityService.java b/extensions/iam/decentralized-identity/identity-did-service/src/main/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityService.java index a6d01a1d7c1..68f4b29a7c9 100644 --- a/extensions/iam/decentralized-identity/identity-did-service/src/main/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityService.java +++ b/extensions/iam/decentralized-identity/identity-did-service/src/main/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityService.java @@ -22,11 +22,8 @@ import org.eclipse.dataspaceconnector.iam.did.spi.credentials.CredentialsVerifier; import org.eclipse.dataspaceconnector.iam.did.spi.document.DidConstants; import org.eclipse.dataspaceconnector.iam.did.spi.document.DidDocument; -import org.eclipse.dataspaceconnector.iam.did.spi.document.JwkPublicKey; -import org.eclipse.dataspaceconnector.iam.did.spi.document.Service; import org.eclipse.dataspaceconnector.iam.did.spi.document.VerificationMethod; import org.eclipse.dataspaceconnector.iam.did.spi.key.PrivateKeyWrapper; -import org.eclipse.dataspaceconnector.iam.did.spi.key.PublicKeyWrapper; import org.eclipse.dataspaceconnector.iam.did.spi.resolution.DidResolverRegistry; import org.eclipse.dataspaceconnector.spi.iam.ClaimToken; import org.eclipse.dataspaceconnector.spi.iam.IdentityService; @@ -78,17 +75,17 @@ public Result verifyJwtToken(TokenRepresentation tokenRepresentation monitor.debug("Extracting public key"); // this will return the _first_ public key entry - Optional publicKey = getPublicKey(didResult.getContent()); + var publicKey = getPublicKey(didResult.getContent()); if (publicKey.isEmpty()) { return Result.failure("Public Key not found in DID Document!"); } //convert the POJO into a usable PK-wrapper: - JwkPublicKey publicKeyJwk = publicKey.get().getPublicKeyJwk(); - PublicKeyWrapper publicKeyWrapper = KeyConverter.toPublicKeyWrapper(publicKeyJwk, publicKey.get().getId()); + var publicKeyJwk = publicKey.get().getPublicKeyJwk(); + var publicKeyWrapper = KeyConverter.toPublicKeyWrapper(publicKeyJwk, publicKey.get().getId()); monitor.debug("Verifying JWT with public key..."); - Result verified = VerifiableCredentialFactory.verify(jwt, publicKeyWrapper, audience); + var verified = VerifiableCredentialFactory.verify(jwt, publicKeyWrapper, audience); if (verified.failed()) { verified.getFailureMessages().forEach(m -> monitor.debug(() -> "Failure in token verification: " + m)); return Result.failure("Token could not be verified!"); @@ -108,10 +105,6 @@ public Result verifyJwtToken(TokenRepresentation tokenRepresentation } } - String getHubUrl(DidDocument did) { - return did.getService().stream().filter(service -> service.getType().equals(DidConstants.HUB_URL)).map(Service::getServiceEndpoint).findFirst().orElseThrow(); - } - @NotNull private Optional getPublicKey(DidDocument did) { return did.getVerificationMethod().stream().filter(vm -> DidConstants.ALLOWED_VERIFICATION_TYPES.contains(vm.getType())).findFirst(); diff --git a/extensions/iam/decentralized-identity/identity-did-service/src/test/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityServiceTest.java b/extensions/iam/decentralized-identity/identity-did-service/src/test/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityServiceTest.java index 2a85895c694..9b352d7ce15 100644 --- a/extensions/iam/decentralized-identity/identity-did-service/src/test/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityServiceTest.java +++ b/extensions/iam/decentralized-identity/identity-did-service/src/test/java/org/eclipse/dataspaceconnector/identity/DecentralizedIdentityServiceTest.java @@ -35,7 +35,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; import java.time.Clock; import java.util.Map; @@ -52,15 +51,9 @@ abstract class DecentralizedIdentityServiceTest { private static final Faker FAKER = new Faker(); private static final String DID_DOCUMENT = getResourceFileContentAsString("dids.json"); - String didUrl = FAKER.internet().url(); + private final String didUrl = FAKER.internet().url(); private DecentralizedIdentityService identityService; - @Test - void verifyResolveHubUrl() throws IOException { - var url = identityService.getHubUrl(new ObjectMapper().readValue(DID_DOCUMENT, DidDocument.class)); - assertEquals("https://myhub.com", url); - } - @Test void generateAndVerifyJwtToken_valid() { var result = identityService.obtainClientCredentials(TokenParameters.Builder.newInstance() diff --git a/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/BackendServiceTestExtension.java b/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/BackendServiceTestExtension.java index 0cc6387b966..4d75b89f7e1 100644 --- a/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/BackendServiceTestExtension.java +++ b/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/BackendServiceTestExtension.java @@ -41,7 +41,7 @@ public String name() { public void initialize(ServiceExtensionContext context) { var exposedHttpPort = context.getConfig().getInteger("web.http.port"); webService.registerResource(new ProviderBackendApiController()); - webService.registerResource(new ConsumerBackendServiceController(context.getMonitor(), okHttpClient)); + webService.registerResource(new ConsumerBackendServiceController(context.getMonitor())); webService.registerResource(new BackendServiceHttpProvisionerController(context.getMonitor(), okHttpClient, typeManager, exposedHttpPort)); } } diff --git a/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ConsumerBackendServiceController.java b/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ConsumerBackendServiceController.java index 971d900086b..0c7cb36d1f9 100644 --- a/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ConsumerBackendServiceController.java +++ b/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ConsumerBackendServiceController.java @@ -18,52 +18,42 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; import org.eclipse.dataspaceconnector.spi.monitor.Monitor; import org.eclipse.dataspaceconnector.spi.types.domain.edr.EndpointDataReference; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; -import static java.lang.String.format; - @Path("/consumer") public class ConsumerBackendServiceController { private final Monitor monitor; - private final OkHttpClient httpClient; private final AtomicReference data = new AtomicReference<>(); + private final Map dataReference = new ConcurrentHashMap<>(); - public ConsumerBackendServiceController(Monitor monitor, OkHttpClient httpClient) { + public ConsumerBackendServiceController(Monitor monitor) { this.monitor = monitor; - this.httpClient = httpClient; } - @Path("/pull") + @Path("/dataReference") @POST @Consumes({ MediaType.APPLICATION_JSON }) - public void pullData(EndpointDataReference dataReference) { - String url = dataReference.getEndpoint(); - monitor.debug("Endpoint Data Reference received, will call data plane at " + url); - var request = new Request.Builder() - .url(url) - .addHeader(dataReference.getAuthKey(), dataReference.getAuthCode()) - .build(); + public void pushDataReference(EndpointDataReference edr) { + monitor.debug("Received new endpoint data reference with url " + edr.getEndpoint()); + dataReference.put(edr.getId(), edr); + } - try (var response = httpClient.newCall(request).execute()) { - var body = response.body(); - var string = body.string(); - if (response.isSuccessful()) { - monitor.info("Data plane responded correctly: " + string); - data.set(string); - } else { - monitor.warning(format("Data plane responded with error: %s %s", response.code(), string)); - } - } catch (Exception e) { - monitor.severe(format("Error in calling the data plane at %s", url), e); - } + @Path("/dataReference/{id}") + @GET + @Produces({ MediaType.APPLICATION_JSON }) + public EndpointDataReference getDataReference(@PathParam("id") String id) { + return Optional.ofNullable(dataReference.get(id)).orElseThrow(NoSuchElementException::new); } @Path("/store") diff --git a/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ProviderBackendApiController.java b/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ProviderBackendApiController.java index bc76fe947c2..e0fca5b2aaf 100644 --- a/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ProviderBackendApiController.java +++ b/system-tests/e2e-transfer-test/backend-service/src/main/java/org/eclipse/dataspaceconnector/test/e2e/ProviderBackendApiController.java @@ -14,20 +14,22 @@ package org.eclipse.dataspaceconnector.test.e2e; +import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import java.util.Map; @Path("/provider") public class ProviderBackendApiController { - + @Path("/data") @GET @Produces(MediaType.APPLICATION_JSON) - public Map getData() { - return Map.of("message", "some information"); + public Map getData(@DefaultValue("some information") @QueryParam("message") String message) { + return Map.of("message", message); } } diff --git a/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/AbstractEndToEndTransfer.java b/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/AbstractEndToEndTransfer.java index 0d3a5397d89..7858921cf39 100644 --- a/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/AbstractEndToEndTransfer.java +++ b/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/AbstractEndToEndTransfer.java @@ -19,6 +19,8 @@ import org.junit.jupiter.api.Test; import java.time.Duration; +import java.util.Map; +import java.util.UUID; import static io.restassured.RestAssured.given; import static org.assertj.core.api.Assertions.assertThat; @@ -37,7 +39,7 @@ public abstract class AbstractEndToEndTransfer { void httpPullDataTransfer() { PROVIDER.registerDataPlane(); CONSUMER.registerDataPlane(); - String definitionId = "1"; + var definitionId = "1"; createAssetAndContractDefinitionOnProvider("asset-id", definitionId, "HttpData"); var catalog = CONSUMER.getCatalog(PROVIDER.idsEndpoint()); @@ -50,29 +52,30 @@ void httpPullDataTransfer() { assertThat(contractAgreementId).isNotEmpty(); - var transferProcessId = CONSUMER.dataRequest(contractAgreementId, assetId, PROVIDER, sync()); + var dataRequestId = UUID.randomUUID().toString(); + var transferProcessId = CONSUMER.dataRequest(dataRequestId, contractAgreementId, assetId, PROVIDER, sync()); await().atMost(timeout).untilAsserted(() -> { var state = CONSUMER.getTransferProcessState(transferProcessId); assertThat(state).isEqualTo(COMPLETED.name()); }); - await().atMost(timeout).untilAsserted(() -> { - given() - .baseUri(CONSUMER.backendService().toString()) - .when() - .get("/api/consumer/data") - .then() - .statusCode(200) - .body("message", equalTo("some information")); - }); + // retrieve the data reference + var edr = CONSUMER.getDataReference(dataRequestId); + + // pull the data without query parameter + await().atMost(timeout).untilAsserted(() -> CONSUMER.pullData(edr, Map.of(), equalTo("some information"))); + + // pull the data with additional query parameter + var msg = UUID.randomUUID().toString(); + await().atMost(timeout).untilAsserted(() -> CONSUMER.pullData(edr, Map.of("message", msg), equalTo(msg))); } @Test void httpPullDataTransferProvisioner() { PROVIDER.registerDataPlane(); CONSUMER.registerDataPlane(); - String definitionId = "1"; + var definitionId = "1"; createAssetAndContractDefinitionOnProvider("asset-id", definitionId, "HttpProvision"); await().atMost(timeout).untilAsserted(() -> { @@ -88,22 +91,16 @@ void httpPullDataTransferProvisioner() { assertThat(contractAgreementId).isNotEmpty(); - var transferProcessId = CONSUMER.dataRequest(contractAgreementId, assetId, PROVIDER, sync()); + var dataRequestId = UUID.randomUUID().toString(); + var transferProcessId = CONSUMER.dataRequest(dataRequestId, contractAgreementId, assetId, PROVIDER, sync()); await().atMost(timeout).untilAsserted(() -> { var state = CONSUMER.getTransferProcessState(transferProcessId); assertThat(state).isEqualTo(COMPLETED.name()); }); - await().atMost(timeout).untilAsserted(() -> { - given() - .baseUri(CONSUMER.backendService().toString()) - .when() - .get("/api/consumer/data") - .then() - .statusCode(200) - .body("message", equalTo("some information")); - }); + var edr = CONSUMER.getDataReference(dataRequestId); + await().atMost(timeout).untilAsserted(() -> CONSUMER.pullData(edr, Map.of(), equalTo("some information"))); } @Test @@ -125,7 +122,7 @@ void httpPushDataTransfer() { var destination = HttpDataAddress.Builder.newInstance() .baseUrl(CONSUMER.backendService() + "/api/consumer/store") .build(); - var transferProcessId = CONSUMER.dataRequest(contractAgreementId, assetId, PROVIDER, destination); + var transferProcessId = CONSUMER.dataRequest(UUID.randomUUID().toString(), contractAgreementId, assetId, PROVIDER, destination); await().atMost(timeout).untilAsserted(() -> { var state = CONSUMER.getTransferProcessState(transferProcessId); diff --git a/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/Participant.java b/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/Participant.java index 4f55144d596..620f642ff4d 100644 --- a/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/Participant.java +++ b/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/dataspaceconnector/test/e2e/Participant.java @@ -24,7 +24,9 @@ import org.eclipse.dataspaceconnector.spi.types.domain.DataAddress; import org.eclipse.dataspaceconnector.spi.types.domain.catalog.Catalog; import org.eclipse.dataspaceconnector.spi.types.domain.contract.offer.ContractOffer; +import org.eclipse.dataspaceconnector.spi.types.domain.edr.EndpointDataReference; import org.eclipse.dataspaceconnector.spi.types.domain.transfer.TransferType; +import org.hamcrest.Matcher; import org.jetbrains.annotations.NotNull; import java.net.URI; @@ -74,7 +76,8 @@ public void createAsset(String assetId, String addressType) { "properties", Map.of( "name", "transfer-test", "baseUrl", backendService + "/api/provider/data", - "type", addressType + "type", addressType, + "proxyQueryParams", "true" ) ) ); @@ -170,8 +173,9 @@ public String getContractAgreementId(String negotiationId) { return contractAgreementId.get(); } - public String dataRequest(String contractAgreementId, String assetId, Participant provider, DataAddress dataAddress) { + public String dataRequest(String id, String contractAgreementId, String assetId, Participant provider, DataAddress dataAddress) { var request = Map.of( + "id", id, "contractId", contractAgreementId, "assetId", assetId, "connectorId", "provider", @@ -207,6 +211,37 @@ public String getTransferProcessState(String transferProcessId) { .extract().body().jsonPath().getString("state"); } + public EndpointDataReference getDataReference(String id) { + var dataReference = new AtomicReference(); + + await().atMost(timeout).untilAsserted(() -> { + var result = given() + .baseUri(backendService.toString()) + .when() + .get("/api/consumer/dataReference/{id}", id) + .then() + .statusCode(200) + .extract() + .body() + .as(EndpointDataReference.class); + dataReference.set(result); + }); + + return dataReference.get(); + } + + public void pullData(EndpointDataReference edr, Map queryParams, Matcher bodyMatcher) { + given() + .baseUri(edr.getEndpoint()) + .header(edr.getAuthKey(), edr.getAuthCode()) + .queryParams(queryParams) + .when() + .get() + .then() + .statusCode(200) + .body("message", bodyMatcher); + } + public URI backendService() { return backendService; } @@ -264,7 +299,7 @@ public Map controlPlaneConfiguration() { put("edc.keystore", resourceAbsolutePath("certs/cert.pfx")); put("edc.keystore.password", "123456"); put("ids.webhook.address", idsEndpoint.toString()); - put("edc.receiver.http.endpoint", backendService + "/api/consumer/pull"); + put("edc.receiver.http.endpoint", backendService + "/api/consumer/dataReference"); put("edc.transfer.proxy.token.signer.privatekey.alias", "1"); put("edc.transfer.proxy.token.verifier.publickey.alias", "public-key"); put("edc.transfer.proxy.endpoint", dataPlanePublic.toString());