diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java b/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java index eeffbfb7dce1506b1c6af3e8229df2183f644955..e5dd7541f2a8787a098e40222765c5fe48d8c62b 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java @@ -15,7 +15,6 @@ public enum SchemaConfig { SET_V_1_0_1(SCHEMA_BASE_URL.schemaUri.resolve("set-payload/1.0.1/set-payload.schema.json"), "set_schema_1.0.1.json"), SET_V_1_0_0(SCHEMA_BASE_URL.schemaUri.resolve("set-payload/1.0.0/set-payload.schema.json"), "set_schema_1.0.0.json"), METADATA_V_1_0_0(SCHEMA_BASE_URL.schemaUri.resolve("metadata/1.0.0/metadata.schema.json"), "metadata_schema_1.0.0.json"), - XZUFI_DESTINATION_SCHEMA(SCHEMA_BASE_URL.schemaUri.resolve("xzufi/destination.schema.json"), "destination_schema.json"); private final URI schemaUri; @@ -50,6 +49,12 @@ public enum SchemaConfig { .collect(Collectors.toList()); } + public static List<String> getSubmissionDataSchemaPaths(final String submissionDataSchemaBaseDir) { + return Stream.empty() + .map(fileName -> submissionDataSchemaBaseDir + "/" + fileName) + .collect(Collectors.toList()); + } + @Override public String toString() { return schemaUri.toString(); diff --git a/api/src/main/java/dev/fitko/fitconnect/api/domain/schema/SchemaResources.java b/api/src/main/java/dev/fitko/fitconnect/api/domain/schema/SchemaResources.java index 022b164a45561ce5305734532cc14a518787625f..f64692e175cced47719ca2fca139d4bd8edbc106 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/domain/schema/SchemaResources.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/domain/schema/SchemaResources.java @@ -10,4 +10,5 @@ public class SchemaResources { List<String> setSchemaPaths; List<String> metadataSchemaPaths; List<String> destinationSchemaPaths; + List<String> submissionDataSchemaPaths; } diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java b/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java index ecee117fa17047f292f00b3e1fb7920b3eda226d..a0201739d0aea68d919757e293beec7f13a9725c 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java @@ -12,6 +12,7 @@ import dev.fitko.fitconnect.api.domain.model.submission.*; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.exceptions.*; +import java.net.URI; import java.util.List; import java.util.UUID; @@ -140,10 +141,11 @@ public interface Sender { * Tests if a given string is well-formed JSON syntax. * * @param json json string that is tested + * @param schemaUri URI of schema to validate against * * @return a {@link ValidationResult} with an optional error */ - ValidationResult validateJsonFormat(SubmissionPayload json); + ValidationResult validateJsonFormat(String json, URI schemaUri); /** * Tests if a given string is well-formed XML syntax. diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/validation/ValidationService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/validation/ValidationService.java index c5d747b3f9e54e225c6f9ef0d55aad86628c4f4d..99057bf38655458ec9ec8d8206ed768545854f38 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/validation/ValidationService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/validation/ValidationService.java @@ -4,6 +4,7 @@ import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; +import java.net.URI; import java.util.Map; /** @@ -77,10 +78,11 @@ public interface ValidationService { * Tests if a given string is well-formed JSON syntax. * * @param json json string that is tested + * @param schemaUri URI of schema to validate against * * @return a {@link ValidationResult} with an optional error */ - ValidationResult validateJsonFormat(String json); + ValidationResult validateJsonFormat(String json, URI schemaUri); /** * Tests if a given string is well-formed XML syntax. diff --git a/client/src/main/java/dev/fitko/fitconnect/client/SenderClient.java b/client/src/main/java/dev/fitko/fitconnect/client/SenderClient.java index 4970c09efeaadfca5460fc50842b53ec26feed76..523193e4379bd075df2c4a7e5dd5a517df80fe79 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/SenderClient.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/SenderClient.java @@ -11,7 +11,7 @@ import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.model.EncryptedSubmissionPayload; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import dev.fitko.fitconnect.client.sender.strategies.SendEncryptedSubmissionStrategy; import dev.fitko.fitconnect.client.sender.strategies.SendNewSubmissionStrategy; import dev.fitko.fitconnect.client.util.ValidDataGuard; diff --git a/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandExecutor.java b/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandExecutor.java index c3f6b15ce439c9f7ef7960bc035cb002be5f8ca7..7410ce89e10fa6bf8d10e83ffdd5bf56e590eea4 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandExecutor.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandExecutor.java @@ -10,7 +10,7 @@ import dev.fitko.fitconnect.client.cli.batch.ImportRecord; import dev.fitko.fitconnect.client.cli.commands.*; import dev.fitko.fitconnect.client.cli.util.AttachmentDataType; import dev.fitko.fitconnect.client.sender.SubmissionBuilder; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import dev.fitko.fitconnect.client.subscriber.ReceivedSubmission; import dev.fitko.fitconnect.client.subscriber.model.ReceivedAttachment; import dev.fitko.fitconnect.core.util.StopWatch; diff --git a/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java b/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java index cfdd4ee6d739976c8ef678ef0ca8c09470575669..24eff7a4a2621a0b10291a9b9793c445cbf52a34 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java @@ -59,9 +59,9 @@ public final class ClientFactory { private static final String CONFIG_ENV_KEY_NAME = "FIT_CONNECT_CONFIG"; private static final String SET_SCHEMA_DIR = "/set-schema"; - private static final String DESTINATION_SCHEMA_DIR = "/destination-schema"; private static final String METADATA_SCHEMA_DIR = "/metadata-schema"; + private static final String SUBMISSION_DATA_SCHEMA_DIR = "/submission-data-schema"; private ClientFactory() { } @@ -129,7 +129,7 @@ public final class ClientFactory { public static RoutingClient routingClient(final ApplicationConfig config) { LOGGER.info("Initializing routing client ..."); final RestTemplate restTemplate = getRestTemplate(config, ApplicationConfigLoader.loadBuildInfo()); - final SchemaProvider schemaProvider = getSchemaProvider(); + final SchemaProvider schemaProvider = getSchemaProvider(restTemplate); final OAuthService authService = getSenderConfiguredAuthService(config, restTemplate); final MessageDigestService messageDigestService = getMessageDigestService(); @@ -145,7 +145,7 @@ public final class ClientFactory { private static Sender getSender(final ApplicationConfig config, final BuildInfo buildInfo) { final RestTemplate restTemplate = getRestTemplate(config, buildInfo); - final SchemaProvider schemaProvider = getSchemaProvider(); + final SchemaProvider schemaProvider = getSchemaProvider(restTemplate); final MessageDigestService messageDigestService = getMessageDigestService(); final CryptoService cryptoService = getCryptoService(messageDigestService); @@ -162,7 +162,7 @@ public final class ClientFactory { private static Subscriber getSubscriber(final ApplicationConfig config, final BuildInfo buildInfo) { final RestTemplate restTemplate = getRestTemplate(config, buildInfo); - final SchemaProvider schemaProvider = getSchemaProvider(); + final SchemaProvider schemaProvider = getSchemaProvider(restTemplate); final MessageDigestService messageDigestService = getMessageDigestService(); final CryptoService cryptoService = getCryptoService(messageDigestService); @@ -231,12 +231,13 @@ public final class ClientFactory { return new EventLogVerifier(keyService, validationService); } - private static SchemaProvider getSchemaProvider() { + private static SchemaProvider getSchemaProvider(RestTemplate restTemplate) { final List<String> setSchemaFiles = SchemaConfig.getSetSchemaFilePaths(SET_SCHEMA_DIR); final List<String> metadataSchemaFiles = SchemaConfig.getMetadataSchemaFileNames(METADATA_SCHEMA_DIR); final List<String> destinationSchemaFiles = SchemaConfig.getDestinationSchemaPaths(DESTINATION_SCHEMA_DIR); - final SchemaResources schemaResources = new SchemaResources(setSchemaFiles, metadataSchemaFiles, destinationSchemaFiles); - return new SchemaResourceProvider(schemaResources); + final List<String> submissionDataSchemaFiles = SchemaConfig.getSubmissionDataSchemaPaths(SUBMISSION_DATA_SCHEMA_DIR); + final SchemaResources schemaResources = new SchemaResources(setSchemaFiles, metadataSchemaFiles, destinationSchemaFiles, submissionDataSchemaFiles); + return new SchemaResourceProvider(restTemplate, schemaResources); } private static RoutingService getRoutingService(final ApplicationConfig config, final RestTemplate restTemplate) { diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/SubmissionBuilder.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/SubmissionBuilder.java index 4298f643133ce5c5c7be0c50fa2c432e4b2710e3..89a55fd239a0adeacc5dfba66fa45a9ee5b4fa20 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/SubmissionBuilder.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/SubmissionBuilder.java @@ -2,7 +2,7 @@ package dev.fitko.fitconnect.client.sender; import dev.fitko.fitconnect.api.domain.model.metadata.data.MimeType; import dev.fitko.fitconnect.api.domain.model.submission.ServiceType; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import dev.fitko.fitconnect.client.sender.steps.*; import lombok.Getter; import org.slf4j.Logger; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/domain/model/submission/SubmissionPayload.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/model/SubmissionPayload.java similarity index 94% rename from api/src/main/java/dev/fitko/fitconnect/api/domain/model/submission/SubmissionPayload.java rename to client/src/main/java/dev/fitko/fitconnect/client/sender/model/SubmissionPayload.java index f276501e0bf62ef7701597c29323d932915f53da..fc7956049bd99f805db90ea84834cf161cf16337 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/domain/model/submission/SubmissionPayload.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/model/SubmissionPayload.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.domain.model.submission; +package dev.fitko.fitconnect.client.sender.model; import dev.fitko.fitconnect.api.domain.model.metadata.data.MimeType; import dev.fitko.fitconnect.api.domain.model.submission.ServiceType; diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/BuildStep.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/BuildStep.java index a5e1defc933ba7038bdb38f17c4b84c094ce9d7d..2ecd116d6e5616c808a692fbddb98fd894ea178b 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/BuildStep.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/BuildStep.java @@ -1,6 +1,6 @@ package dev.fitko.fitconnect.client.sender.steps; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; public interface BuildStep { diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java index fbe3e33e1628ff8d888c0da90a72749e3f0bcc6f..664109153eb409b19e28c53657b6bb46f6cad3e0 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java @@ -2,6 +2,7 @@ package dev.fitko.fitconnect.client.sender.strategies; import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.domain.model.destination.Destination; +import dev.fitko.fitconnect.api.domain.model.destination.DestinationService; import dev.fitko.fitconnect.api.domain.model.metadata.ContentStructure; import dev.fitko.fitconnect.api.domain.model.metadata.Hash; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; @@ -27,7 +28,7 @@ import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; import dev.fitko.fitconnect.api.exceptions.SubmissionNotCreatedException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.model.AttachmentPayload; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import dev.fitko.fitconnect.core.util.StopWatch; import org.apache.tika.Tika; import org.slf4j.Logger; @@ -40,6 +41,7 @@ import java.net.URLConnection; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.UUID; diff --git a/client/src/main/java/dev/fitko/fitconnect/client/util/ValidDataGuard.java b/client/src/main/java/dev/fitko/fitconnect/client/util/ValidDataGuard.java index 0e15340daa25242c9d25b35e215f21aa0f8a2d79..12491f857bbff1a0fb2b8da53145f57925d44cc1 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/util/ValidDataGuard.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/util/ValidDataGuard.java @@ -7,7 +7,7 @@ import dev.fitko.fitconnect.api.domain.model.submission.ServiceType; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.model.EncryptedSubmissionPayload; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import java.net.URI; import java.util.Objects; @@ -136,7 +136,7 @@ public class ValidDataGuard { } private void checkJsonFormat(final SubmissionPayload submissionPayload) { - final ValidationResult validationResult = sender.validateJsonFormat(submissionPayload.getData()); + final ValidationResult validationResult = sender.validateJsonFormat(submissionPayload.getData(), submissionPayload.getSchemaUri()); if (validationResult.hasError()) { throw new IllegalArgumentException("Data is not in expected json format, please provide valid json: " + validationResult.getError().getMessage()); } diff --git a/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java index 3ae0ca490f445fb370a766d18700b1be36be78e6..a7ef9d0a2ec8cc3b58bf5b5fd5cf81f62ceb9a52 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java @@ -23,7 +23,7 @@ import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.EncryptedSubmissionBuilder; import dev.fitko.fitconnect.client.sender.SubmissionBuilder; import dev.fitko.fitconnect.client.sender.model.EncryptedSubmissionPayload; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import dev.fitko.fitconnect.client.testutil.LogCaptor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -77,7 +77,7 @@ public class SenderClientTest { when(senderMock.sendSubmission(any())).thenReturn(expectedSubmission); when(senderMock.validatePublicKey(any())).thenReturn(ValidationResult.ok()); when(senderMock.getEncryptionKeyForDestination(any())).thenReturn(publicKey); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); when(senderMock.validateMetadata(any())).thenReturn(ValidationResult.ok()); @@ -182,7 +182,7 @@ public class SenderClientTest { when(senderMock.getDestination(any())).thenReturn(destination); when(senderMock.createSubmission(any())).thenReturn(announcedSubmission); when(senderMock.validatePublicKey(any())).thenReturn(ValidationResult.ok()); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); when(senderMock.getEncryptionKeyForDestination(any())).thenReturn(publicKey); // When @@ -513,7 +513,7 @@ public class SenderClientTest { when(senderMock.getEncryptionKeyForDestination(any())).thenReturn(publicKey); when(senderMock.validateMetadata(any())).thenReturn(ValidationResult.ok()); when(senderMock.validateXmlFormat(any())).thenReturn(ValidationResult.ok()); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); when(senderMock.sendSubmission(any())).thenReturn(new Submission()); return destinationId; diff --git a/client/src/test/java/dev/fitko/fitconnect/client/cli/CommandLineClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/cli/CommandLineClientTest.java index ae4a9f465b0ad7f942f6b3bb2d7f825ae00456f1..61e54c21aca6754a05348568d776afe5dc1b1802 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/cli/CommandLineClientTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/cli/CommandLineClientTest.java @@ -11,7 +11,7 @@ import dev.fitko.fitconnect.client.SubscriberClient; import dev.fitko.fitconnect.client.cli.batch.CsvImporter; import dev.fitko.fitconnect.client.cli.batch.ImportRecord; import dev.fitko.fitconnect.client.sender.model.EncryptedSubmissionPayload; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import dev.fitko.fitconnect.client.subscriber.ReceivedSubmission; import dev.fitko.fitconnect.client.subscriber.model.ReceivedAttachment; import dev.fitko.fitconnect.client.subscriber.model.ReceivedData; diff --git a/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java b/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java index a3e1453fe975257bd64cef25767de302dc07f170..ef356cb038f5576a41b9be92f44563ac84abf238 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/util/ValidDataGuardTest.java @@ -9,7 +9,7 @@ import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.EncryptedSubmissionBuilder; import dev.fitko.fitconnect.client.sender.SubmissionBuilder; import dev.fitko.fitconnect.client.sender.model.EncryptedSubmissionPayload; -import dev.fitko.fitconnect.api.domain.model.submission.SubmissionPayload; +import dev.fitko.fitconnect.client.sender.model.SubmissionPayload; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -56,7 +56,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -107,7 +107,7 @@ class ValidDataGuardTest { void testMissingDestinationId() { // Given - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{}", URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")) @@ -126,7 +126,7 @@ class ValidDataGuardTest { void testInvalidServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{\"test\" . \"data\"}", @@ -145,7 +145,7 @@ class ValidDataGuardTest { void testMissingServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("{\"test\" . \"data\"}", @@ -171,7 +171,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -202,7 +202,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -234,7 +234,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final SubmissionPayload submissionPayload = SubmissionBuilder.Builder() .withJsonData("\"test\": \"json\"", @@ -268,7 +268,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -321,7 +321,7 @@ class ValidDataGuardTest { void testMissingDestinationId() { // Given - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -341,7 +341,7 @@ class ValidDataGuardTest { void testInvalidServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -361,7 +361,7 @@ class ValidDataGuardTest { void testMissingServiceIdentifier() { // Given - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") @@ -387,7 +387,7 @@ class ValidDataGuardTest { destination.setServices(Set.of(service)); when(senderMock.getDestination(any())).thenReturn(destination); - when(senderMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(senderMock.validateJsonFormat(any(), URI.create("urn:something"))).thenReturn(ValidationResult.ok()); final EncryptedSubmissionPayload encryptedSubmissionPayload = EncryptedSubmissionBuilder.Builder() .withEncryptedData("4Y0sJhadfrQnNZXeS7Pqh73FvtF") diff --git a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java index eb5cc289f429871403de518cefccfca60b5cd1b2..d58b74baf4733d024a5014b348d05cb44351b7a8 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java @@ -6,7 +6,10 @@ import dev.fitko.fitconnect.api.domain.model.event.EventLogEntry; import dev.fitko.fitconnect.api.domain.model.event.EventStatus; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; -import dev.fitko.fitconnect.api.domain.model.submission.*; +import dev.fitko.fitconnect.api.domain.model.submission.CreateSubmission; +import dev.fitko.fitconnect.api.domain.model.submission.Submission; +import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; +import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.api.services.crypto.CryptoService; @@ -17,6 +20,7 @@ import dev.fitko.fitconnect.api.services.validation.ValidationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.URI; import java.util.List; import java.util.UUID; @@ -112,9 +116,9 @@ public class SubmissionSender implements Sender { } @Override - public ValidationResult validateJsonFormat(final SubmissionPayload json) { + public ValidationResult validateJsonFormat(final String json, final URI schemaUri) { LOGGER.info("Validating data json format"); - return validationService.validateJsonFormat(json); + return validationService.validateJsonFormat(json, schemaUri); } @Override diff --git a/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java b/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java index cb5cfef450e902b2db6af39322660c5d56e21acd..cb81e6849f036aaf147d460cac118a155c35b394 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java @@ -9,6 +9,7 @@ import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.web.client.RestTemplate; import java.io.BufferedReader; import java.io.InputStream; @@ -32,15 +33,22 @@ public class SchemaResourceProvider implements SchemaProvider { private final Map<URI, String> destinationSchemas; + private final Map<URI, String> submissionDataSchemas; + + private final RestTemplate restTemplate; + private static final ObjectMapper MAPPER = new ObjectMapper(); - public SchemaResourceProvider(final SchemaResources schemaResources) { + public SchemaResourceProvider(final RestTemplate restTemplate, final SchemaResources schemaResources) { setSchemas = new HashMap<>(); metadataSchemas = new HashMap<>(); destinationSchemas = new HashMap<>(); + submissionDataSchemas = new HashMap<>(); + this.restTemplate = restTemplate; populateSetSchemas(schemaResources.getSetSchemaPaths()); populateMetadataSchemas(schemaResources.getMetadataSchemaPaths()); populateDestinationSchemas(schemaResources.getDestinationSchemaPaths()); + populateSubmissionDataSchemas(schemaResources.getSubmissionDataSchemaPaths()); } private void populateMetadataSchemas(final List<String> metadataSchemaPaths) { @@ -58,6 +66,11 @@ public class SchemaResourceProvider implements SchemaProvider { getResourceFiles(destinationSchemaPaths).forEach(this::addDestinationSchema); } + private void populateSubmissionDataSchemas(final List<String> submissionDataSchemaPaths) { + LOGGER.info("Initializing submission data schemas"); + getResourceFiles(submissionDataSchemaPaths).forEach(this::addSubmissionDataSchema); + } + @Override public boolean isAllowedSetSchema(final URI schemaUri) { return schemaVersionMatchesPattern(schemaUri, ALLOWED_SCHEMA_PATTERN); @@ -99,14 +112,19 @@ public class SchemaResourceProvider implements SchemaProvider { @Override public String loadSubmissionDataSchema(final URI schemaUri) throws SchemaNotFoundException { - String schema; - if(schemaUri.toString().matches("http.+")) { - schema = "load schema from remote"; + if (schemaUri.toString().matches("http.+")) { + try { + return restTemplate.getForEntity(schemaUri, String.class).getBody(); + } catch (Exception exception) { + throw new SchemaNotFoundException("Submission data schema " + schemaUri + " is not available.", exception); + } } - schema = destinationSchemas.get(schemaUri); + + final String schema = submissionDataSchemas.get(schemaUri); if (schema == null) { - throw new SchemaNotFoundException("Destination schema " + schemaUri.toString() + " is not available."); + throw new SchemaNotFoundException("Submission data schema " + schemaUri + " is not available."); } + return schema; } @@ -122,6 +140,10 @@ public class SchemaResourceProvider implements SchemaProvider { destinationSchemas.put(readIdFromSchema(schema), schema); } + private void addSubmissionDataSchema(final String schema) { + submissionDataSchemas.put(readIdFromSchema(schema), schema); + } + private URI readIdFromSchema(final String schema) { try { return URI.create(MAPPER.readTree(schema).get("$id").asText()); diff --git a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java index 37455f13cf52a0e8c6b8e053712ae8ce11da4454..31a70c2137720dce5bcd40a1875ecd2005e7ced7 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java @@ -33,7 +33,6 @@ import org.xml.sax.XMLReader; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -152,9 +151,11 @@ public class DefaultValidationService implements ValidationService { } @Override - public ValidationResult validateJsonFormat(final String json) { + public ValidationResult validateJsonFormat(final String json, final URI schemaUri) { + + String schema = schemaProvider.loadSubmissionDataSchema(schemaUri); try { - MAPPER.readTree(json); + returnValidationResult(SCHEMA_FACTORY_DRAFT_2007.getSchema(schema).validate(MAPPER.readTree(json))); } catch (final JacksonException e) { return ValidationResult.error(e); } diff --git a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java index 46a8f81341450573d2aa69c7c65c0ec54c063f20..7887831208484aa9945cb6b79e7f8e1d19e1028c 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java @@ -37,6 +37,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.net.URI; import java.text.ParseException; import java.util.Collections; import java.util.Date; @@ -54,6 +55,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -331,10 +333,10 @@ public class SubmissionSenderTest { void testValidJsonFormatValidation() { // Given - when(validationServiceMock.validateJsonFormat(any())).thenReturn(ValidationResult.ok()); + when(validationServiceMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.ok()); // When - final ValidationResult validationResult = underTest.validateJsonFormat("{}"); + final ValidationResult validationResult = underTest.validateJsonFormat("{}", URI.create("urn:something")); //Then assertTrue(validationResult.isValid()); @@ -344,10 +346,10 @@ public class SubmissionSenderTest { void testInvalidJsonFormatValidation() { // Given - when(validationServiceMock.validateJsonFormat(any())).thenReturn(ValidationResult.error(new ValidationException("Invalid json"))); + when(validationServiceMock.validateJsonFormat(any(), eq(URI.create("urn:something")))).thenReturn(ValidationResult.error(new ValidationException("Invalid json"))); // When - final ValidationResult validationResult = underTest.validateJsonFormat("$%&/()"); + final ValidationResult validationResult = underTest.validateJsonFormat("$%&/()", URI.create("urn:something")); //Then assertTrue(validationResult.hasError()); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java index a790df4634bbef654f6e6d7eefda5a7661df9da7..c894ac53ad9d76576289815db42492223f081f7b 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java @@ -27,6 +27,7 @@ import dev.fitko.fitconnect.core.schema.SchemaResourceProvider; import dev.fitko.fitconnect.core.validation.DefaultValidationService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.web.client.RestTemplate; import java.io.File; import java.io.IOException; @@ -41,6 +42,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; class SecurityEventTokenServiceTest { @@ -61,8 +63,9 @@ class SecurityEventTokenServiceTest { final List<String> setSchemas = SchemaConfig.getSetSchemaFilePaths("/set-schema"); final List<String> metadataSchemas = SchemaConfig.getMetadataSchemaFileNames("/metadata-schema"); final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); - final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas); - final SchemaProvider schemaProvider = new SchemaResourceProvider(schemaResources); + final List<String> submissionDataSchemas = SchemaConfig.getSubmissionDataSchemaPaths("/submission-data-schema"); + final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemas); + final SchemaProvider schemaProvider = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); validationService = new DefaultValidationService(config, new HashService(), schemaProvider); underTest = new SecurityEventTokenService(config, validationService, signingKey); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java b/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java index 0b1899e945d8a6eda17770d21ff9a9ba381ae8e5..764644acc6ba655c6a259d84647a9eab21e1411a 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java @@ -8,6 +8,7 @@ import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.web.client.RestTemplate; import java.net.URI; import java.util.List; @@ -15,6 +16,7 @@ import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; class SchemaResourceProviderTest { @@ -25,8 +27,9 @@ class SchemaResourceProviderTest { final List<String> setSchemas = SchemaConfig.getSetSchemaFilePaths("/set-schema"); final List<String> metadataSchemas = SchemaConfig.getMetadataSchemaFileNames("/metadata-schema"); final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); - final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas); - underTest = new SchemaResourceProvider(schemaResources); + final List<String> submissionDataSchemas = SchemaConfig.getSubmissionDataSchemaPaths("/submission-data-schema"); + final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemas); + underTest = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); } @Test diff --git a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java index ba7f6ec3e1f553294408cf421a9218f2ad9f2462..ede11c83a93f887693e1075dba52b62c03f1737a 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java @@ -32,6 +32,7 @@ import dev.fitko.fitconnect.jwkvalidator.exceptions.JWKValidationException; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.web.client.RestTemplate; import java.io.IOException; import java.net.URI; @@ -59,8 +60,9 @@ class DefaultValidationServiceTest { final List<String> setSchemas = SchemaConfig.getSetSchemaFilePaths("/set-schema"); final List<String> metadataSchemas = SchemaConfig.getMetadataSchemaFileNames("/metadata-schema"); final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); - final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas); - schemaProvider = new SchemaResourceProvider(schemaResources); + final List<String> submissionDataSchemas = SchemaConfig.getSubmissionDataSchemaPaths("/submission-data-schema"); + final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemas); + schemaProvider = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); underTest = new DefaultValidationService(config, hashService, schemaProvider); } @@ -412,7 +414,7 @@ class DefaultValidationServiceTest { final var validJson = getResource("/valid_json_data.json"); // When - final ValidationResult validationResult = underTest.validateJsonFormat(validJson); + final ValidationResult validationResult = underTest.validateJsonFormat(validJson, URI.create("urn:something")); // Then assertTrue(validationResult.isValid()); @@ -425,7 +427,7 @@ class DefaultValidationServiceTest { final var invalidJson = getResource("/invalid_json_data.json"); // When - final ValidationResult validationResult = underTest.validateJsonFormat(invalidJson); + final ValidationResult validationResult = underTest.validateJsonFormat(invalidJson, URI.create("urn:something")); // Then assertFalse(validationResult.isValid());