From d03cedeec58d7483bf299683d2a3bc965438298b Mon Sep 17 00:00:00 2001 From: Augusto Leal Date: Thu, 26 Oct 2023 15:29:41 -0300 Subject: [PATCH 1/8] feat (ch-edc): create process endpoint included --- .../edc/multipart/MultipartController.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java index 0fdf8a90..a8fbb540 100644 --- a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java +++ b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java @@ -82,10 +82,23 @@ public MultipartController(@NotNull Monitor monitor, @POST @Path("messages/log/{pid}") - public Response request(@PathParam(PID) String pid, + public Response messageRequest(@PathParam(PID) String pid, @FormDataParam(HEADER) InputStream headerInputStream, @FormDataParam(PAYLOAD) String payload) { + return execute(pid, headerInputStream, payload); + } + + @POST + @Path("process/{pid}") + public Response processRequest(@PathParam(PID) String pid, + @FormDataParam(HEADER) InputStream headerInputStream, + @FormDataParam(PAYLOAD) String payload){ + return execute(pid, headerInputStream, payload); + + } + + private Response execute(String pid, InputStream headerInputStream, String payload){ // Check if pid is missing if (pid == null) { monitor.severe(LOG_ID + ": PID is missing"); @@ -208,7 +221,6 @@ public Response request(@PathParam(PID) String pid, .build(); } } - private boolean validateToken(Message header) { var dynamicAttributeToken = new DynamicAttributeTokenBuilder(). From c6662bb21a6e6891f005bac52d2e6ee348af4935 Mon Sep 17 00:00:00 2001 From: Glaucio Jannotti Date: Fri, 27 Oct 2023 18:27:11 -0300 Subject: [PATCH 2/8] chore (ch-edc): create process multipart endpoint --- .../app/delegate/CreateProcessDelegate.java | 69 +++++++++++++++++ .../edc/dto/CreateProcessRequest.java | 35 +++++++++ .../edc/dto/CreateProcessResponse.java | 29 +++++++ .../edc/handler/LogMessageHandler.java | 8 +- .../edc/handler/RequestMessageHandler.java | 69 +++++++++++++++++ .../edc/handler/LogMessageHandlerTest.java | 6 +- .../edc/multipart/MultipartController.java | 77 +++++++++++-------- .../edc/multipart/MultipartExtension.java | 4 +- .../dto/RequestValidationResponse.java | 44 +++++++++++ .../multipart/MultipartControllerTest.java | 18 ++--- 10 files changed, 305 insertions(+), 54 deletions(-) create mode 100644 clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/app/delegate/CreateProcessDelegate.java create mode 100644 clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessRequest.java create mode 100644 clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessResponse.java create mode 100644 clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandler.java create mode 100644 clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/dto/RequestValidationResponse.java diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/app/delegate/CreateProcessDelegate.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/app/delegate/CreateProcessDelegate.java new file mode 100644 index 00000000..2f518157 --- /dev/null +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/app/delegate/CreateProcessDelegate.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 truzzt GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * truzzt GmbH - Initial implementation + * + */ +package de.truzzt.clearinghouse.edc.app.delegate; + +import de.truzzt.clearinghouse.edc.dto.*; +import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; +import de.truzzt.clearinghouse.edc.types.clearinghouse.Context; +import de.truzzt.clearinghouse.edc.types.clearinghouse.Header; +import de.truzzt.clearinghouse.edc.types.clearinghouse.SecurityToken; +import de.truzzt.clearinghouse.edc.types.clearinghouse.TokenFormat; +import okhttp3.ResponseBody; + +public class CreateProcessDelegate implements AppSenderDelegate { + + private final TypeManagerUtil typeManagerUtil; + + public CreateProcessDelegate(TypeManagerUtil typeManagerUtil) { + this.typeManagerUtil = typeManagerUtil; + } + + public String buildRequestUrl(String baseUrl, HandlerRequest handlerRequest) { + return baseUrl + "/process/" + handlerRequest.getPid(); + } + + public CreateProcessRequest buildRequestBody(HandlerRequest handlerRequest) { + var header = handlerRequest.getHeader(); + + var multipartContext = header.getContext(); + var context = new Context(multipartContext.getIds(), multipartContext.getIdsc()); + + var multipartSecurityToken = header.getSecurityToken(); + var multipartTokenFormat = multipartSecurityToken.getTokenFormat(); + var securityToken = SecurityToken.Builder.newInstance(). + type(multipartSecurityToken.getType()). + id(multipartSecurityToken.getId()). + tokenFormat(new TokenFormat(multipartTokenFormat.getId())). + tokenValue(multipartSecurityToken.getTokenValue()). + build(); + + var requestHeader = Header.Builder.newInstance() + .context(context) + .id(header.getId()) + .type(header.getType()) + .securityToken(securityToken) + .issuerConnector(header.getIssuerConnector()) + .modelVersion(header.getModelVersion()) + .issued(header.getIssued()) + .senderAgent(header.getSenderAgent()) + .build(); + + return new CreateProcessRequest(requestHeader, handlerRequest.getPayload()); + } + + @Override + public CreateProcessResponse parseResponseBody(ResponseBody responseBody) { + return typeManagerUtil.parse(responseBody.byteStream(), CreateProcessResponse.class); + } +} diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessRequest.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessRequest.java new file mode 100644 index 00000000..ad3078ac --- /dev/null +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessRequest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 truzzt GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * truzzt GmbH - Initial implementation + * + */ +package de.truzzt.clearinghouse.edc.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import de.truzzt.clearinghouse.edc.types.clearinghouse.Header; +import org.jetbrains.annotations.NotNull; + +public class CreateProcessRequest { + + @JsonProperty("header") + @NotNull + private final Header header; + + @JsonProperty("payload") + @NotNull + private final String payload; + + public CreateProcessRequest(@NotNull Header header, @NotNull String payload) { + this.header = header; + this.payload = payload; + } +} + diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessResponse.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessResponse.java new file mode 100644 index 00000000..fb591d41 --- /dev/null +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/dto/CreateProcessResponse.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 truzzt GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * truzzt GmbH - Initial implementation + * + */ +package de.truzzt.clearinghouse.edc.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.jetbrains.annotations.NotNull; + +public class CreateProcessResponse { + + @JsonProperty("pid") + @NotNull + private String pid; + + public String getPid() { + return pid; + } + +} \ No newline at end of file diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandler.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandler.java index 2d48528a..26b41046 100644 --- a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandler.java +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandler.java @@ -20,7 +20,6 @@ import de.truzzt.clearinghouse.edc.dto.HandlerResponse; import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; import org.eclipse.edc.protocol.ids.spi.types.IdsId; -import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.jetbrains.annotations.NotNull; @@ -32,22 +31,17 @@ public class LogMessageHandler implements Handler { - private final Monitor monitor; private final IdsId connectorId; - private final TypeManagerUtil typeManagerUtil; private final AppSender appSender; private final LoggingMessageDelegate senderDelegate; private final ServiceExtensionContext context; - public LogMessageHandler(Monitor monitor, - IdsId connectorId, + public LogMessageHandler(IdsId connectorId, TypeManagerUtil typeManagerUtil, AppSender appSender, ServiceExtensionContext context) { - this.monitor = monitor; this.connectorId = connectorId; - this.typeManagerUtil = typeManagerUtil; this.appSender = appSender; this.context = context; diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandler.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandler.java new file mode 100644 index 00000000..6a0cd0ef --- /dev/null +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 truzzt GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * truzzt GmbH - Initial implementation + * + */ +package de.truzzt.clearinghouse.edc.handler; + +import de.truzzt.clearinghouse.edc.app.AppSender; +import de.truzzt.clearinghouse.edc.app.delegate.CreateProcessDelegate; +import de.truzzt.clearinghouse.edc.dto.AppSenderRequest; +import de.truzzt.clearinghouse.edc.dto.HandlerRequest; +import de.truzzt.clearinghouse.edc.dto.HandlerResponse; +import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; +import org.eclipse.edc.protocol.ids.spi.types.IdsId; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.jetbrains.annotations.NotNull; + +import static de.truzzt.clearinghouse.edc.util.ResponseUtil.createMultipartResponse; +import static de.truzzt.clearinghouse.edc.util.ResponseUtil.messageProcessedNotification; +import static de.truzzt.clearinghouse.edc.util.SettingsConstants.APP_BASE_URL_DEFAULT_VALUE; +import static de.truzzt.clearinghouse.edc.util.SettingsConstants.APP_BASE_URL_SETTING; + +public class RequestMessageHandler implements Handler { + + private final IdsId connectorId; + private final AppSender appSender; + private final CreateProcessDelegate senderDelegate; + + private final ServiceExtensionContext context; + + public RequestMessageHandler(IdsId connectorId, + TypeManagerUtil typeManagerUtil, + AppSender appSender, + ServiceExtensionContext context) { + this.connectorId = connectorId; + this.appSender = appSender; + this.context = context; + + this.senderDelegate = new CreateProcessDelegate(typeManagerUtil); + } + + @Override + public boolean canHandle(@NotNull HandlerRequest handlerRequest) { + return handlerRequest.getHeader().getType().equals("ids:RequestMessage"); + } + + @Override + public @NotNull HandlerResponse handleRequest(@NotNull HandlerRequest handlerRequest) { + var baseUrl = context.getSetting(APP_BASE_URL_SETTING, APP_BASE_URL_DEFAULT_VALUE); + var header = handlerRequest.getHeader(); + + var url = senderDelegate.buildRequestUrl(baseUrl, handlerRequest); + var token = buildJWTToken(handlerRequest.getHeader().getSecurityToken(), context); + var body = senderDelegate.buildRequestBody(handlerRequest); + + var request = AppSenderRequest.Builder.newInstance().url(url).token(token).body(body).build(); + + var response = appSender.send(request, senderDelegate); + return createMultipartResponse(messageProcessedNotification(header, connectorId), response); + } +} diff --git a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandlerTest.java b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandlerTest.java index f72e158f..5d9e2b9e 100644 --- a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandlerTest.java +++ b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/LogMessageHandlerTest.java @@ -12,8 +12,6 @@ import okhttp3.ResponseBody; import org.eclipse.edc.protocol.ids.spi.types.IdsId; import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.http.EdcHttpClient; -import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -28,8 +26,6 @@ import static org.mockito.Mockito.spy; class LogMessageHandlerTest { - @Mock - private Monitor monitor; @Mock private IdsId connectorId; @Mock @@ -49,7 +45,7 @@ class LogMessageHandlerTest { public void setUp() { MockitoAnnotations.openMocks(this); senderDelegate = spy(new LoggingMessageDelegate(typeManagerUtil)); - logMessageHandler = spy(new LogMessageHandler(monitor, connectorId, typeManagerUtil, appSender, context)); + logMessageHandler = spy(new LogMessageHandler(connectorId, typeManagerUtil, appSender, context)); } @Test diff --git a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java index a8fbb540..4adc31d7 100644 --- a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java +++ b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java @@ -18,6 +18,7 @@ import de.truzzt.clearinghouse.edc.handler.Handler; import de.truzzt.clearinghouse.edc.dto.HandlerRequest; import de.truzzt.clearinghouse.edc.dto.HandlerResponse; +import de.truzzt.clearinghouse.edc.multipart.dto.RequestValidationResponse; import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; import de.truzzt.clearinghouse.edc.types.ids.Message; @@ -82,37 +83,51 @@ public MultipartController(@NotNull Monitor monitor, @POST @Path("messages/log/{pid}") - public Response messageRequest(@PathParam(PID) String pid, - @FormDataParam(HEADER) InputStream headerInputStream, - @FormDataParam(PAYLOAD) String payload) { - return execute(pid, headerInputStream, payload); + public Response logMessage(@PathParam(PID) String pid, + @FormDataParam(HEADER) InputStream headerInputStream, + @FormDataParam(PAYLOAD) String payload) { + var response = validaRequest(pid, headerInputStream); + if (response.fail()) + return response.getError(); + // Check if payload is missing + if (payload == null) { + monitor.severe(LOG_ID + ": Payload is missing"); + return Response.status(Response.Status.BAD_REQUEST) + .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId))) + .build(); + } + + return processRequest(pid, response.getHeader(), payload); } @POST @Path("process/{pid}") - public Response processRequest(@PathParam(PID) String pid, - @FormDataParam(HEADER) InputStream headerInputStream, - @FormDataParam(PAYLOAD) String payload){ - return execute(pid, headerInputStream, payload); - + public Response createProcess(@PathParam(PID) String pid, + @FormDataParam(HEADER) InputStream headerInputStream, + @FormDataParam(PAYLOAD) String payload){ + var response = validaRequest(pid, headerInputStream); + if (response.fail()) + return response.getError(); + + return processRequest(pid, response.getHeader(), payload); } - private Response execute(String pid, InputStream headerInputStream, String payload){ + private RequestValidationResponse validaRequest(String pid, InputStream headerInputStream){ // Check if pid is missing if (pid == null) { monitor.severe(LOG_ID + ": PID is missing"); - return Response.status(Response.Status.BAD_REQUEST) + return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId))) - .build(); + .build()); } // Check if header is missing if (headerInputStream == null) { monitor.severe(LOG_ID + ": Header is missing"); - return Response.status(Response.Status.BAD_REQUEST) + return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId))) - .build(); + .build()); } // Convert header to message @@ -121,9 +136,9 @@ private Response execute(String pid, InputStream headerInputStream, String paylo header = typeManagerUtil.parse(headerInputStream, Message.class); } catch (Exception e) { monitor.severe(format(LOG_ID + ": Header parsing failed: %s", e.getMessage())); - return Response.status(Response.Status.BAD_REQUEST) + return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId))) - .build(); + .build()); } // Check if any required header field missing @@ -137,44 +152,41 @@ private Response execute(String pid, InputStream headerInputStream, String paylo || header.getSenderAgent() == null || (header.getSenderAgent() != null && StringUtils.isNullOrBlank(header.getSenderAgent().toString())) ) { - return Response.status(Response.Status.BAD_REQUEST) + return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(header, connectorId))) - .build(); + .build()); } // Check if security token is present var securityToken = header.getSecurityToken(); if (securityToken == null || securityToken.getTokenValue() == null) { monitor.severe(LOG_ID + ": Token is missing in header"); - return Response.status(Response.Status.BAD_REQUEST) + return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, notAuthenticated(header, connectorId))) - .build(); + .build()); } // Check the security token type var tokenFormat = securityToken.getTokenFormat().getId().toString(); if (!tokenFormat.equals(TokenFormat.JWT_TOKEN_FORMAT)) { monitor.severe(LOG_ID + ": Invalid security token type: " + tokenFormat); - return Response.status(Response.Status.BAD_REQUEST) + return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId))) - .build(); - } - - // Check if payload is missing - if (payload == null) { - monitor.severe(LOG_ID + ": Payload is missing"); - return Response.status(Response.Status.BAD_REQUEST) - .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId))) - .build(); + .build()); } // Validate DAT if (!validateToken(header)) { - return Response.status(Response.Status.FORBIDDEN) + return new RequestValidationResponse(Response.status(Response.Status.FORBIDDEN) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, notAuthenticated(header, connectorId))) - .build(); + .build()); } + return new RequestValidationResponse(header); + } + + private Response processRequest(String pid, Message header, String payload){ + // Build the multipart request var multipartRequest = HandlerRequest.Builder.newInstance() .pid(pid) @@ -221,6 +233,7 @@ private Response execute(String pid, InputStream headerInputStream, String paylo .build(); } } + private boolean validateToken(Message header) { var dynamicAttributeToken = new DynamicAttributeTokenBuilder(). diff --git a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartExtension.java b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartExtension.java index 59d3cc6c..a36a7334 100644 --- a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartExtension.java +++ b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartExtension.java @@ -17,6 +17,7 @@ import de.truzzt.clearinghouse.edc.handler.Handler; import de.truzzt.clearinghouse.edc.handler.LogMessageHandler; import de.truzzt.clearinghouse.edc.app.AppSender; +import de.truzzt.clearinghouse.edc.handler.RequestMessageHandler; import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; import org.eclipse.edc.protocol.ids.api.configuration.IdsApiConfiguration; @@ -73,7 +74,8 @@ public void initialize(ServiceExtensionContext context) { var clearingHouseAppSender = new AppSender(monitor, httpClient, typeManagerUtil); var handlers = new LinkedList(); - handlers.add(new LogMessageHandler(monitor, connectorId, typeManagerUtil, clearingHouseAppSender, context)); + handlers.add(new RequestMessageHandler(connectorId, typeManagerUtil, clearingHouseAppSender, context)); + handlers.add(new LogMessageHandler(connectorId, typeManagerUtil, clearingHouseAppSender, context)); var multipartController = new MultipartController(monitor, connectorId, diff --git a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/dto/RequestValidationResponse.java b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/dto/RequestValidationResponse.java new file mode 100644 index 00000000..ba89ccb6 --- /dev/null +++ b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/dto/RequestValidationResponse.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 truzzt GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * truzzt GmbH - Initial implementation + * + */ +package de.truzzt.clearinghouse.edc.multipart.dto; + +import de.truzzt.clearinghouse.edc.types.ids.Message; +import jakarta.ws.rs.core.Response; +import org.jetbrains.annotations.NotNull; + +public class RequestValidationResponse { + + private Response error; + private Message header; + + public RequestValidationResponse(@NotNull Response error) { + this.error = error; + } + public RequestValidationResponse(@NotNull Message header) { + this.header = header; + } + + public Response getError() { + return error; + } + + public Message getHeader() { + return header; + } + + public Boolean fail() { + return (error != null); + } + +} diff --git a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java index 3b7861ed..7f9d1068 100644 --- a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java +++ b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java @@ -106,7 +106,7 @@ public void success() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.VALID_HEADER_JSON); - var response = controller.request(pid, header, PAYLOAD); + var response = controller.logMessage(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); @@ -122,7 +122,7 @@ public void success() { public void missingPIDError() { var header = TestUtils.getHeaderInputStream(TestUtils.VALID_HEADER_JSON); - var response = controller.request(null, header, PAYLOAD); + var response = controller.logMessage(null, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -137,7 +137,7 @@ public void missingPIDError() { public void missingHeaderError() { var pid = UUID.randomUUID().toString(); - var response = controller.request(pid, null, PAYLOAD); + var response = controller.logMessage(pid, null, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -153,7 +153,7 @@ public void invalidHeaderError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.INVALID_HEADER_JSON); - var response = controller.request(pid, header, PAYLOAD); + var response = controller.logMessage(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -169,7 +169,7 @@ public void missingHeaderFieldsError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.MISSING_FIELDS_HEADER_JSON); - var response = controller.request(pid, header, PAYLOAD); + var response = controller.logMessage(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -188,7 +188,7 @@ public void invalidSecurityTokenError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.INVALID_TOKEN_HEADER_JSON); - var response = controller.request(pid, header, PAYLOAD); + var response = controller.logMessage(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.getStatus()); @@ -204,7 +204,7 @@ public void missingSecurityTokenError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.MISSING_TOKEN_HEADER_JSON); - var response = controller.request(pid, header, PAYLOAD); + var response = controller.logMessage(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -220,7 +220,7 @@ public void missingPayloadError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.VALID_HEADER_JSON); - var response = controller.request(pid, header, null); + var response = controller.logMessage(pid, header, null); assertNotNull(response); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -241,7 +241,7 @@ public void invalidMessageTypeError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.INVALID_TYPE_HEADER_JSON); - var response = controller.request(pid, header, PAYLOAD); + var response = controller.logMessage(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); From 75e89cf0a13ebc432dfc59badb706ad49a118f0c Mon Sep 17 00:00:00 2001 From: Augusto Leal Date: Mon, 30 Oct 2023 19:17:03 -0300 Subject: [PATCH 3/8] feat (ch-edc): create process test included --- .../edc/multipart/MultipartController.java | 4 +- .../multipart/MultipartControllerTest.java | 85 ++++++++++++++----- .../edc/multipart/tests/TestUtils.java | 5 ++ .../headers/valid-create-process-header.json | 20 +++++ 4 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json diff --git a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java index 4adc31d7..a566cd7d 100644 --- a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java +++ b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java @@ -113,7 +113,7 @@ public Response createProcess(@PathParam(PID) String pid, return processRequest(pid, response.getHeader(), payload); } - private RequestValidationResponse validaRequest(String pid, InputStream headerInputStream){ + RequestValidationResponse validaRequest(String pid, InputStream headerInputStream){ // Check if pid is missing if (pid == null) { monitor.severe(LOG_ID + ": PID is missing"); @@ -185,7 +185,7 @@ private RequestValidationResponse validaRequest(String pid, InputStream headerIn return new RequestValidationResponse(header); } - private Response processRequest(String pid, Message header, String payload){ + Response processRequest(String pid, Message header, String payload){ // Build the multipart request var multipartRequest = HandlerRequest.Builder.newInstance() diff --git a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java index 7f9d1068..7143fd19 100644 --- a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java +++ b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java @@ -7,6 +7,8 @@ import de.truzzt.clearinghouse.edc.dto.LoggingMessageResponse; import de.truzzt.clearinghouse.edc.handler.Handler; import de.truzzt.clearinghouse.edc.handler.LogMessageHandler; +import de.truzzt.clearinghouse.edc.handler.RequestMessageHandler; +import de.truzzt.clearinghouse.edc.multipart.dto.RequestValidationResponse; import de.truzzt.clearinghouse.edc.multipart.tests.TestUtils; import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; import de.truzzt.clearinghouse.edc.types.ids.Message; @@ -23,6 +25,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.io.*; import java.net.URI; @@ -32,13 +35,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyByte; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; public class MultipartControllerTest { private static final String IDS_WEBHOOK_ADDRESS = "http://localhost/callback"; private static final String PAYLOAD = "Hello World"; + private static final String CREATE_PROCESS_PAYLOAD = "{ \"owners\": [\"1\", \"2\"]}"; private MultipartController controller; @@ -52,6 +60,9 @@ public class MultipartControllerTest { @Mock private LogMessageHandler logMessageHandler; + @Mock + private RequestMessageHandler requestMessageHandler; + private final ObjectMapper mapper = new ObjectMapper(); @BeforeEach @@ -92,7 +103,7 @@ private T extractPayload(Response response, Class type) { } @Test - public void success() { + public void logMessageSuccess() { var responseHeader = TestUtils.getValidResponseHeader(mapper); var responsePayload = TestUtils.getValidResponsePayload(mapper); @@ -110,7 +121,7 @@ public void success() { assertNotNull(response); assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); - + var message = extractHeader(response, Message.class); assertEquals("ids:LogMessage", message.getType()); @@ -118,16 +129,43 @@ public void success() { assertNotNull(payload.getData()); } + @Test + public void createProcessSuccess() { + var responseHeader = TestUtils.getValidResponseHeader(mapper); + var responsePayload = TestUtils.getValidResponsePayload(mapper); + + doReturn(Result.success()) + .when(tokenService).verifyDynamicAttributeToken(any(DynamicAttributeToken.class), any(URI.class), any(String.class)); + doReturn(true) + .when(requestMessageHandler).canHandle(any(HandlerRequest.class)); + doReturn(HandlerResponse.Builder.newInstance().header(responseHeader).payload(responsePayload).build()) + .when(requestMessageHandler).handleRequest(any(HandlerRequest.class)); + + var pid = UUID.randomUUID().toString(); + var header = TestUtils.getHeaderInputStream(TestUtils.VALID_CREATE_PROCESS_HEADER_JSON); + + var response = controller.createProcess(pid, header, CREATE_PROCESS_PAYLOAD); + + assertNotNull(response); + assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); + + var message = extractHeader(response, Message.class); + assertEquals("ids:RequestMessage", message.getType()); + + var payload = extractPayload(response, LoggingMessageResponse.class); + assertNotNull(payload.getData()); + } + @Test public void missingPIDError() { var header = TestUtils.getHeaderInputStream(TestUtils.VALID_HEADER_JSON); - var response = controller.logMessage(null, header, PAYLOAD); + var response = controller.validaRequest(null, header); assertNotNull(response); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(response.fail()); - var message = extractHeader(response, RejectionMessage.class); + var message = extractHeader(response.getError(), RejectionMessage.class); assertNotNull(message.getRejectionReason()); assertEquals(RejectionReason.MALFORMED_MESSAGE.getId(), message.getRejectionReason().getId()); @@ -137,12 +175,12 @@ public void missingPIDError() { public void missingHeaderError() { var pid = UUID.randomUUID().toString(); - var response = controller.logMessage(pid, null, PAYLOAD); + var response = controller.validaRequest(pid, null); assertNotNull(response); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(response.fail()); - var message = extractHeader(response, RejectionMessage.class); + var message = extractHeader(response.getError(), RejectionMessage.class); assertNotNull(message.getRejectionReason()); assertEquals(RejectionReason.MALFORMED_MESSAGE.getId(), message.getRejectionReason().getId()); @@ -153,12 +191,12 @@ public void invalidHeaderError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.INVALID_HEADER_JSON); - var response = controller.logMessage(pid, header, PAYLOAD); + var response = controller.validaRequest(pid, header); assertNotNull(response); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(response.fail()); - var message = extractHeader(response, RejectionMessage.class); + var message = extractHeader(response.getError(), RejectionMessage.class); assertNotNull(message.getRejectionReason()); assertEquals(RejectionReason.MALFORMED_MESSAGE.getId(), message.getRejectionReason().getId()); @@ -169,12 +207,12 @@ public void missingHeaderFieldsError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.MISSING_FIELDS_HEADER_JSON); - var response = controller.logMessage(pid, header, PAYLOAD); + var response = controller.validaRequest(pid, header); assertNotNull(response); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(response.fail()); - var message = extractHeader(response, RejectionMessage.class); + var message = extractHeader(response.getError(), RejectionMessage.class); assertNotNull(message.getRejectionReason()); assertEquals(RejectionReason.MALFORMED_MESSAGE.getId(), message.getRejectionReason().getId()); @@ -188,12 +226,12 @@ public void invalidSecurityTokenError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.INVALID_TOKEN_HEADER_JSON); - var response = controller.logMessage(pid, header, PAYLOAD); + var response = controller.validaRequest(pid, header); assertNotNull(response); - assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.getStatus()); + assertTrue(response.fail()); - var message = extractHeader(response, RejectionMessage.class); + var message = extractHeader(response.getError(), RejectionMessage.class); assertNotNull(message.getRejectionReason()); assertEquals(RejectionReason.NOT_AUTHENTICATED.getId(), message.getRejectionReason().getId()); @@ -204,12 +242,12 @@ public void missingSecurityTokenError() { var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.MISSING_TOKEN_HEADER_JSON); - var response = controller.logMessage(pid, header, PAYLOAD); + var response = controller.validaRequest(pid, header); assertNotNull(response); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(response.fail()); - var message = extractHeader(response, RejectionMessage.class); + var message = extractHeader(response.getError(), RejectionMessage.class); assertNotNull(message.getRejectionReason()); assertEquals(RejectionReason.NOT_AUTHENTICATED.getId(), message.getRejectionReason().getId()); @@ -217,6 +255,9 @@ public void missingSecurityTokenError() { @Test public void missingPayloadError() { + doReturn(Result.success()) + .when(tokenService).verifyDynamicAttributeToken(any(DynamicAttributeToken.class), any(URI.class), any(String.class)); + var pid = UUID.randomUUID().toString(); var header = TestUtils.getHeaderInputStream(TestUtils.VALID_HEADER_JSON); @@ -239,9 +280,9 @@ public void invalidMessageTypeError() { .when(logMessageHandler).canHandle(any(HandlerRequest.class)); var pid = UUID.randomUUID().toString(); - var header = TestUtils.getHeaderInputStream(TestUtils.INVALID_TYPE_HEADER_JSON); + var header = TestUtils.getResponseHeader(new ObjectMapper(), TestUtils.INVALID_TYPE_HEADER_JSON); - var response = controller.logMessage(pid, header, PAYLOAD); + var response = controller.processRequest(pid, header, PAYLOAD); assertNotNull(response); assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); diff --git a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/tests/TestUtils.java b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/tests/TestUtils.java index 4cda33e2..00e6d817 100644 --- a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/tests/TestUtils.java +++ b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/tests/TestUtils.java @@ -11,6 +11,7 @@ public class TestUtils extends BaseTestUtils { public static final String VALID_HEADER_JSON = "headers/valid-header.json"; + public static final String VALID_CREATE_PROCESS_HEADER_JSON = "headers/valid-create-process-header.json"; public static final String INVALID_HEADER_JSON = "headers/invalid-header.json"; public static final String INVALID_TYPE_HEADER_JSON = "headers/invalid-type.json"; public static final String INVALID_TOKEN_HEADER_JSON = "headers/invalid-token.json"; @@ -25,6 +26,10 @@ public static InputStream getHeaderInputStream(String path) { return new ByteArrayInputStream(json.getBytes()); } + public static Message getResponseHeader(ObjectMapper mapper, String path) { + return parseFile(mapper, Message.class, path); + } + public static Message getValidResponseHeader(ObjectMapper mapper) { return parseFile(mapper, Message.class, VALID_RESPONSE_HEADER_JSON); } diff --git a/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json b/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json new file mode 100644 index 00000000..bb2eb204 --- /dev/null +++ b/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json @@ -0,0 +1,20 @@ +{ + "@context":{ + "ids" : "https://w3id.org/idsa/core/", + "idsc" : "https://w3id.org/idsa/code/" + }, + "@type":"ids:RequestMessage", + "@id":"https://w3id.org/idsa/autogen/logMessage/9fdba4ad-f750-4bbc-a7f0-f648ac853508", + "ids:securityToken": { + "@type" : "ids:DynamicAttributeToken", + "@id" : "https://w3id.org/idsa/autogen/dynamicAttributeToken/7bbbd2c1-2d75-4e3d-bd10-c52d0381cab0", + "ids:tokenValue" : "eyJ0eXAiOiJKV1QiLCJraWQiOiJkZWZhdWx0IiwiYWxnIjoiUlMyNTYifQ.eyJzY29wZXMiOlsiaWRzYzpJRFNfQ09OTkVDVE9SX0FUVFJJQlVURVNfQUxMIl0sImF1ZCI6Imlkc2M6SURTX0NPTk5FQ1RPUlNfQUxMIiwiaXNzIjoiaHR0cHM6Ly9kYXBzLmFpc2VjLmZyYXVuaG9mZXIuZGUiLCJuYmYiOjE2MzQ2NTA3MzksImlhdCI6MTYzNDY1MDczOSwianRpIjoiTVRneE9EUXdPVFF6TXpZd05qWXlOVFExTUE9PSIsImV4cCI6MTYzNDY1NDMzOSwic2VjdXJpdHlQcm9maWxlIjoiaWRzYzpCQVNFX1NFQ1VSSVRZX1BST0ZJTEUiLCJyZWZlcnJpbmdDb25uZWN0b3IiOiJodHRwOi8vYnJva2VyLmlkcy5pc3N0LmZyYXVuaG9mZXIuZGUuZGVtbyIsIkB0eXBlIjoiaWRzOkRhdFBheWxvYWQiLCJAY29udGV4dCI6Imh0dHBzOi8vdzNpZC5vcmcvaWRzYS9jb250ZXh0cy9jb250ZXh0Lmpzb25sZCIsInRyYW5zcG9ydENlcnRzU2hhMjU2IjoiOTc0ZTYzMjRmMTJmMTA5MTZmNDZiZmRlYjE4YjhkZDZkYTc4Y2M2YTZhMDU2NjAzMWZhNWYxYTM5ZWM4ZTYwMCIsInN1YiI6IjkyOjE0OkU3OkFDOjEwOjIyOkYyOkNDOjA1OjZFOjJBOjJCOjhEOkRCOjEwOkQ2OjREOkEwOkExOjUzOmtleWlkOkNCOjhDOkM3OkI2Ojg1Ojc5OkE4OjIzOkE2OkNCOjE1OkFCOjE3OjUwOjJGOkU2OjY1OjQzOjVEOkU4In0.Qw3gWMgwnKQyVatbsozcin6qtQbLyXlk6QdaLajGaDmxSYqCKEcAje4kiDp5Fqj04WPmVyF0k8c1BJA3KGnaW3Qcikv4MNxqqoenvKIrSTokXsA7-osqBCfxLhV-s2lSXVTAtV_Q7f71eSoR5j-7nPPX8_nf4Xup4_VzfnwRmnuAbLfHfWThbupxFazC34r3waXCltOTFVa_XDlwEDMpPY7vEPeaqIt2t6ofVGo_HF86UB19liL-UZvp0uSE9z2fhloyxOrx9B_xavGS7pP6oRaumSJEN_x9dfdeDS98HQ_oBSSGBzaI4fM7ik35Yg42KQwmkZesD6P_YSEzVLcJDg", + "ids:tokenFormat" : { + "@id" : "idsc:JWT" + } + }, + "ids:senderAgent":"http://example.org", + "ids:modelVersion":"4.1.0", + "ids:issued" : "2021-06-23T17:27:23.566+02:00", + "ids:issuerConnector" : "https://companyA.com/connector/59a68243-dd96-4c8d-88a9-0f0e03e13b1b" +} \ No newline at end of file From 610fc8910af7edf3690989f7f24f83b6f81ce934 Mon Sep 17 00:00:00 2001 From: Augusto Leal Date: Tue, 31 Oct 2023 09:40:47 -0300 Subject: [PATCH 4/8] feat (ch-edc): create process test working --- .../clearinghouse/edc/multipart/MultipartControllerTest.java | 4 ++-- .../test/resources/headers/valid-create-process-header.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java index 7143fd19..ef2d40b8 100644 --- a/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java +++ b/clearing-house-edc/extensions/multipart/src/test/java/de/truzzt/clearinghouse/edc/multipart/MultipartControllerTest.java @@ -72,7 +72,7 @@ public void setUp() { connectorId = IdsId.Builder.newInstance().type(IdsType.CONNECTOR).value("http://test.connector").build(); typeManagerUtil = new TypeManagerUtil(new ObjectMapper()); - List multipartHandlers = List.of(logMessageHandler); + List multipartHandlers = List.of(logMessageHandler, requestMessageHandler); controller = new MultipartController(monitor, connectorId, typeManagerUtil, tokenService, IDS_WEBHOOK_ADDRESS, multipartHandlers); } @@ -131,7 +131,7 @@ public void logMessageSuccess() { @Test public void createProcessSuccess() { - var responseHeader = TestUtils.getValidResponseHeader(mapper); + var responseHeader = TestUtils.getResponseHeader(mapper, TestUtils.VALID_CREATE_PROCESS_HEADER_JSON); var responsePayload = TestUtils.getValidResponsePayload(mapper); doReturn(Result.success()) diff --git a/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json b/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json index bb2eb204..a1cd612f 100644 --- a/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json +++ b/clearing-house-edc/extensions/multipart/src/test/resources/headers/valid-create-process-header.json @@ -17,4 +17,5 @@ "ids:modelVersion":"4.1.0", "ids:issued" : "2021-06-23T17:27:23.566+02:00", "ids:issuerConnector" : "https://companyA.com/connector/59a68243-dd96-4c8d-88a9-0f0e03e13b1b" -} \ No newline at end of file +} + From a7103cedced9c00fed5879d137e11d45b5ae0142 Mon Sep 17 00:00:00 2001 From: Augusto Leal Date: Tue, 31 Oct 2023 14:58:44 -0300 Subject: [PATCH 5/8] feat (ch-edc): RequestMessageHandler tests included --- .../handler/RequestMessageHandlerTest.java | 114 ++++++++++++++++++ .../clearinghouse/edc/tests/TestUtils.java | 54 +++++++++ .../headers/valid-create-process-header.json | 21 ++++ 3 files changed, 189 insertions(+) create mode 100644 clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandlerTest.java create mode 100644 clearing-house-edc/core/src/test/resources/headers/valid-create-process-header.json diff --git a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandlerTest.java b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandlerTest.java new file mode 100644 index 00000000..5c9032b9 --- /dev/null +++ b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/handler/RequestMessageHandlerTest.java @@ -0,0 +1,114 @@ +package de.truzzt.clearinghouse.edc.handler; + +import com.auth0.jwt.JWT; +import com.fasterxml.jackson.databind.ObjectMapper; +import de.truzzt.clearinghouse.edc.app.AppSender; +import de.truzzt.clearinghouse.edc.app.delegate.CreateProcessDelegate; +import de.truzzt.clearinghouse.edc.app.delegate.LoggingMessageDelegate; +import de.truzzt.clearinghouse.edc.dto.HandlerRequest; +import de.truzzt.clearinghouse.edc.dto.HandlerResponse; +import de.truzzt.clearinghouse.edc.tests.TestUtils; +import de.truzzt.clearinghouse.edc.types.TypeManagerUtil; +import de.truzzt.clearinghouse.edc.types.ids.SecurityToken; +import okhttp3.ResponseBody; +import org.eclipse.edc.protocol.ids.spi.types.IdsId; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static de.truzzt.clearinghouse.edc.util.SettingsConstants.APP_BASE_URL_DEFAULT_VALUE; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +class RequestMessageHandlerTest { + + @Mock + private IdsId connectorId; + @Mock + private TypeManagerUtil typeManagerUtil; + @Mock + private AppSender appSender; + @Mock + private ServiceExtensionContext context; + + @Mock + private CreateProcessDelegate createProcessDelegate; + @Mock + private RequestMessageHandler requestMessageHandler; + + private final ObjectMapper mapper = new ObjectMapper(); + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + requestMessageHandler = spy(new RequestMessageHandler(connectorId, typeManagerUtil, appSender, context)); + } + @Test + void successfulCanHandle() { + HandlerRequest request = TestUtils.getValidHandlerCreateProcessRequest(mapper); + + Boolean response = requestMessageHandler.canHandle(request); + + assertNotNull(response); + assertEquals(true, response); + } + + @Test + public void invalidMessageTypeCanHandle(){ + + HandlerRequest request = TestUtils.getInvalidHandlerRequest(mapper); + + Boolean response = requestMessageHandler.canHandle(request); + + assertNotNull(response); + assertEquals(response, false); + } + + @Test + public void successfulHandleRequest(){ + HandlerRequest request = TestUtils.getValidHandlerRequest(mapper); + doReturn(JWT.create().toString()) + .when(requestMessageHandler).buildJWTToken(any(SecurityToken.class), any(ServiceExtensionContext.class)); + + doReturn(TestUtils.getValidCreateProcessResponse(TestUtils.getValidAppSenderRequest(mapper).getUrl(), mapper)) + .when(createProcessDelegate).parseResponseBody(any(ResponseBody.class)); + + doReturn(APP_BASE_URL_DEFAULT_VALUE+ "/process/" + request.getPid()) + .when(createProcessDelegate) + .buildRequestUrl(any(String.class), any(HandlerRequest.class)); + + doReturn(TestUtils.getValidCreateProcessRequest(request)) + .when(createProcessDelegate).buildRequestBody(any(HandlerRequest.class)); + + HandlerResponse response = requestMessageHandler.handleRequest(request); + + assertNotNull(response); + assertEquals(response.getHeader().getType(), "ids:MessageProcessedNotificationMessage"); + } + + @Test + public void missingSubjectBuildJwtToken() { + EdcException exception = assertThrows(EdcException.class, () -> requestMessageHandler.buildJWTToken( + TestUtils.getInvalidTokenHandlerRequest(mapper) + .getHeader() + .getSecurityToken(), context)); + + assertEquals("JWT Token subject is missing",exception.getMessage()); + } + @Test + public void successfulBuildJwtToken() { + doReturn("1").when(context).getSetting(anyString(), anyString()); + var response = requestMessageHandler.buildJWTToken( + TestUtils.getValidHandlerRequest(mapper) + .getHeader() + .getSecurityToken(), context); + + assertNotNull(response); + } +} \ No newline at end of file diff --git a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/tests/TestUtils.java b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/tests/TestUtils.java index f1a4458b..44e236d4 100644 --- a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/tests/TestUtils.java +++ b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/tests/TestUtils.java @@ -3,6 +3,8 @@ import com.auth0.jwt.JWT; import com.fasterxml.jackson.databind.ObjectMapper; import de.truzzt.clearinghouse.edc.dto.AppSenderRequest; +import de.truzzt.clearinghouse.edc.dto.CreateProcessRequest; +import de.truzzt.clearinghouse.edc.dto.CreateProcessResponse; import de.truzzt.clearinghouse.edc.dto.HandlerRequest; import de.truzzt.clearinghouse.edc.dto.LoggingMessageRequest; import de.truzzt.clearinghouse.edc.dto.LoggingMessageResponse; @@ -23,7 +25,9 @@ public class TestUtils extends BaseTestUtils { public static final String TEST_BASE_URL = "http://localhost:8000"; private static final String TEST_PAYLOAD = "Hello World"; + private static final String TEST_CREATE_PROCCESS_PAYLOAD = "{ \"owners\": [\"1\", \"2\"]}";; private static final String VALID_HEADER_JSON = "headers/valid-header.json"; + private static final String VALID_CREATE_PROCESS_HEADER_JSON = "headers/valid-create-process-header.json"; private static final String INVALID_HEADER_JSON = "headers/invalid-header.json"; private static final String INVALID_TYPE_HEADER_JSON = "headers/invalid-type.json"; private static final String INVALID_TOKEN_HEADER_JSON = "headers/invalid-token.json"; @@ -32,6 +36,10 @@ public static Message getValidHeader(ObjectMapper mapper) { return parseFile(mapper, Message.class, VALID_HEADER_JSON); } + public static Message getValidCreateProcessHeader(ObjectMapper mapper) { + return parseFile(mapper, Message.class, VALID_CREATE_PROCESS_HEADER_JSON); + } + public static Message getInvalidTokenHeader(ObjectMapper mapper) { return parseFile(mapper, Message.class, INVALID_TOKEN_HEADER_JSON); } @@ -90,6 +98,15 @@ public static LoggingMessageResponse getValidLoggingMessageResponse(String url, } } + public static CreateProcessResponse getValidCreateProcessResponse(String url, ObjectMapper mapper) { + try { + return mapper.readValue(getValidResponse(url).body().byteStream(), CreateProcessResponse.class); + + } catch (IOException e) { + throw new EdcException("Error parsing response", e); + } + } + public static LoggingMessageRequest getValidLoggingMessageRequest(HandlerRequest handlerRequest) { var header = handlerRequest.getHeader(); @@ -120,6 +137,36 @@ public static LoggingMessageRequest getValidLoggingMessageRequest(HandlerRequest return new LoggingMessageRequest(requestHeader, handlerRequest.getPayload()); } + public static CreateProcessRequest getValidCreateProcessRequest(HandlerRequest handlerRequest) { + + var header = handlerRequest.getHeader(); + + var multipartContext = header.getContext(); + var context = new Context(multipartContext.getIds(), multipartContext.getIdsc()); + + var multipartSecurityToken = header.getSecurityToken(); + var multipartTokenFormat = multipartSecurityToken.getTokenFormat(); + var securityToken = SecurityToken.Builder.newInstance(). + type(multipartSecurityToken.getType()). + id(multipartSecurityToken.getId()). + tokenFormat(new TokenFormat(multipartTokenFormat.getId())). + tokenValue(multipartSecurityToken.getTokenValue()). + build(); + + var requestHeader = Header.Builder.newInstance() + .context(context) + .id(header.getId()) + .type(header.getType()) + .securityToken(securityToken) + .issuerConnector(header.getIssuerConnector()) + .modelVersion(header.getModelVersion()) + .issued(header.getIssued()) + .senderAgent(header.getSenderAgent()) + .build(); + + return new CreateProcessRequest(requestHeader, handlerRequest.getPayload()); + } + public static ResponseBody getValidResponseBody(){ return ResponseBody.create( MediaType.get("application/json; charset=utf-8"), @@ -134,6 +181,13 @@ public static HandlerRequest getValidHandlerRequest(ObjectMapper mapper){ .payload(TEST_PAYLOAD).build(); } + public static HandlerRequest getValidHandlerCreateProcessRequest(ObjectMapper mapper){ + return HandlerRequest.Builder.newInstance() + .pid(UUID.randomUUID().toString()) + .header(getValidCreateProcessHeader(mapper)) + .payload(TEST_PAYLOAD).build(); + } + public static HandlerRequest getInvalidTokenHandlerRequest(ObjectMapper mapper){ return HandlerRequest.Builder.newInstance() .pid(UUID.randomUUID().toString()) diff --git a/clearing-house-edc/core/src/test/resources/headers/valid-create-process-header.json b/clearing-house-edc/core/src/test/resources/headers/valid-create-process-header.json new file mode 100644 index 00000000..a1cd612f --- /dev/null +++ b/clearing-house-edc/core/src/test/resources/headers/valid-create-process-header.json @@ -0,0 +1,21 @@ +{ + "@context":{ + "ids" : "https://w3id.org/idsa/core/", + "idsc" : "https://w3id.org/idsa/code/" + }, + "@type":"ids:RequestMessage", + "@id":"https://w3id.org/idsa/autogen/logMessage/9fdba4ad-f750-4bbc-a7f0-f648ac853508", + "ids:securityToken": { + "@type" : "ids:DynamicAttributeToken", + "@id" : "https://w3id.org/idsa/autogen/dynamicAttributeToken/7bbbd2c1-2d75-4e3d-bd10-c52d0381cab0", + "ids:tokenValue" : "eyJ0eXAiOiJKV1QiLCJraWQiOiJkZWZhdWx0IiwiYWxnIjoiUlMyNTYifQ.eyJzY29wZXMiOlsiaWRzYzpJRFNfQ09OTkVDVE9SX0FUVFJJQlVURVNfQUxMIl0sImF1ZCI6Imlkc2M6SURTX0NPTk5FQ1RPUlNfQUxMIiwiaXNzIjoiaHR0cHM6Ly9kYXBzLmFpc2VjLmZyYXVuaG9mZXIuZGUiLCJuYmYiOjE2MzQ2NTA3MzksImlhdCI6MTYzNDY1MDczOSwianRpIjoiTVRneE9EUXdPVFF6TXpZd05qWXlOVFExTUE9PSIsImV4cCI6MTYzNDY1NDMzOSwic2VjdXJpdHlQcm9maWxlIjoiaWRzYzpCQVNFX1NFQ1VSSVRZX1BST0ZJTEUiLCJyZWZlcnJpbmdDb25uZWN0b3IiOiJodHRwOi8vYnJva2VyLmlkcy5pc3N0LmZyYXVuaG9mZXIuZGUuZGVtbyIsIkB0eXBlIjoiaWRzOkRhdFBheWxvYWQiLCJAY29udGV4dCI6Imh0dHBzOi8vdzNpZC5vcmcvaWRzYS9jb250ZXh0cy9jb250ZXh0Lmpzb25sZCIsInRyYW5zcG9ydENlcnRzU2hhMjU2IjoiOTc0ZTYzMjRmMTJmMTA5MTZmNDZiZmRlYjE4YjhkZDZkYTc4Y2M2YTZhMDU2NjAzMWZhNWYxYTM5ZWM4ZTYwMCIsInN1YiI6IjkyOjE0OkU3OkFDOjEwOjIyOkYyOkNDOjA1OjZFOjJBOjJCOjhEOkRCOjEwOkQ2OjREOkEwOkExOjUzOmtleWlkOkNCOjhDOkM3OkI2Ojg1Ojc5OkE4OjIzOkE2OkNCOjE1OkFCOjE3OjUwOjJGOkU2OjY1OjQzOjVEOkU4In0.Qw3gWMgwnKQyVatbsozcin6qtQbLyXlk6QdaLajGaDmxSYqCKEcAje4kiDp5Fqj04WPmVyF0k8c1BJA3KGnaW3Qcikv4MNxqqoenvKIrSTokXsA7-osqBCfxLhV-s2lSXVTAtV_Q7f71eSoR5j-7nPPX8_nf4Xup4_VzfnwRmnuAbLfHfWThbupxFazC34r3waXCltOTFVa_XDlwEDMpPY7vEPeaqIt2t6ofVGo_HF86UB19liL-UZvp0uSE9z2fhloyxOrx9B_xavGS7pP6oRaumSJEN_x9dfdeDS98HQ_oBSSGBzaI4fM7ik35Yg42KQwmkZesD6P_YSEzVLcJDg", + "ids:tokenFormat" : { + "@id" : "idsc:JWT" + } + }, + "ids:senderAgent":"http://example.org", + "ids:modelVersion":"4.1.0", + "ids:issued" : "2021-06-23T17:27:23.566+02:00", + "ids:issuerConnector" : "https://companyA.com/connector/59a68243-dd96-4c8d-88a9-0f0e03e13b1b" +} + From ed94ba5d6888f30ec9157aee78623645d3b00ff1 Mon Sep 17 00:00:00 2001 From: Augusto Leal Date: Fri, 10 Nov 2023 12:57:37 -0300 Subject: [PATCH 6/8] feat (ch-edc): Excluding the coverage from dto classes --- clearing-house-edc/core/build.gradle.kts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clearing-house-edc/core/build.gradle.kts b/clearing-house-edc/core/build.gradle.kts index 8fe966c6..0982d796 100644 --- a/clearing-house-edc/core/build.gradle.kts +++ b/clearing-house-edc/core/build.gradle.kts @@ -54,4 +54,11 @@ tasks.jacocoTestReport { xml.required = true } dependsOn(tasks.test) + classDirectories.setFrom( + files(classDirectories.files.map { + fileTree(it) { + exclude("**/dto/**") + } + }) + ) } From a4b77c03220ca2706ac6b579e6299746014081c9 Mon Sep 17 00:00:00 2001 From: Augusto Leal Date: Fri, 10 Nov 2023 16:18:00 -0300 Subject: [PATCH 7/8] feat (ch-edc): Excluding the coverage from some types directory --- clearing-house-edc/core/build.gradle.kts | 5 ++++- .../de/truzzt/clearinghouse/edc/types/ids/SecurityToken.java | 2 +- .../clearinghouse/edc/types/{ids => }/util/VocabUtil.java | 2 +- .../clearinghouse/edc/types/ids/util/VocabUtilTest.java | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) rename clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/{ids => }/util/VocabUtil.java (95%) diff --git a/clearing-house-edc/core/build.gradle.kts b/clearing-house-edc/core/build.gradle.kts index 0982d796..957d08fd 100644 --- a/clearing-house-edc/core/build.gradle.kts +++ b/clearing-house-edc/core/build.gradle.kts @@ -57,7 +57,10 @@ tasks.jacocoTestReport { classDirectories.setFrom( files(classDirectories.files.map { fileTree(it) { - exclude("**/dto/**") + exclude( + "**/dto/**", + "**/types/clearinghouse/*", + "**/types/ids/*") } }) ) diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/SecurityToken.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/SecurityToken.java index b8f1b46f..c659df6e 100644 --- a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/SecurityToken.java +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/SecurityToken.java @@ -15,7 +15,7 @@ package de.truzzt.clearinghouse.edc.types.ids; import com.fasterxml.jackson.annotation.JsonProperty; -import de.truzzt.clearinghouse.edc.types.ids.util.VocabUtil; +import de.truzzt.clearinghouse.edc.types.util.VocabUtil; import org.jetbrains.annotations.NotNull; import java.net.URI; diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtil.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/util/VocabUtil.java similarity index 95% rename from clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtil.java rename to clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/util/VocabUtil.java index 15a76805..8d187601 100644 --- a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtil.java +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/util/VocabUtil.java @@ -12,7 +12,7 @@ * truzzt GmbH - EDC extension implementation * */ -package de.truzzt.clearinghouse.edc.types.ids.util; +package de.truzzt.clearinghouse.edc.types.util; import java.net.MalformedURLException; import java.net.URI; diff --git a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtilTest.java b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtilTest.java index 5d8da421..6e6063ae 100644 --- a/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtilTest.java +++ b/clearing-house-edc/core/src/test/java/de/truzzt/clearinghouse/edc/types/ids/util/VocabUtilTest.java @@ -1,5 +1,6 @@ package de.truzzt.clearinghouse.edc.types.ids.util; +import de.truzzt.clearinghouse.edc.types.util.VocabUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; From dc18f0f977e3b6abb505afc1e6b28256aaf2a7fd Mon Sep 17 00:00:00 2001 From: Glaucio Jannotti Date: Tue, 21 Nov 2023 16:34:44 -0300 Subject: [PATCH 8/8] fix (ch-edc): dsp token format --- .../de/truzzt/clearinghouse/edc/types/ids/TokenFormat.java | 7 ++++++- .../clearinghouse/edc/multipart/MultipartController.java | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/TokenFormat.java b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/TokenFormat.java index 56d86cd5..1bb06024 100644 --- a/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/TokenFormat.java +++ b/clearing-house-edc/core/src/main/java/de/truzzt/clearinghouse/edc/types/ids/TokenFormat.java @@ -21,7 +21,8 @@ public class TokenFormat { - public static final String JWT_TOKEN_FORMAT = "idsc:JWT"; + public static final String JWT_TOKEN_FORMAT_IDS = "idsc:JWT"; + public static final String JWT_TOKEN_FORMAT_DSP = "https://w3id.org/idsa/code/JWT"; @JsonProperty("@id") @NotNull @@ -30,4 +31,8 @@ public class TokenFormat { public URI getId() { return id; } + + public static boolean isValid(String id) { + return id.equals(JWT_TOKEN_FORMAT_IDS) || id.equals(JWT_TOKEN_FORMAT_DSP); + } } diff --git a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java index a566cd7d..d1532c27 100644 --- a/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java +++ b/clearing-house-edc/extensions/multipart/src/main/java/de/truzzt/clearinghouse/edc/multipart/MultipartController.java @@ -168,7 +168,7 @@ RequestValidationResponse validaRequest(String pid, InputStream headerInputStrea // Check the security token type var tokenFormat = securityToken.getTokenFormat().getId().toString(); - if (!tokenFormat.equals(TokenFormat.JWT_TOKEN_FORMAT)) { + if (!TokenFormat.isValid(tokenFormat)) { monitor.severe(LOG_ID + ": Invalid security token type: " + tokenFormat); return new RequestValidationResponse(Response.status(Response.Status.BAD_REQUEST) .entity(createFormDataMultiPart(typeManagerUtil, HEADER, malformedMessage(null, connectorId)))