diff --git a/README.md b/README.md index 7e248357f259684e0f1c3a8911d313582c5d6434..ab90980c2c64c5fe4280d6f5fc1fe09961758aa3 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ See the projects' module documentation for more specific information: * [API Module ](api/README.md) * [Core Module ](core/README.md) * [Client Module ](client/README.md) +* [Integration-Test Module ](integration-tests/README.md) ## Setup @@ -110,20 +111,20 @@ _The following steps show how to get the SDK running_ ````java final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromPath(Path.of("path/to/config.yml")); ```` -7. Afterwards the config is used to initialize clients with the `ClientFactory` that offer clients for sender, subscriber and routing: +7. Afterwards the config is used to initialize clients with the `ClientFactory` that offer clients for sender, subscriber and routing: ````java final SenderClient senderClient = ClientFactory.getSenderClient(config); // final SubscriberClient subscriberClient = ClientFactory.getSubscriberClient(config); // - final RoutingClient routingClient = ClientFactory.getRoutingClient(config); + final RouterClient routerClient = ClientFactory.getRouterClient(config); ```` <p align="right">(<a href="#top">back to top</a>)</p> ## API Usage for Routing -The Routing-Client allows to retrieve data about areas and services as well as their service destination. -A typical workflow using the `RoutingClient` and `SenderClient` would be: +The Router-Client allows to retrieve data about areas and services as well as their service destination. +A typical workflow using the `RouterClient` and `SenderClient` would be: 1) Find the `areaId` for an area via routing 2) Find the destination for a `leikaKey` and an `areaId` via routing @@ -133,13 +134,13 @@ A typical workflow using the `RoutingClient` and `SenderClient` would be: Areas can be searched with one or more search criteria: ```java -final RoutingClient routingClient = ClientFactory.getRoutingClient(config); +final RouterClient routerClient = ClientFactory.getRouterClient(config); final var citySearchCriterion = "Leip*"; final var zipCodeSearchCriterion = "04229"; // get first 5 area results -final List<Area> areas = routingClient.findAreas(List.of(citySearchCriterion, zipCodeSearchCriterion), 0, 5); +final List<Area> areas = routerClient.findAreas(List.of(citySearchCriterion, zipCodeSearchCriterion), 0, 5); LOGGER.info("Found {} areas", areas.size()); for (final Area area : areas){ @@ -163,7 +164,7 @@ __Note:__ Both, the `leikaKey` service-identifier and the region keys `ars/ags`c #### Find destination by service identifier and *areaId* ```java -final RoutingClient routingClient = ClientFactory.getRoutingClient(config); +final RouterClient routerClient = ClientFactory.getRouterClient(config); final DestinationSearch search = DestinationSearch.Builder() .withLeikaKey("99123456760610") @@ -172,7 +173,7 @@ final DestinationSearch search = DestinationSearch.Builder() .build(); // get first 3 route results -final List<Route> routes = routingClient.findDestinations(search); +final List<Route> routes = routerClient.findDestinations(search); LOGGER.info("Found {} routes for service identifier {}", routes.size(), leikaKey); for (final Route route : routes){ @@ -185,7 +186,7 @@ for (final Route route : routes){ Besides the areaId another search criterion for the area/region can be used as well: ```java -final RoutingClient routingClient = ClientFactory.getRoutingClient(config); +final RouterClient routerClient = ClientFactory.getRouterClient(config); final DestinationSearch search = DestinationSearch.Builder() .withLeikaKey("99123456760610") @@ -194,7 +195,7 @@ final DestinationSearch search = DestinationSearch.Builder() .build(); // get first 3 route results -final List<Route> routes = routingClient.findDestinations(search); +final List<Route> routes = routerClient.findDestinations(search); LOGGER.info("Found {} routes for service identifier {}", routes.size(), leikaKey); for (final Route route : routes){ @@ -202,7 +203,6 @@ for (final Route route : routes){ } ``` - ## API Usage for Sender For sending submission and already encrypted submissions builder are provided to construct the necessary payload to be sent. @@ -218,8 +218,12 @@ If all data, metadata and attachments are encrypted outside the SDK the sender c #### 1. Retrieve public encryption key: ```java +final SenderClient senderClient = ClientFactory.getSenderClient(config); + +// destination id that was retrieved via the router client final var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"); -final String publicJwkAsJsonString = ClientFactory.getSenderClient(config).getPublicKey(destinationId); + +final String publicJwkAsJsonString = senderClient.getPublicKeyForDestination(destinationId); ``` #### 2. Send encrypted data @@ -469,9 +473,25 @@ if(validationResult.hasError()){ } ``` +## Error Handling +### Exceptions +All clients accessible via the ``ClientFactory`` throw a custom `RuntimeException` if a technical error occurred: +- SenderClient => throws ``FitConnectSenderException`` +- SubscriberClient => throws ``FitConnectSubscriberException`` +- RouterClient => throws ``FitConnectRouterException`` + +For all other issues regarding the configuration and set-up of the SDK a ``FitConnectInitialisationException`` will be thrown. + +### Auto-Reject +The SDK performs validations on all kind of requests e.g. checks for data integrity and JWT-validity. +If one of the validations fails on subscriber side, whilst retrieving, the submission it will be auto-rejected. +This means a ``REJECT`` event is sent to the event-log with a subsequent deletion of that invalid submission. + +Please see the [documentation on verification](https://docs.fitko.de/fit-connect/docs/receiving/verification) for all tests and checks that are executed. + ## Integration Tests -Integration tests do not run per default with `mvn test`, but they can be executed with the maven profile `IntegrationTests` via `mvn -PIntegrationTests test`. +Integration tests do not run per default with `mvn test`, but they can be executed with the maven via `mvn verify`. They expect the following environment variables to be set in the rn configuration of the IDE or on the local terminal: * SENDER_CLIENT_ID @@ -491,7 +511,6 @@ var submissionBaseUrl = "https://submission-api-testing.fit-connect.fitko.dev"; ``` ## Roadmap -- [ ] Add auto-reject on technical errors - [ ] Maven central release of 1.0.0-beta See the [open issues](https://git.fitko.de/fit-connect/planning/-/boards/44?search=SDK) for a full list of proposed features (and known issues). diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/ApplicationConfig.java b/api/src/main/java/dev/fitko/fitconnect/api/config/ApplicationConfig.java index 2226141c85623f070e562b7b7fae1bf4e13cdfb3..cb5b8ff966dae0db75e519abc741f2060a89c474 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/ApplicationConfig.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/ApplicationConfig.java @@ -1,18 +1,23 @@ package dev.fitko.fitconnect.api.config; -import dev.fitko.fitconnect.api.exceptions.InitializationException; +import dev.fitko.fitconnect.api.config.defaults.ResourcePaths; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.With; +import lombok.experimental.Accessors; import java.net.URI; -import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -@Data +@Getter @Builder +@Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor public class ApplicationConfig { @@ -29,9 +34,6 @@ public class ApplicationConfig { @Builder.Default private Integer requestTimeoutInSeconds = 30; - @Builder.Default - private boolean enableAutoReject = true; - @Builder.Default private URI setSchemaWriteVersion = SchemaConfig.SET_V_1_0_1.getSchemaUri(); @@ -41,31 +43,40 @@ public class ApplicationConfig { @Builder.Default private URI destinationSchemaVersion = SchemaConfig.XZUFI_DESTINATION_SCHEMA.getSchemaUri(); + private String submissionDataSchemaPath; + private SenderConfig senderConfig; private SubscriberConfig subscriberConfig; + @With @Builder.Default - private Map<EnvironmentName, Environment> environments = Collections.emptyMap(); + private Map<EnvironmentName, Environment> environments = new HashMap<>(); private EnvironmentName activeEnvironment; - private String submissionDataSchemaPath; + public boolean isAutoRejectEnabled() { + return getCurrentEnvironment().getEnableAutoReject(); + } - private Environment getEnvironmentByName(final EnvironmentName environmentName) { - if (environments.containsKey(environmentName)) { - return environments.get(environmentName); - } else { - throw new InitializationException("No environment with name '" + environmentName.getName() + "' found. Available environments are: " + getAvailableEnvironmentNames()); - } + public boolean isSkipSubmissionDataValidation() { + return getCurrentEnvironment().getSkipSubmissionDataValidation(); + } + + public boolean isAllowInsecurePublicKey() { + return getCurrentEnvironment().getAllowInsecurePublicKey(); } public Environment getCurrentEnvironment() { - return getEnvironmentByName(activeEnvironment); + if (environments.containsKey(activeEnvironment)) { + return environments.get(activeEnvironment); + } else { + throw new FitConnectInitialisationException("No environment with name '" + activeEnvironment.getName() + "' found. Available environments are: " + getAvailableEnvironmentNames()); + } } public String getOAuthTokenEndpoint() { - return getCurrentEnvironment().getAuthBaseUrl() + ResourcePaths.AUTH_TOKEN_PATH; + return getAuthBaseUrl() + ResourcePaths.AUTH_TOKEN_PATH; } public String getSubmissionsEndpoint() { @@ -113,7 +124,10 @@ public class ApplicationConfig { } private String getSubmissionBaseUrl() { - return getCurrentEnvironment().getSubmissionBaseUrl(); + return getCurrentEnvironment().getSubmissionBaseUrls() + .stream() + .findFirst() + .orElseThrow(() -> new FitConnectInitialisationException("No submission base url found, expected at least one")); } private String getSelfServicePortalBaseUrl() { @@ -124,6 +138,10 @@ public class ApplicationConfig { return getCurrentEnvironment().getRoutingBaseUrl(); } + private String getAuthBaseUrl() { + return getCurrentEnvironment().getAuthBaseUrl(); + } + private String getAvailableEnvironmentNames() { return environments.keySet() .stream() diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/Environment.java b/api/src/main/java/dev/fitko/fitconnect/api/config/Environment.java index af65655666ce26b69963a1468f452a05a960d4b6..ddcae3873fbcb8628f4e8ee47749b1464367f6fc 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/Environment.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/Environment.java @@ -4,14 +4,48 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.Collections; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor public class Environment { + private String authBaseUrl; private String routingBaseUrl; - private String submissionBaseUrl; + private List<String> submissionBaseUrls = Collections.emptyList(); private String selfServicePortalBaseUrl; - private boolean allowInsecurePublicKey; - private boolean skipSubmissionDataValidation; + + private Boolean enableAutoReject = true; + private Boolean allowInsecurePublicKey = false; + private Boolean skipSubmissionDataValidation = false; + + /** + * Merges current env with provided other env. + * If a field of the current env is null or empty, the value from other will be set. + * + * @param other environment to merge the current environment with + * @return merged environment + */ + public Environment merge(final Environment other){ + + final Environment mergedEnv = new Environment(); + + mergedEnv.setAuthBaseUrl(isNullOrEmpty(authBaseUrl) ? other.getAuthBaseUrl() : authBaseUrl); + mergedEnv.setRoutingBaseUrl(isNullOrEmpty(routingBaseUrl) ? other.getRoutingBaseUrl() : routingBaseUrl); + mergedEnv.setSubmissionBaseUrls(submissionBaseUrls.isEmpty() ? other.getSubmissionBaseUrls() : submissionBaseUrls); + mergedEnv.setSelfServicePortalBaseUrl(isNullOrEmpty(selfServicePortalBaseUrl) ? other.getSelfServicePortalBaseUrl() : selfServicePortalBaseUrl); + + mergedEnv.setEnableAutoReject(enableAutoReject == null ? other.getEnableAutoReject() : enableAutoReject); + mergedEnv.setAllowInsecurePublicKey(allowInsecurePublicKey == null ? other.getAllowInsecurePublicKey() : allowInsecurePublicKey); + mergedEnv.setSkipSubmissionDataValidation(skipSubmissionDataValidation == null ? other.getSkipSubmissionDataValidation() : skipSubmissionDataValidation); + + return mergedEnv; + } + + private boolean isNullOrEmpty(final String s){ + return s == null || s.isEmpty(); + } + } diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java b/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java deleted file mode 100644 index 367aee5f1e9241da95d258021e3e7ed58dd49c4f..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.fitko.fitconnect.api.config; - -final class ResourcePaths { - - private ResourcePaths() { - } - - static final String AUTH_TOKEN_PATH = "/token"; - - static final String DESTINATIONS_PATH = "/v1/destinations/%s"; - static final String DESTINATIONS_KEY_PATH = "/v1/destinations/%s/keys/%s"; - - static final String EVENTS_PATH = "/v1/cases/%s/events"; - - static final String SUBMISSION_PATH = "/v1/submissions/%s"; - static final String SUBMISSIONS_PATH = "/v1/submissions"; - static final String SUBMISSION_ATTACHMENT_PATH = "/v1/submissions/%s/attachments/%s"; - - static final String ROUTING_AREA_PATH = "/v1/areas"; - static final String ROUTING_ROUTE_PATH = "/v1/routes"; - - static final String WELL_KNOWN_KEYS_PATH = "/.well-known/jwks.json"; -} - diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/BuildInfo.java b/api/src/main/java/dev/fitko/fitconnect/api/config/build/BuildInfo.java similarity index 76% rename from api/src/main/java/dev/fitko/fitconnect/api/config/BuildInfo.java rename to api/src/main/java/dev/fitko/fitconnect/api/config/build/BuildInfo.java index d73b03b823f7b9f73a7b305493ffe5ec930933e9..dac3c451b0486dd003e8d69f0df7f54571502163 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/BuildInfo.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/build/BuildInfo.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.config; +package dev.fitko.fitconnect.api.config.build; import lombok.Data; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/DefaultEnvironments.java b/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/DefaultEnvironments.java new file mode 100644 index 0000000000000000000000000000000000000000..73e1c377a5bb556c1629bb82495be152f985425e --- /dev/null +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/DefaultEnvironments.java @@ -0,0 +1,51 @@ +package dev.fitko.fitconnect.api.config.defaults; + +import dev.fitko.fitconnect.api.config.Environment; +import dev.fitko.fitconnect.api.config.EnvironmentName; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Getter +@AllArgsConstructor +public enum DefaultEnvironments { + + PROD(new EnvironmentName("PROD"), new Environment( + "https://auth-prod.fit-connect.fitko.net", + "https://routing-api-prod.fit-connect.fitko.net", + List.of("https://submission-api-prod.fit-connect.niedersachsen.de"), + "https://portal.auth-prod.fit-connect.fitko.net", + true, + false, + false)), + + STAGE(new EnvironmentName("STAGE"), new Environment( + "https://auth-refz.fit-connect.fitko.net", + "https://routing-api-prod.fit-connect.fitko.net", + List.of("https://submission-api-refz.fit-connect.niedersachsen.de"), + "https://portal.auth-refz.fit-connect.fitko.net", + true, + false, + false) + ), + + TEST(new EnvironmentName("TEST"), new Environment( + "https://auth-testing.fit-connect.fitko.dev", + "https://routing-api-testing.fit-connect.fitko.dev", + List.of("https://submission-api-testing.fit-connect.fitko.dev"), + "https://portal.auth-testing.fit-connect.fitko.dev", + true, + true, + false)); + + private final EnvironmentName environmentName; + private final Environment environment; + + public static Map<EnvironmentName, Environment> getEnvironmentsAsMap(){ + return Arrays.stream(values()).collect(Collectors.toMap(DefaultEnvironments::getEnvironmentName, DefaultEnvironments::getEnvironment)); + } +} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/ResourcePaths.java b/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/ResourcePaths.java new file mode 100644 index 0000000000000000000000000000000000000000..29614c66cb938e597fc1edff93771965c33f184f --- /dev/null +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/ResourcePaths.java @@ -0,0 +1,24 @@ +package dev.fitko.fitconnect.api.config.defaults; + +public final class ResourcePaths { + + private ResourcePaths() { + } + + public static final String AUTH_TOKEN_PATH = "/token"; + + public static final String DESTINATIONS_PATH = "/v1/destinations/{destinationId}"; + public static final String DESTINATIONS_KEY_PATH = "/v1/destinations/{destinationId}/keys/{kid}"; + + public static final String EVENTS_PATH = "/v1/cases/{caseId}/events"; + + public static final String SUBMISSION_PATH = "/v1/submissions/{submissionId}"; + public static final String SUBMISSIONS_PATH = "/v1/submissions"; + public static final String SUBMISSION_ATTACHMENT_PATH = "/v1/submissions/{submissionId}/attachments/{attachmentId}"; + + public static final String ROUTING_AREA_PATH = "/v1/areas"; + public static final String ROUTING_ROUTE_PATH = "/v1/routes"; + + public static final String WELL_KNOWN_KEYS_PATH = "/.well-known/jwks.json"; +} + diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java b/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/SchemaConfig.java similarity index 97% rename from api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java rename to api/src/main/java/dev/fitko/fitconnect/api/config/defaults/SchemaConfig.java index b1d3c0d49c2823d3b261acc212514b5b57922005..6c9e66c16b85c5d9833e950f173702b9c883066d 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/SchemaConfig.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/defaults/SchemaConfig.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.config; +package dev.fitko.fitconnect.api.config.defaults; import lombok.Getter; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/domain/model/event/Event.java b/api/src/main/java/dev/fitko/fitconnect/api/domain/model/event/Event.java index 3a1bf7c1c9676ed697efa2a6f26ecd5de562a454..ce8321917bfbb9bcbe702eb195cbd80b95274c29 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/domain/model/event/Event.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/domain/model/event/Event.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import static dev.fitko.fitconnect.api.config.SchemaConfig.EVENTS_SCHEMA_PATH; +import static dev.fitko.fitconnect.api.config.defaults.SchemaConfig.EVENTS_SCHEMA_PATH; public enum Event { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationContext.java b/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationContext.java index 9448e3ad0bc9e2dd8c82ffca50685f0b3a4eb1b5..058911a4c930bb426823e808758c95d10e59e5c0 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationContext.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationContext.java @@ -1,7 +1,7 @@ package dev.fitko.fitconnect.api.domain.validation; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import lombok.Getter; import java.util.ArrayList; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationResult.java b/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationResult.java index 129780e15ceb875ba1a9538599e2ccd3716bd26a..be37b33edb89977f9a9d6a53ab9fee14853d4ddf 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationResult.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/domain/validation/ValidationResult.java @@ -1,6 +1,7 @@ package dev.fitko.fitconnect.api.domain.validation; import dev.fitko.fitconnect.api.domain.model.event.problems.Problem; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import java.util.ArrayList; import java.util.List; @@ -61,6 +62,15 @@ public final class ValidationResult { return new ValidationResult(false, exception); } + /** + * Create new failed result with an error message that's wrapped in a ValidationException. + * + * @return the invalid result + */ + public static ValidationResult error(final String errorMessage) { + return new ValidationResult(false, new ValidationException(errorMessage)); + } + /** * Create new failed result with a {@link Problem}. * diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AttachmentCreationException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AttachmentCreationException.java deleted file mode 100644 index c510597c7acdfff01460919a315ad29042c3db9c..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AttachmentCreationException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class AttachmentCreationException extends RuntimeException { - - public AttachmentCreationException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } - - public AttachmentCreationException(final String errorMessage) { - super(errorMessage); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AttachmentUploadException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AttachmentUploadException.java deleted file mode 100644 index cc12d3ac7a33ea2067f12b622020c1e960ec5d47..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AttachmentUploadException.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class AttachmentUploadException extends RuntimeException { - - public AttachmentUploadException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AuthenticationException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AuthenticationException.java deleted file mode 100644 index 0091336dd9c96d676741cc0d990e1e953ccb3f7f..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AuthenticationException.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class AuthenticationException extends RuntimeException { - - public AuthenticationException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DataNotPresentException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DataNotPresentException.java deleted file mode 100644 index b9914ed451f32dad632ba4c25bece1d1db5590c6..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DataNotPresentException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class DataNotPresentException extends RuntimeException { - - public DataNotPresentException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } - - public DataNotPresentException(final String errorMessage) { - super(errorMessage); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/FileHandlingException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/FileHandlingException.java deleted file mode 100644 index dfe704d8d1b0e97e652029ba1619fa7294cade56..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/FileHandlingException.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class FileHandlingException extends RuntimeException { - - public FileHandlingException(Exception exception) { - super(exception); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/InitializationException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/InitializationException.java deleted file mode 100644 index 3c723047701e37ff8c1b0991eedaaf12a9461e08..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/InitializationException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class InitializationException extends RuntimeException { - - public InitializationException(final String errorMessage) { - super(errorMessage); - } - - public InitializationException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/KeyNotRetrievedException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/KeyNotRetrievedException.java deleted file mode 100644 index 3858e304602a571b20eaef89dd61a0e6358c1b32..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/KeyNotRetrievedException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class KeyNotRetrievedException extends RuntimeException { - - public KeyNotRetrievedException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } - - public KeyNotRetrievedException(final String errorMessage) { - super(errorMessage); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/MetadataNotCreatedException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/MetadataNotCreatedException.java deleted file mode 100644 index 6a4eb61a666e3d794c76c82c82d0280cb267444a..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/MetadataNotCreatedException.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class MetadataNotCreatedException extends RuntimeException { - - public MetadataNotCreatedException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RoutingException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RoutingException.java deleted file mode 100644 index ad334471f971fc361883cc03781fdd37b6b21f36..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RoutingException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class RoutingException extends RuntimeException { - - public RoutingException(final String errorMessage) { - super(errorMessage); - } - - public RoutingException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmissionNotCreatedException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmissionNotCreatedException.java deleted file mode 100644 index 2a41fa6835b6f7ffa5057599b9d7ae1f86b52446..0000000000000000000000000000000000000000 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmissionNotCreatedException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.fitko.fitconnect.api.exceptions; - -public class SubmissionNotCreatedException extends RuntimeException { - - public SubmissionNotCreatedException(final String errorMessage, final Throwable error) { - super(errorMessage, error); - } - - public SubmissionNotCreatedException(final String errorMessage) { - super(errorMessage); - } -} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectInitialisationException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectInitialisationException.java new file mode 100644 index 0000000000000000000000000000000000000000..f52f617849f4fbdae7351ef83f367f22ae37289d --- /dev/null +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectInitialisationException.java @@ -0,0 +1,12 @@ +package dev.fitko.fitconnect.api.exceptions.client; + +public class FitConnectInitialisationException extends RuntimeException { + + public FitConnectInitialisationException(final String errorMessage) { + super(errorMessage); + } + + public FitConnectInitialisationException(final String errorMessage, final Throwable error) { + super(errorMessage, error); + } +} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectRouterException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectRouterException.java new file mode 100644 index 0000000000000000000000000000000000000000..0f5ce3db91f80a12a74811b4b2a223a2f49225e9 --- /dev/null +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectRouterException.java @@ -0,0 +1,13 @@ +package dev.fitko.fitconnect.api.exceptions.client; + +public class FitConnectRouterException extends RuntimeException { + + public FitConnectRouterException(final String errorMessage, final Throwable throwable) { + super(errorMessage, throwable); + } + + public FitConnectRouterException(final String errorMessage) { + super(errorMessage); + } + +} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectSenderException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectSenderException.java new file mode 100644 index 0000000000000000000000000000000000000000..896a07e20a2e280afbdbc60fe70261bbd7cbdd77 --- /dev/null +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectSenderException.java @@ -0,0 +1,8 @@ +package dev.fitko.fitconnect.api.exceptions.client; + +public class FitConnectSenderException extends RuntimeException { + + public FitConnectSenderException(final String errorMessage, final Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectSubscriberException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectSubscriberException.java new file mode 100644 index 0000000000000000000000000000000000000000..7b3a951591b23cff21b1de3815f8978c8d071d18 --- /dev/null +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/client/FitConnectSubscriberException.java @@ -0,0 +1,8 @@ +package dev.fitko.fitconnect.api.exceptions.client; + +public class FitConnectSubscriberException extends RuntimeException { + + public FitConnectSubscriberException(final String errorMessage, final Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AuthenticationTagsEmptyException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/AuthenticationTagsEmptyException.java similarity index 85% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/AuthenticationTagsEmptyException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/AuthenticationTagsEmptyException.java index 8b4ad53aa037dc3cde571b77dde849582a952d83..b0bb330ca24fdcae71b526be582685cb8d4172d9 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/AuthenticationTagsEmptyException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/AuthenticationTagsEmptyException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class AuthenticationTagsEmptyException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/BatchImportException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/BatchImportException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/BatchImportException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/BatchImportException.java index c91e7437063a1592dd8237c160a88156e16205c5..d65a9c0d8ac2bb77bbae30a7b4d2f4f5ec1f2b0e 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/BatchImportException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/BatchImportException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class BatchImportException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DataIntegrityException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/DataIntegrityException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/DataIntegrityException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/DataIntegrityException.java index bbd29906d8ba74272968f4d30289e14dc3b7af80..e17a9ae8d4c42db61a638bef7ff40e6447253f0e 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DataIntegrityException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/DataIntegrityException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class DataIntegrityException extends Exception { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DecryptionException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/DecryptionException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/DecryptionException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/DecryptionException.java index 37174195c1f879481304f9104d2c1a991933dcd7..ff15c62f7cf5d120eea2d0a36224f773130c046a 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/DecryptionException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/DecryptionException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class DecryptionException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/EncryptionException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EncryptionException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/EncryptionException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EncryptionException.java index a9a780966eb91a7a5b4c01d87c463c64bd68b3da..64a786aa81c9ef62487b511d80279c98c2a78c7d 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/EncryptionException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EncryptionException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class EncryptionException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/EventCreationException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EventCreationException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/EventCreationException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EventCreationException.java index 41e4c0d94b3889200348a301868e0426bff5a391..3a02e0bc22af5d58be8125b5378016d4d77dce0f 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/EventCreationException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EventCreationException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class EventCreationException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/EventLogException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EventLogException.java similarity index 83% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/EventLogException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EventLogException.java index d47bdc98396880ee8dfa6fc12f11f863cb841501..9e2ae46efb2ef6265886378505d5f31419c555b3 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/EventLogException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/EventLogException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class EventLogException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/InvalidKeyException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/InvalidKeyException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/InvalidKeyException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/InvalidKeyException.java index 52cb4aa6bbbe21eeda985e252518c88103b08613..0571c1cb8d3cce5afb92d77ddb71269d7b156a2f 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/InvalidKeyException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/InvalidKeyException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class InvalidKeyException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/RestApiException.java similarity index 93% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/RestApiException.java index bbefe15ed5db248b3f7738422ed16c1980af2b46..a1aee1f01fa8db6de81d61449c05ab3508d84386 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/RestApiException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class RestApiException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RootCertificateException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/RootCertificateException.java similarity index 82% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/RootCertificateException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/RootCertificateException.java index 4d888dab142cdb285747c2f0e10a93bd843f701a..568f9e11899106d1ebfd2a4605d8620a58b3d04e 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RootCertificateException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/RootCertificateException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class RootCertificateException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SchemaNotFoundException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SchemaNotFoundException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/SchemaNotFoundException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SchemaNotFoundException.java index f7c4b982c102ad6f692cd8c9c93c5d1c9b168c1c..43bd955964276e3eb8bd7bd502d45385be52b1e5 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SchemaNotFoundException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SchemaNotFoundException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class SchemaNotFoundException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmissionRequestException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SubmissionRequestException.java similarity index 85% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmissionRequestException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SubmissionRequestException.java index 708c3355cbee2f243e09dd4f6771d37d8f48fe83..2202a1a9fb0abc9b3bcb065b40cc0ceb9b35ede6 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmissionRequestException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SubmissionRequestException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class SubmissionRequestException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmitEventNotFoundException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SubmitEventNotFoundException.java similarity index 85% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmitEventNotFoundException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SubmitEventNotFoundException.java index 5075c4886298d75067ea9de71fcef7348c1a89c0..52d7a91f0c43b53df5a2afb76288306e32bd25b5 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/SubmitEventNotFoundException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/SubmitEventNotFoundException.java @@ -1,4 +1,4 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class SubmitEventNotFoundException extends RuntimeException { diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/ValidationException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/ValidationException.java similarity index 84% rename from api/src/main/java/dev/fitko/fitconnect/api/exceptions/ValidationException.java rename to api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/ValidationException.java index 3113bb7807e78e3b93d7548ac8bf06fbda2632b6..941d757e2c167b0791278d32dde057fbc06693e7 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/ValidationException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/internal/ValidationException.java @@ -1,8 +1,7 @@ -package dev.fitko.fitconnect.api.exceptions; +package dev.fitko.fitconnect.api.exceptions.internal; public class ValidationException extends RuntimeException { - public ValidationException(final String errorMessage) { super(errorMessage); } 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 b6255764d53ae6fe9d91e83cdd947cd072f4878a..e5534d1ee621afd5529e17eda05a162574797aed 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 @@ -4,7 +4,6 @@ import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.domain.model.destination.Destination; import dev.fitko.fitconnect.api.domain.model.event.EventLogEntry; import dev.fitko.fitconnect.api.domain.model.event.SubmissionStatus; -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.metadata.attachment.ApiAttachment; import dev.fitko.fitconnect.api.domain.model.metadata.data.Data; @@ -13,9 +12,9 @@ import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; 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.model.submission.*; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.*; +import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import java.net.URI; import java.util.List; @@ -85,9 +84,8 @@ public interface Sender { * @param submission with a destinationId, a list of attachmentIds and a serviceType * @return the announced submission * - * @throws SubmissionNotCreatedException if the announcement of the submission failed, e.g. due to a technical problem */ - SubmissionForPickup createSubmission(CreateSubmission submission) throws SubmissionNotCreatedException; + SubmissionForPickup createSubmission(CreateSubmission submission); /** * Uploads encrypted {@link ApiAttachment}s to for given submission id. @@ -96,7 +94,6 @@ public interface Sender { * @param attachmentId unique identifier of the attachment * @param encryptedAttachment string of JWE encrypted attachment * - * @throws AttachmentUploadException if a technical problem occurred upload the attachment */ void uploadAttachment(UUID submissionId, UUID attachmentId, String encryptedAttachment); @@ -115,9 +112,8 @@ public interface Sender { * * @return the public key for encrypting {@link Metadata}, {@link Data} and {@link ApiAttachment}s * - * @throws KeyNotRetrievedException if a technical problem occurred fetching the key */ - RSAKey getEncryptionKeyForDestination(UUID destinationId) throws KeyNotRetrievedException; + RSAKey getEncryptionKeyForDestination(UUID destinationId); /** * Send a {@link SubmitSubmission} that includes encrypted {@link Metadata} and {@link Data} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/Subscriber.java b/api/src/main/java/dev/fitko/fitconnect/api/services/Subscriber.java index 29db8291a4a9b77f93d4725b9ceeb467569931db..f82b50132e50b8bb28131b34902f6dd14f4cffc0 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/Subscriber.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/Subscriber.java @@ -14,8 +14,8 @@ import dev.fitko.fitconnect.api.domain.model.metadata.data.Data; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.DecryptionException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import java.net.URI; import java.util.List; @@ -147,6 +147,7 @@ public interface Subscriber { * Sends a confirmation event if the received submission matches all validations. * * @param eventPayload contains submissionId, caseId, destination and a list of problems + * @see <a href="https://docs.fitko.de/fit-connect/docs/receiving/process-and-acknowledge">Process And Acknowledge</a> */ void acceptSubmission(EventPayload eventPayload); @@ -155,6 +156,7 @@ public interface Subscriber { * Sends a rejection event if the received submission violates any validation rule. * * @param eventPayload contains submissionId, caseId, destination and a list of problems + * @see <a href="https://docs.fitko.de/fit-connect/docs/receiving/process-and-acknowledge">Process And Acknowledge</a> */ void rejectSubmission(EventPayload eventPayload); diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/auth/OAuthService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/auth/OAuthService.java index c553dd0f55945bf01fa2ca8380c5c862ae1f99b5..685e577cc5440303bb78350dd375a09162989ac5 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/auth/OAuthService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/auth/OAuthService.java @@ -3,7 +3,7 @@ package dev.fitko.fitconnect.api.services.auth; import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; /** * A service that provides an interface to authenticate against the FIT-Connect API in order diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java index fb6d70e73f17a1ea0b7959d297a3e5f9ff675124..890ffc9f14ac68f9d8e675173e8ebd98be82562f 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java @@ -4,8 +4,8 @@ import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.domain.model.metadata.attachment.ApiAttachment; import dev.fitko.fitconnect.api.domain.model.metadata.data.Data; import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; -import dev.fitko.fitconnect.api.exceptions.DecryptionException; -import dev.fitko.fitconnect.api.exceptions.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException; /** * A service that allows to encrypt and decrypt {@link Data} and {@link ApiAttachment}s of a {@link SubmitSubmission} diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/events/EventLogService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/events/EventLogService.java index d319f317dcbf277ee90f971d0f05aac7cd04920b..ded5f5a1a3f035bbfee219262c1b5ed189a0ec9a 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/events/EventLogService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/events/EventLogService.java @@ -7,7 +7,7 @@ import dev.fitko.fitconnect.api.domain.model.event.EventLogEntry; import dev.fitko.fitconnect.api.domain.model.event.SubmissionStatus; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.model.submission.Submission; -import dev.fitko.fitconnect.api.exceptions.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; import java.util.List; import java.util.UUID; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/events/SecurityEventService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/events/SecurityEventService.java index 4ec5ce6d97615df76a75a82ddb0608e2d43012ff..3ff98c30180baee8e002c74944b7b42923e9ea23 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/events/SecurityEventService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/events/SecurityEventService.java @@ -4,7 +4,7 @@ import com.nimbusds.jwt.SignedJWT; import dev.fitko.fitconnect.api.domain.model.event.EventLog; import dev.fitko.fitconnect.api.domain.model.event.EventPayload; import dev.fitko.fitconnect.api.domain.model.submission.Submission; -import dev.fitko.fitconnect.api.exceptions.EventCreationException; +import dev.fitko.fitconnect.api.exceptions.internal.EventCreationException; /** * A service that creates SET events that are added to a {@link Submission}s {@link EventLog}. diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/routing/RoutingService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/routing/RoutingService.java index d398df4511dffc54be443b6da13ab7608169fa11..fe8b64d16d2856db12572d1e1db3adf9218f9f44 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/routing/RoutingService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/routing/RoutingService.java @@ -4,7 +4,7 @@ import dev.fitko.fitconnect.api.domain.model.route.Area; import dev.fitko.fitconnect.api.domain.model.route.AreaResult; import dev.fitko.fitconnect.api.domain.model.route.Route; import dev.fitko.fitconnect.api.domain.model.route.RouteResult; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import java.util.List; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/schema/SchemaProvider.java b/api/src/main/java/dev/fitko/fitconnect/api/services/schema/SchemaProvider.java index af69d63c2ee5263af2f30835720158d25cef30cf..2874cda531cd9d84cb19a93eb37fb83294733b34 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/schema/SchemaProvider.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/schema/SchemaProvider.java @@ -1,7 +1,7 @@ package dev.fitko.fitconnect.api.services.schema; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; -import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.SchemaNotFoundException; import java.net.URI; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/submission/SubmissionService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/submission/SubmissionService.java index 5f49f41da3c6b6bff5c30ef75f3bf1f5e3c1308e..dd8277053dfa7616ebcf827df1d009e874288428 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/services/submission/SubmissionService.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/services/submission/SubmissionService.java @@ -10,7 +10,7 @@ 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.SubmissionsForPickup; import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import java.util.UUID; diff --git a/client/src/main/java/dev/fitko/fitconnect/client/RouterClient.java b/client/src/main/java/dev/fitko/fitconnect/client/RouterClient.java new file mode 100644 index 0000000000000000000000000000000000000000..7386001362beeaae85cd39f57eed15e9eb135354 --- /dev/null +++ b/client/src/main/java/dev/fitko/fitconnect/client/RouterClient.java @@ -0,0 +1,84 @@ +package dev.fitko.fitconnect.client; + +import dev.fitko.fitconnect.api.domain.model.route.Area; +import dev.fitko.fitconnect.api.domain.model.route.Route; +import dev.fitko.fitconnect.api.domain.model.route.RouteResult; +import dev.fitko.fitconnect.api.domain.validation.ValidationResult; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectRouterException; +import dev.fitko.fitconnect.api.services.routing.RoutingService; +import dev.fitko.fitconnect.client.router.DestinationSearch; +import dev.fitko.fitconnect.core.routing.RouteVerifier; + +import java.util.List; +import java.util.function.Supplier; + +public final class RouterClient { + + private final RoutingService routingService; + private final RouteVerifier routeVerifier; + + public RouterClient(final RoutingService routingService, final RouteVerifier routeVerifier) { + this.routingService = routingService; + this.routeVerifier = routeVerifier; + } + + /** + * Finds a list of {@link Route}s by a given service identifier and an area search criterion. + * + * @param search search parameters that contain leikaKey and one other area search criterion see {@link DestinationSearch} + * @return list of found {@link Route}s matching the search criteria + * @throws FitConnectRouterException if the signature validation failed or a technical error occurred + */ + public List<Route> findDestinations(final DestinationSearch search) throws FitConnectRouterException { + + final String leikaKey = search.getLeikaKey(); + final String ars = search.getArs(); + final String ags = search.getAgs(); + final String areaId = search.getAreaId(); + final int offset = search.getOffset(); + final int limit = search.getLimit(); + + final RouteResult routeResult = wrapExceptions(() -> routingService.getRoutes(leikaKey, ars, ags, areaId, offset, limit), "Finding destination failed"); + final ValidationResult validationResult = routeVerifier.validateRouteDestinations(routeResult.getRoutes(), leikaKey, ars); + + if (validationResult.hasError()) { + throw new FitConnectRouterException(validationResult.getError().getMessage(), validationResult.getError()); + } + + return routeResult.getRoutes(); + } + + /** + * Finds a list of {@link Area}s based on a filter criterion, e.g. a zip code or city. + * + * @param filter filter criterion as string + * @param offset offset to start from + * @param limit max entries + * @return list of {@link Area} + * @throws FitConnectRouterException if a technical error occurred during the query + */ + public List<Area> findAreas(final String filter, final int offset, final int limit) throws FitConnectRouterException { + return wrapExceptions(() -> findAreas(List.of(filter), offset, limit), "Finding areas failed"); + } + + /** + * Find a list {@link Area}s based on a list of multiple filter criteria, e.g. a zip code or a city as in List.of("04229", "Leip*"). + * + * @param filters list of string filters + * @param offset offset to start from + * @param limit max entries + * @return list of {@link Area} + * @throws FitConnectRouterException if a technical error occurred during the query + */ + public List<Area> findAreas(final List<String> filters, final int offset, final int limit) throws FitConnectRouterException { + return wrapExceptions(() -> routingService.getAreas(filters, offset, limit).getAreas(), "Finding areas failed"); + } + + private <T> T wrapExceptions(final Supplier<T> supplier, final String errorMessage) { + try { + return supplier.get(); + } catch (final Exception e) { + throw new FitConnectRouterException(errorMessage, e.getCause() != null ? e.getCause() : e); + } + } +} diff --git a/client/src/main/java/dev/fitko/fitconnect/client/RoutingClient.java b/client/src/main/java/dev/fitko/fitconnect/client/RoutingClient.java deleted file mode 100644 index c4438300daff840e8dcc9090eb3688004a22651b..0000000000000000000000000000000000000000 --- a/client/src/main/java/dev/fitko/fitconnect/client/RoutingClient.java +++ /dev/null @@ -1,67 +0,0 @@ -package dev.fitko.fitconnect.client; - -import dev.fitko.fitconnect.api.domain.model.route.Area; -import dev.fitko.fitconnect.api.domain.model.route.Route; -import dev.fitko.fitconnect.api.domain.model.route.RouteResult; -import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.RoutingException; -import dev.fitko.fitconnect.api.services.routing.RoutingService; -import dev.fitko.fitconnect.client.router.DestinationSearch; -import dev.fitko.fitconnect.core.routing.RouteVerifier; - -import java.util.List; - -public final class RoutingClient { - - private final RoutingService routingService; - private final RouteVerifier routeVerifier; - - public RoutingClient(final RoutingService routingService, final RouteVerifier routeVerifier) { - this.routingService = routingService; - this.routeVerifier = routeVerifier; - } - - /** - * Finds a list of {@link Route}s by a given service identifier and an area search criterion. - * - * @param search search parameters that contain leikaKey and one other area search criterion see {@link DestinationSearch} - * @return list of found {@link Route}s matching the search criteria - * @throws RoutingException if the signature validation failed - * @throws RestApiException if a technical error occurred during the query - */ - public List<Route> findDestinations(final DestinationSearch search) throws RoutingException, RestApiException { - final RouteResult routeResult = routingService.getRoutes(search.getLeikaKey(), search.getArs(), search.getAgs(), search.getAreaId(), search.getOffset(), search.getLimit()); - final ValidationResult result = routeVerifier.validateRouteDestinations(routeResult.getRoutes(), search.getLeikaKey(), search.getArs()); - if (result.hasError()) { - throw new RoutingException(result.getError().getMessage(), result.getError()); - } - return routeResult.getRoutes(); - } - - /** - * Finds a list of {@link Area}s based on a filter criterion, e.g. a zip code or city. - * - * @param filter filter criterion as string - * @param offset offset to start from - * @param limit max entries - * @return list of {@link Area} - * @throws RestApiException if a technical error occurred during the query - */ - public List<Area> findAreas(final String filter, final int offset, final int limit) throws RestApiException { - return findAreas(List.of(filter), offset, limit); - } - - /** - * Find a list {@link Area}s based on a list of multiple filter criteria, e.g. a zip code or a city as in List.of("04229", "Leip*"). - * - * @param filters list of string filters - * @param offset offset to start from - * @param limit max entries - * @return list of {@link Area} - * @throws RestApiException if a technical error occurred during the query - */ - public List<Area> findAreas(final List<String> filters, final int offset, final int limit) throws RestApiException { - return routingService.getAreas(filters, offset, limit).getAreas(); - } -} 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 997d2c8e567b0e113ca1767a8c396153d7943cf9..89cdcb545848a690878d3e5f147c043d96fc6abf 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/SenderClient.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/SenderClient.java @@ -6,8 +6,7 @@ import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; -import dev.fitko.fitconnect.api.exceptions.KeyNotRetrievedException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSenderException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.model.SendableEncryptedSubmission; import dev.fitko.fitconnect.client.sender.model.SendableSubmission; @@ -16,6 +15,7 @@ import dev.fitko.fitconnect.client.sender.strategies.SendNewSubmissionStrategy; import dev.fitko.fitconnect.client.util.ValidDataGuard; import java.util.UUID; +import java.util.function.Supplier; /** * A sender-side client for announcing and handing in a {@link SubmitSubmission} @@ -36,11 +36,10 @@ public class SenderClient { * * @param destinationId unique identifier of a {@link Destination} * @return optional string containing the public JWK - * @throws KeyNotRetrievedException is there was a technical problem retrieving the key - * @throws InvalidKeyException if the key validation failed + * @throws FitConnectSenderException if a technical or error occurred retrieving the key or a validation failed */ - public String getPublicKeyForDestination(final UUID destinationId) throws KeyNotRetrievedException, InvalidKeyException { - return sender.getEncryptionKeyForDestination(destinationId).toJSONString(); + public String getPublicKeyForDestination(final UUID destinationId) throws FitConnectSenderException { + return wrapExceptions(() -> sender.getEncryptionKeyForDestination(destinationId).toJSONString(), "Retrieving public key failed."); } /** @@ -48,9 +47,10 @@ public class SenderClient { * * @param sentSubmission the original {@link SentSubmission} the status should be retrieved for * @return {@link SubmissionStatus} the current status + * @throws FitConnectSenderException if a technical or error occurred during status retrieval or a validation failed */ - public SubmissionStatus getStatusForSubmission(final SentSubmission sentSubmission) { - return sender.getLastedEvent(sentSubmission); + public SubmissionStatus getStatusForSubmission(final SentSubmission sentSubmission) throws FitConnectSenderException { + return wrapExceptions(() -> sender.getLastedEvent(sentSubmission), "Retrieving current status of submission failed."); } /** @@ -61,28 +61,43 @@ public class SenderClient { * @param httpBody HTTP body provided by the callback * @param callbackSecret secret owned by the client, which is used to calculate the hmac * @return {@code ValidationResult.ok()} if hmac and timestamp provided by the callback meet the required conditions + * @throws FitConnectSenderException if a technical error occurred during the validation */ - public ValidationResult validateCallback(final String hmac, final Long timestamp, final String httpBody, final String callbackSecret) { - return sender.validateCallback(hmac, timestamp, httpBody, callbackSecret); + public ValidationResult validateCallback(final String hmac, final Long timestamp, final String httpBody, final String callbackSecret) throws FitConnectSenderException { + return wrapExceptions(() -> sender.validateCallback(hmac, timestamp, httpBody, callbackSecret), "Callback validation could not be applied."); } /** * Send submission with attachments and data to FIT-Connect API. Encryption is handled by the SDK. * * @return {@link SentSubmission} object of the handed in submission + * @throws FitConnectSenderException if a technical error occurred during sending or a validation failed */ - public SentSubmission send(final SendableSubmission sendableSubmission) { - dataGuard.ensureValidDataPayload(sendableSubmission); - return new SendNewSubmissionStrategy(sender).send(sendableSubmission); + public SentSubmission send(final SendableSubmission sendableSubmission) throws FitConnectSenderException { + return wrapExceptions(() -> { + dataGuard.ensureValidDataPayload(sendableSubmission); + return new SendNewSubmissionStrategy(sender).send(sendableSubmission); + }, "Sending submission failed."); } /** * Send already encrypted submission to FIT-Connect API. * * @return {@link SentSubmission} object of the handed in submission + * @throws FitConnectSenderException if a technical error occurred during sending or a validation failed */ - public SentSubmission send(final SendableEncryptedSubmission sendableEncryptedSubmission) { - dataGuard.ensureValidDataPayload(sendableEncryptedSubmission); - return new SendEncryptedSubmissionStrategy(sender).send(sendableEncryptedSubmission); + public SentSubmission send(final SendableEncryptedSubmission sendableEncryptedSubmission) throws FitConnectSenderException { + return wrapExceptions(() -> { + dataGuard.ensureValidDataPayload(sendableEncryptedSubmission); + return new SendEncryptedSubmissionStrategy(sender).send(sendableEncryptedSubmission); + }, "Sending already encrypted submission failed."); + } + + private <T> T wrapExceptions(final Supplier<T> supplier, final String errorMessage) { + try { + return supplier.get(); + } catch (final Exception e) { + throw new FitConnectSenderException(errorMessage, e.getCause() != null ? e.getCause() : e); + } } } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/SubscriberClient.java b/client/src/main/java/dev/fitko/fitconnect/client/SubscriberClient.java index 932cad122d9cdf148bf8af9388efd2bdff0604df..5fb0258b2527dbbaa3c1bb00b47f1045aa708cb1 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/SubscriberClient.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/SubscriberClient.java @@ -12,7 +12,7 @@ import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.SubmissionRequestException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSubscriberException; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.client.sender.model.Attachment; import dev.fitko.fitconnect.client.subscriber.ReceivedSubmission; @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.function.Supplier; /** * A subscriber-side client for retrieving submissions. @@ -46,8 +47,9 @@ public class SubscriberClient { * * @param destinationId filter criterion for the submissions * @return set of the first 0..500 available submissions + * @throws FitConnectSubscriberException if a technical error occurred retrieving the list of available submissions */ - public Set<SubmissionForPickup> getAvailableSubmissionsForDestination(final UUID destinationId) { + public Set<SubmissionForPickup> getAvailableSubmissionsForDestination(final UUID destinationId) throws FitConnectSubscriberException { return getAvailableSubmissionsForDestination(destinationId, 0, DEFAULT_SUBMISSION_LIMIT); } @@ -58,9 +60,10 @@ public class SubscriberClient { * @param offset position in the dataset * @param limit number of submissions in result (max. is 500) * @return set of available submissions in the given range + * @throws FitConnectSubscriberException if a technical error occurred retrieving the list of available submissions */ - public Set<SubmissionForPickup> getAvailableSubmissionsForDestination(final UUID destinationId, final int offset, final int limit) { - final Set<SubmissionForPickup> submissions = subscriber.pollAvailableSubmissionsForDestination(destinationId, offset, limit); + public Set<SubmissionForPickup> getAvailableSubmissionsForDestination(final UUID destinationId, final int offset, final int limit) throws FitConnectSubscriberException { + final Set<SubmissionForPickup> submissions = wrapExceptions(() -> subscriber.pollAvailableSubmissionsForDestination(destinationId, offset, limit), "Submissions could not be retrieved"); LOGGER.info("Received {} submission(s) for destination {}", submissions.size(), destinationId); return submissions; } @@ -71,8 +74,9 @@ public class SubscriberClient { * @param submission {@link SentSubmission} that is requested * @return {@link ReceivedSubmission} to get the submission {@link Metadata}, {@link Data} and {@link ApiAttachment}s as well as * accept or reject the loaded submission + * @throws FitConnectSubscriberException if a technical error occurred or validation failed */ - public ReceivedSubmission requestSubmission(final SubmissionForPickup submission) { + public ReceivedSubmission requestSubmission(final SubmissionForPickup submission) throws FitConnectSubscriberException { return requestSubmission(submission.getSubmissionId()); } @@ -81,10 +85,10 @@ public class SubscriberClient { * * @param submissionId unique identifier of the requested submission * @return {@link ReceivedSubmission} to get the submission {@link Metadata}, {@link Data} and {@link Attachment}s as well as accept or reject the loaded submission - * @throws SubmissionRequestException if a technical error occurred or validation failed + * @throws FitConnectSubscriberException if a technical error occurred or validation failed */ - public ReceivedSubmission requestSubmission(final UUID submissionId) throws SubmissionRequestException { - return submissionReceiver.receiveSubmission(submissionId); + public ReceivedSubmission requestSubmission(final UUID submissionId) throws FitConnectSubscriberException { + return wrapExceptions(() -> submissionReceiver.receiveSubmission(submissionId), "Submission could not be retrieved"); } /** @@ -92,10 +96,14 @@ public class SubscriberClient { * * @param submissionForPickup the submission that should be rejected * @param rejectionProblems list of {@link Problem}s that give more detailed information on why the submission was rejected + * @throws FitConnectSubscriberException if a technical error occurred rejecting the submission * @see <a href="https://docs.fitko.de/fit-connect/docs/getting-started/event-log/events">FIT-Connect Events</a> */ - public void rejectSubmission(final SubmissionForPickup submissionForPickup, final List<Problem> rejectionProblems) { - subscriber.rejectSubmission(EventPayload.forRejectEvent(submissionForPickup, rejectionProblems)); + public void rejectSubmission(final SubmissionForPickup submissionForPickup, final List<Problem> rejectionProblems) throws FitConnectSubscriberException { + wrapExceptions(() -> { + subscriber.rejectSubmission(EventPayload.forRejectEvent(submissionForPickup, rejectionProblems)); + return null; + }, "Could not reject submission"); } /** @@ -106,21 +114,30 @@ public class SubscriberClient { * @param httpBody HTTP body provided by the callback * @param callbackSecret secret owned by the client, which is used to calculate the hmac * @return {@code true} if hmac and timestamp provided by the callback meet the required conditions + * @throws FitConnectSubscriberException if a technical error occurred during the validation */ - public ValidationResult validateCallback(final String hmac, final Long timestamp, final String httpBody, final String callbackSecret) { - return subscriber.validateCallback(hmac, timestamp, httpBody, callbackSecret); + public ValidationResult validateCallback(final String hmac, final Long timestamp, final String httpBody, final String callbackSecret) throws FitConnectSubscriberException { + return wrapExceptions(() -> subscriber.validateCallback(hmac, timestamp, httpBody, callbackSecret), "Callback validation failed"); } /** * Retrieve the current status of a {@link Submission}. * * @param destinationId unique identifier of the {@link Destination} the status should be retrieved for - * @param caseId unique identifier of the case the status should be retrieved for - * @param submissionId unique identifier of the submission the status should be retrieved for - * + * @param caseId unique identifier of the case the status should be retrieved for + * @param submissionId unique identifier of the submission the status should be retrieved for * @return {@link SubmissionStatus} the current status + * @throws FitConnectSubscriberException if a technical error occurred during the status request */ - public SubmissionStatus getStatusForSubmission(final UUID destinationId, final UUID caseId, final UUID submissionId) { - return subscriber.getLastedEvent(destinationId, caseId, submissionId); + public SubmissionStatus getStatusForSubmission(final UUID destinationId, final UUID caseId, final UUID submissionId) throws FitConnectSubscriberException { + return wrapExceptions(() -> subscriber.getLastedEvent(destinationId, caseId, submissionId), "Status for submission not available"); + } + + private <T> T wrapExceptions(final Supplier<T> supplier, final String errorMessage) { + try { + return supplier.get(); + } catch (final Exception e) { + throw new FitConnectSubscriberException(errorMessage, e.getCause() != null ? e.getCause() : e); + } } } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/bootstrap/ApplicationConfigLoader.java b/client/src/main/java/dev/fitko/fitconnect/client/bootstrap/ApplicationConfigLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..4b2cff42e9fb8470a577ba2c2576d01ded54c70a --- /dev/null +++ b/client/src/main/java/dev/fitko/fitconnect/client/bootstrap/ApplicationConfigLoader.java @@ -0,0 +1,101 @@ +package dev.fitko.fitconnect.client.bootstrap; + +import dev.fitko.fitconnect.api.config.ApplicationConfig; +import dev.fitko.fitconnect.api.config.defaults.DefaultEnvironments; +import dev.fitko.fitconnect.api.config.Environment; +import dev.fitko.fitconnect.api.config.EnvironmentName; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.introspector.BeanAccess; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.util.Map; + +public final class ApplicationConfigLoader { + + private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationConfigLoader.class); + private static final String CONFIG_ENV_KEY_NAME = "FIT_CONNECT_CONFIG"; + + private ApplicationConfigLoader() { + } + + /** + * Load ApplicationConfig from path. + * + * @param configPath path to config file + * @return ApplicationConfig + * @throws FitConnectInitialisationException if the config file could not be loaded + */ + public static ApplicationConfig loadConfigFromPath(final Path configPath) { + try { + return loadConfigFromYamlString(Files.readString(configPath)); + } catch (final IOException | NullPointerException e) { + LOGGER.error("config file could not be loaded from path {}", configPath); + throw new FitConnectInitialisationException(e.getMessage(), e); + } + } + + /** + * Load ApplicationConfig from FIT_CONNECT_CONFIG environment variable. + * Make sure this variable is set and points to a config.yaml. + * + * @return ApplicationConfig + * @throws FitConnectInitialisationException if the config file could not be loaded + */ + public static ApplicationConfig loadConfigFromEnvironment() { + final Path configPath = getPathFromEnvironment(); + return loadConfigFromPath(configPath); + } + + /** + * Load ApplicationConfig from yaml string. + * + * @param configYaml string content of the yaml config file + * @return ApplicationConfig + */ + public static ApplicationConfig loadConfigFromYamlString(final String configYaml) { + return mergeConfigEnvironmentsWithSdkDefaults(initNewYaml().loadAs(configYaml, ApplicationConfig.class)); + } + + /** + * Merge the configured default environments with the config from user. + * + * @param config loaded config with user overrides + * @return application config that contains default environments, overrides of the defaults user specific environments + */ + private static ApplicationConfig mergeConfigEnvironmentsWithSdkDefaults(final ApplicationConfig config) { + + final Map<EnvironmentName, Environment> sdkEnvironments = DefaultEnvironments.getEnvironmentsAsMap(); + final Map<EnvironmentName, Environment> configEnvironments = config.getEnvironments(); + + for (final EnvironmentName environmentName : configEnvironments.keySet()) { + final Environment configEnvironment = configEnvironments.get(environmentName); + if (sdkEnvironments.containsKey(environmentName)) { + sdkEnvironments.put(environmentName, configEnvironment.merge(sdkEnvironments.get(environmentName))); + } else { + sdkEnvironments.put(environmentName, configEnvironment); + } + } + return config.withEnvironments(sdkEnvironments); + } + + private static Path getPathFromEnvironment() { + try { + return Path.of(System.getenv(CONFIG_ENV_KEY_NAME)); + } catch (final NullPointerException | InvalidPathException e) { + LOGGER.warn("Environment variable {} could not be loaded", CONFIG_ENV_KEY_NAME); + throw new FitConnectInitialisationException(e.getMessage(), e); + } + } + + private static Yaml initNewYaml() { + final Yaml yaml = new Yaml(); + yaml.setBeanAccess(BeanAccess.FIELD); + return yaml; + } +} diff --git a/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java b/client/src/main/java/dev/fitko/fitconnect/client/bootstrap/ClientFactory.java similarity index 88% rename from client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java rename to client/src/main/java/dev/fitko/fitconnect/client/bootstrap/ClientFactory.java index eb522217da6bb1d45bfab35864a199890e477ae3..cd88d765d530ae7d069fee4bd087ba25165a2416 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/bootstrap/ClientFactory.java @@ -1,14 +1,13 @@ -package dev.fitko.fitconnect.client.factory; +package dev.fitko.fitconnect.client.bootstrap; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.config.ApplicationConfig; -import dev.fitko.fitconnect.api.config.BuildInfo; -import dev.fitko.fitconnect.api.config.SchemaConfig; +import dev.fitko.fitconnect.api.config.build.BuildInfo; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; import dev.fitko.fitconnect.api.config.SubscriberConfig; import dev.fitko.fitconnect.api.domain.schema.SchemaResources; -import dev.fitko.fitconnect.api.exceptions.InitializationException; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.api.services.auth.OAuthService; @@ -22,7 +21,7 @@ import dev.fitko.fitconnect.api.services.routing.RoutingService; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import dev.fitko.fitconnect.api.services.submission.SubmissionService; import dev.fitko.fitconnect.api.services.validation.ValidationService; -import dev.fitko.fitconnect.client.RoutingClient; +import dev.fitko.fitconnect.client.RouterClient; import dev.fitko.fitconnect.client.SenderClient; import dev.fitko.fitconnect.client.SubscriberClient; import dev.fitko.fitconnect.client.subscriber.SubmissionReceiver; @@ -57,7 +56,7 @@ import java.text.ParseException; import java.util.List; /** - * Factory that constructs {@link SenderClient}, {@link SubscriberClient} and {@link RoutingClient}. + * Factory that constructs {@link SenderClient}, {@link SubscriberClient} and {@link RouterClient}. */ public final class ClientFactory { @@ -77,8 +76,9 @@ public final class ClientFactory { * Create a new {@link SenderClient} to send submissions that is automatically configured via a provided {@link ApplicationConfig}. * * @return the sender client + * @throws FitConnectInitialisationException on errors during the sender client construction */ - public static SenderClient getSenderClient(final ApplicationConfig config) { + public static SenderClient getSenderClient(final ApplicationConfig config) throws FitConnectInitialisationException { checkNotNull(config); LOGGER.info("Initializing sender client ..."); return new SenderClient(getSender(config, loadBuildInfo())); @@ -88,8 +88,9 @@ public final class ClientFactory { * Create a new {@link SubscriberClient} to receive submissions that is automatically configured via a provided {@link ApplicationConfig}. * * @return the subscriber client + * @throws FitConnectInitialisationException on errors during the subscriber client construction */ - public static SubscriberClient getSubscriberClient(final ApplicationConfig config) { + public static SubscriberClient getSubscriberClient(final ApplicationConfig config) throws FitConnectInitialisationException { checkNotNull(config); @@ -106,15 +107,16 @@ public final class ClientFactory { } /** - * Create a new {@link RoutingClient} to find destinations and services that is automatically configured via a provided {@link ApplicationConfig}. + * Create a new {@link RouterClient} to find destinations and services that is automatically configured via a provided {@link ApplicationConfig}. * * @return the routing client + * @throws FitConnectInitialisationException on errors during the routing client construction */ - public static RoutingClient getRoutingClient(final ApplicationConfig config) { + public static RouterClient getRouterClient(final ApplicationConfig config) throws FitConnectInitialisationException { checkNotNull(config); - LOGGER.info("Initializing routing client ..."); + LOGGER.info("Initializing router client ..."); final HttpClient httpClient = getHttpClient(config, loadBuildInfo()); final SchemaProvider schemaProvider = getSchemaProvider(httpClient, config.getSubmissionDataSchemaPath()); final OAuthService authService = getSenderConfiguredAuthService(config, httpClient); @@ -127,7 +129,7 @@ public final class ClientFactory { final RouteVerifier routeVerifier = getRouteVerifier(keyService, validator); final RoutingService routingService = getRoutingService(config, httpClient); - return new RoutingClient(routingService, routeVerifier); + return new RouterClient(routingService, routeVerifier); } private static Sender getSender(final ApplicationConfig config, final BuildInfo buildInfo) { @@ -242,7 +244,7 @@ public final class ClientFactory { return RSAKey.parse(JWK.parse(key).toJSONObject()); } catch (final ParseException | NullPointerException e) { LOGGER.error("Could not parse key, please check environment (config.yml)"); - throw new InvalidKeyException("Key could not be parsed", e); + throw new FitConnectInitialisationException("Key could not be parsed", e); } } @@ -251,24 +253,28 @@ public final class ClientFactory { return Files.readString(Path.of(pathName)); } catch (final IOException | NullPointerException e) { LOGGER.error("Could not read {} from path '{}'. Please provide a valid path in your config.yml", errorKey, pathName); - throw new InitializationException(e.getMessage(), e); + throw new FitConnectInitialisationException(e.getMessage(), e); } } private static BuildInfo loadBuildInfo() { - final InputStream resource = ClientFactory.class.getClassLoader().getResourceAsStream(BUILD_INFO_PATH); - return new Yaml().loadAs(resource, BuildInfo.class); + try { + final InputStream resource = ClientFactory.class.getClassLoader().getResourceAsStream(BUILD_INFO_PATH); + return new Yaml().loadAs(resource, BuildInfo.class); + } catch (final Exception e) { + throw new FitConnectInitialisationException("Build info could not be loaded", e); + } } private static void checkNotNull(final ApplicationConfig config) { if (config == null) { - throw new InitializationException("application config must not be null"); + throw new FitConnectInitialisationException("application config must not be null"); } } private static String getPrivateDecryptionKeyPathFromSubscriber(final SubscriberConfig subscriberConfig) { if (subscriberConfig.getPrivateDecryptionKeyPaths().size() != 1) { - throw new InitializationException("Currently only one configured private key per subscriber is allowed !"); + throw new FitConnectInitialisationException("Currently only one configured private key per subscriber is allowed !"); } final String keyPath = subscriberConfig.getPrivateDecryptionKeyPaths().get(0); LOGGER.info("Reading private decryption key from {}", keyPath); 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 e1f19a66702c72ce2a572d2df27124044e888dbd..0464636b6863ecc604cfdf73294b5cab540c37c9 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 @@ -2,7 +2,7 @@ package dev.fitko.fitconnect.client.cli; import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; -import dev.fitko.fitconnect.api.exceptions.BatchImportException; +import dev.fitko.fitconnect.api.exceptions.internal.BatchImportException; import dev.fitko.fitconnect.client.SenderClient; import dev.fitko.fitconnect.client.SubscriberClient; import dev.fitko.fitconnect.client.cli.batch.BatchImporter; @@ -114,7 +114,7 @@ class CommandExecutor { final SendableSubmission sendableSubmission = SendableSubmission.Builder() .setDestination(sendSubmissionCommand.destinationId) - .setServiceType(sendSubmissionCommand.serviceName, sendSubmissionCommand.leikaKey) + .setServiceType(sendSubmissionCommand.leikaKey, sendSubmissionCommand.serviceName) .setJsonData(getDataAsString(sendSubmissionCommand.data), sendSubmissionCommand.schemaUri) .addAttachments(attachments) .build(); @@ -126,7 +126,7 @@ class CommandExecutor { final SendableSubmission sendableSubmission = SendableSubmission.Builder() .setDestination(sendSubmissionCommand.destinationId) - .setServiceType(sendSubmissionCommand.serviceName, sendSubmissionCommand.leikaKey) + .setServiceType(sendSubmissionCommand.leikaKey, sendSubmissionCommand.serviceName) .setXmlData(getDataAsString(sendSubmissionCommand.data), sendSubmissionCommand.schemaUri) .addAttachments(attachments) .build(); diff --git a/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandLineRunner.java b/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandLineRunner.java index 8b0cd7ef434ad68e5cb76abd97ecf2be2e24a4c1..67ebdb904577f552a49f3fad218db4f48d1dadcb 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandLineRunner.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/cli/CommandLineRunner.java @@ -2,8 +2,8 @@ package dev.fitko.fitconnect.client.cli; import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.client.SenderClient; -import dev.fitko.fitconnect.client.factory.ApplicationConfigLoader; -import dev.fitko.fitconnect.client.factory.ClientFactory; +import dev.fitko.fitconnect.client.bootstrap.ApplicationConfigLoader; +import dev.fitko.fitconnect.client.bootstrap.ClientFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,7 +32,7 @@ public final class CommandLineRunner { try { return ApplicationConfigLoader.loadConfigFromEnvironment(); } catch (final Exception e) { - LOGGER.warn("Could not load config from environment, loading default config {} {}", DEFAULT_CONFIG_NAME, e); + LOGGER.warn("Could not load config from environment, loading default config {}", DEFAULT_CONFIG_NAME); return ApplicationConfigLoader.loadConfigFromPath(Path.of(DEFAULT_CONFIG_NAME)); } } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/cli/batch/CsvImporter.java b/client/src/main/java/dev/fitko/fitconnect/client/cli/batch/CsvImporter.java index 6e48c08a892ec624417c97743f95838736d76930..2c6188981946374f749061f926951ca5da3ae9f2 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/cli/batch/CsvImporter.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/cli/batch/CsvImporter.java @@ -2,7 +2,7 @@ package dev.fitko.fitconnect.client.cli.batch; import com.opencsv.bean.CsvToBeanBuilder; import com.opencsv.bean.exceptionhandler.CsvExceptionHandler; -import dev.fitko.fitconnect.api.exceptions.BatchImportException; +import dev.fitko.fitconnect.api.exceptions.internal.BatchImportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/client/src/main/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoader.java b/client/src/main/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoader.java deleted file mode 100644 index 1bb043e8cc0d312f3fb5f1320e90808f5cdf6b28..0000000000000000000000000000000000000000 --- a/client/src/main/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoader.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.fitko.fitconnect.client.factory; - -import dev.fitko.fitconnect.api.config.ApplicationConfig; -import dev.fitko.fitconnect.api.exceptions.InitializationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.yaml.snakeyaml.Yaml; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; - -public final class ApplicationConfigLoader { - - private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationConfigLoader.class); - private static final String CONFIG_ENV_KEY_NAME = "FIT_CONNECT_CONFIG"; - - private ApplicationConfigLoader() { - } - - /** - * Load ApplicationConfig from path. - * - * @param configPath path to config file - * @return ApplicationConfig - * @throws InitializationException if the config file could not be loaded - */ - public static ApplicationConfig loadConfigFromPath(final Path configPath) { - try { - return loadConfigFromYamlString(Files.readString(configPath)); - } catch (final IOException | NullPointerException e) { - LOGGER.error("config file could not be loaded from path {}", configPath); - throw new InitializationException(e.getMessage(), e); - } - } - - /** - * Load ApplicationConfig from FIT_CONNECT_CONFIG environment variable. - * Make sure this variable is set and points to a config.yaml. - * - * @return ApplicationConfig - * @throws InitializationException if the config file could not be loaded - */ - public static ApplicationConfig loadConfigFromEnvironment() { - final Path configPath = getPathFromEnvironment(); - return loadConfigFromPath(configPath); - } - - /** - * Load ApplicationConfig from yaml string. - * - * @param configYaml string content of the yaml config file - * @return ApplicationConfig - */ - public static ApplicationConfig loadConfigFromYamlString(final String configYaml) { - return new Yaml().loadAs(configYaml, ApplicationConfig.class); - } - - private static Path getPathFromEnvironment() { - try { - return Path.of(System.getenv(CONFIG_ENV_KEY_NAME)); - } catch (final NullPointerException | InvalidPathException e) { - LOGGER.error("Environment variable {} could not be loaded", CONFIG_ENV_KEY_NAME); - throw new InitializationException(e.getMessage(), e); - } - } - -} diff --git a/client/src/main/java/dev/fitko/fitconnect/client/router/DestinationSearch.java b/client/src/main/java/dev/fitko/fitconnect/client/router/DestinationSearch.java index eab9b403648844cbf232e5d7b68ae78acfc177ef..a8b6d3a512b8b23c998f4e858fc10590fcfeb0a3 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/router/DestinationSearch.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/router/DestinationSearch.java @@ -1,5 +1,7 @@ package dev.fitko.fitconnect.client.router; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectRouterException; +import dev.fitko.fitconnect.client.RouterClient; import lombok.AllArgsConstructor; import lombok.Value; @@ -33,9 +35,9 @@ public class DestinationSearch { * * @param leikaKey service identifier * @return Builder - * @throws IllegalArgumentException if the leika key pattern is not matching + * @throws FitConnectRouterException if the leika key pattern is not matching */ - OptionalProperties withLeikaKey(final String leikaKey) throws IllegalArgumentException; + OptionalProperties withLeikaKey(final String leikaKey) throws FitConnectRouterException; } public interface OptionalProperties { @@ -45,53 +47,53 @@ public class DestinationSearch { * * @param ars amtlicher regionalschlüssel * @return Builder - * @throws IllegalArgumentException if the ars key pattern is not matching + * @throws FitConnectRouterException if the ars key pattern is not matching */ - Pagination withArs(final String ars) throws IllegalArgumentException; + Pagination withArs(final String ars) throws FitConnectRouterException; /** * Official regional key of the area. * * @param ags amtlicher gemeindeschlüssel * @return Builder - * @throws IllegalArgumentException if the ags key pattern is not matching + * @throws FitConnectRouterException if the ags key pattern is not matching */ - Pagination withAgs(final String ags) throws IllegalArgumentException; + Pagination withAgs(final String ags) throws FitConnectRouterException; /** * ID of the area. This ID can be determined via the routing clients <code>findAreas</code> search. * * @param areaId id of the area * @return Builder - * @throws IllegalArgumentException if the area id pattern is not matching - * @see dev.fitko.fitconnect.client.RoutingClient#findAreas(String, int, int) + * @throws FitConnectRouterException if the area id pattern is not matching + * @see RouterClient#findAreas(String, int, int) */ - Pagination withAreaId(final String areaId) throws IllegalArgumentException; + Pagination withAreaId(final String areaId) throws FitConnectRouterException; /** * Start position of the subset of the result set. Default is 0. * * @param offset start of the subset * @return Builder - * @throws IllegalArgumentException if the offset is a negative number + * @throws FitConnectRouterException if the offset is a negative number */ - Builder withOffset(final int offset) throws IllegalArgumentException; + Builder withOffset(final int offset) throws FitConnectRouterException; /** * Max. size of the subset of the result set. Maximum is 500. Default is 100. * * @param limit max. entries in the subset * @return Builder - * @throws IllegalArgumentException if the limit is > 500 + * @throws FitConnectRouterException if the limit is > 500 */ - Builder withLimit(final int limit) throws IllegalArgumentException; + Builder withLimit(final int limit) throws FitConnectRouterException; /** * Construct the search request. * * @return DestinationSearch */ - DestinationSearch build() throws IllegalArgumentException; + DestinationSearch build() throws FitConnectRouterException; } @@ -102,25 +104,25 @@ public class DestinationSearch { * * @param offset start of the subset * @return Builder - * @throws IllegalArgumentException if the offset is a negative number + * @throws FitConnectRouterException if the offset is a negative number */ - Pagination withOffset(final int offset) throws IllegalArgumentException; + Pagination withOffset(final int offset) throws FitConnectRouterException; /** * Max. size of the subset of the result set. Maximum is 500. Default is 100. * * @param limit max. entries in the subset * @return Builder - * @throws IllegalArgumentException if the limit is > 500 + * @throws FitConnectRouterException if the limit is > 500 */ - Pagination withLimit(final int limit) throws IllegalArgumentException; + Pagination withLimit(final int limit) throws FitConnectRouterException; /** * Construct the search request. * * @return DestinationSearch */ - DestinationSearch build() throws IllegalArgumentException; + DestinationSearch build() throws FitConnectRouterException; } @@ -130,7 +132,7 @@ public class DestinationSearch { * * @return DestinationSearch */ - DestinationSearch build() throws IllegalArgumentException; + DestinationSearch build() throws FitConnectRouterException; } private static class Builder implements MandatoryProperties, OptionalProperties, Pagination, BuildSearch { @@ -149,18 +151,18 @@ public class DestinationSearch { @Override - public OptionalProperties withLeikaKey(final String leikaKey) throws IllegalArgumentException { + public OptionalProperties withLeikaKey(final String leikaKey) throws FitConnectRouterException { if (!LEIKA_KEY_PATTERN.matcher(leikaKey).matches()) { - throw new IllegalArgumentException("Leika key does not match allowed pattern " + LEIKA_KEY_PATTERN); + throw new FitConnectRouterException("Leika key does not match allowed pattern " + LEIKA_KEY_PATTERN); } this.leikaKey = leikaKey; return this; } @Override - public Pagination withArs(final String ars) throws IllegalArgumentException { + public Pagination withArs(final String ars) throws FitConnectRouterException { if (!ARS_PATTERN.matcher(ars).matches()) { - throw new IllegalArgumentException("ARS key does not match allowed pattern " + ARS_PATTERN); + throw new FitConnectRouterException("ARS key does not match allowed pattern " + ARS_PATTERN); } this.ars = ars; @@ -168,55 +170,48 @@ public class DestinationSearch { } @Override - public Pagination withAgs(final String ags) throws IllegalArgumentException { + public Pagination withAgs(final String ags) throws FitConnectRouterException { if (!AGS_PATTERN.matcher(ags).matches()) { - throw new IllegalArgumentException("AGS key does not match allowed pattern " + AGS_PATTERN); + throw new FitConnectRouterException("AGS key does not match allowed pattern " + AGS_PATTERN); } this.ags = ags; return this; } - /** - * ID of the area. This ID can be determined via the routing clients <code>findAreas</code> search. - * - * @param areaId id of the area - * @return Builder - * @throws IllegalArgumentException if the area id pattern is not matching - * @see dev.fitko.fitconnect.client.RoutingClient#findAreas(String, int, int) - */ - public Pagination withAreaId(final String areaId) throws IllegalArgumentException { + @Override + public Pagination withAreaId(final String areaId) throws FitConnectRouterException { if (!AREA_ID_PATTERN.matcher(areaId).matches()) { - throw new IllegalArgumentException("AreaId key does not match allowed pattern " + AREA_ID_PATTERN); + throw new FitConnectRouterException("AreaId key does not match allowed pattern " + AREA_ID_PATTERN); } this.areaId = areaId; return this; } @Override - public Builder withOffset(final int offset) throws IllegalArgumentException { + public Builder withOffset(final int offset) throws FitConnectRouterException { if (limit < 0) { - throw new IllegalArgumentException("offset must be positive"); + throw new FitConnectRouterException("offset must be positive"); } this.offset = offset; return this; } @Override - public Builder withLimit(final int limit) throws IllegalArgumentException { + public Builder withLimit(final int limit) throws FitConnectRouterException { if (limit > 500) { - throw new IllegalArgumentException("limit must no be > 500"); + throw new FitConnectRouterException("limit must no be > 500"); } this.limit = limit; return this; } @Override - public DestinationSearch build() throws IllegalArgumentException { + public DestinationSearch build() throws FitConnectRouterException { if (leikaKey == null) { - throw new IllegalArgumentException("leikaKey is mandatory"); + throw new FitConnectRouterException("leikaKey is mandatory"); } if(Arrays.asList(areaId, ags, ars).stream().allMatch(Objects::isNull)){ - throw new IllegalArgumentException("at least one regional search criterion (areaId, ars or ags) is mandatory"); + throw new FitConnectRouterException("at least one regional search criterion (areaId, ars or ags) is mandatory"); } return new DestinationSearch(leikaKey, ars, ags, areaId, offset, limit); } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/model/Attachment.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/model/Attachment.java index 932fe4ae7c3dc4e673997642dc045eeca63cbe91..1a4c4ba24269fbec3e9709d3a95f60a8bde1004b 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/model/Attachment.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/model/Attachment.java @@ -1,6 +1,6 @@ package dev.fitko.fitconnect.client.sender.model; -import dev.fitko.fitconnect.api.exceptions.AttachmentCreationException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSenderException; import java.io.BufferedInputStream; import java.io.IOException; @@ -23,7 +23,7 @@ public class Attachment { * @param filePath path of the attachment file * @param mimeType mime-type of the attachment */ - public static Attachment fromPath(final Path filePath, final String mimeType) throws AttachmentCreationException { + public static Attachment fromPath(final Path filePath, final String mimeType) throws FitConnectSenderException { return fromPath(filePath, mimeType, null, null); } @@ -34,9 +34,9 @@ public class Attachment { * @param mimeType mime-type of the attachment * @param fileName name of the attachment file * @param description description of the attachment file - * @throws AttachmentCreationException if the file path could not be read + * @throws FitConnectSenderException if the file path could not be read */ - public static Attachment fromPath(final Path filePath, final String mimeType, final String fileName, final String description) throws AttachmentCreationException { + public static Attachment fromPath(final Path filePath, final String mimeType, final String fileName, final String description) throws FitConnectSenderException { return new Attachment(readBytesFromPath(filePath), mimeType, fileName, description); } @@ -45,9 +45,9 @@ public class Attachment { * * @param inputStream stream of the attachment data * @param mimeType mime type of the provided attachment data - * @throws AttachmentCreationException if the input-stream could not be read + * @throws FitConnectSenderException if the input-stream could not be read */ - public static Attachment fromInputStream(final InputStream inputStream, final String mimeType) throws AttachmentCreationException { + public static Attachment fromInputStream(final InputStream inputStream, final String mimeType) throws FitConnectSenderException { return fromInputStream(inputStream, mimeType, null, null); } @@ -58,9 +58,9 @@ public class Attachment { * @param mimeType mime type of the provided attachment data * @param fileName name of the attachment file * @param description description of the attachment file - * @throws AttachmentCreationException if the input-stream could not be read + * @throws FitConnectSenderException if the input-stream could not be read */ - public static Attachment fromInputStream(final InputStream inputStream, final String mimeType, final String fileName, final String description) throws AttachmentCreationException { + public static Attachment fromInputStream(final InputStream inputStream, final String mimeType, final String fileName, final String description) throws FitConnectSenderException { return new Attachment(readBytesFromInputStream(inputStream), mimeType, fileName, description); } @@ -173,7 +173,7 @@ public class Attachment { try (final BufferedInputStream bis = new BufferedInputStream(inputStream)) { return bis.readAllBytes(); } catch (final IOException e) { - throw new AttachmentCreationException("Attachment could not be read from input-stream ", e); + throw new FitConnectSenderException("Attachment could not be read from input-stream ", e); } } @@ -181,7 +181,7 @@ public class Attachment { try { return Files.readAllBytes(path); } catch (final IOException e) { - throw new AttachmentCreationException("Reading attachment from path '" + path + "' failed ", e); + throw new FitConnectSenderException("Reading attachment from path '" + path + "' failed ", e); } } @@ -189,7 +189,7 @@ public class Attachment { try { return Path.of(fileName).getFileName().toString(); } catch (final InvalidPathException e) { - throw new AttachmentCreationException("Reading filename '" + fileName + "' failed ", e); + throw new FitConnectSenderException("Reading filename '" + fileName + "' failed ", e); } } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedAttachmentsStep.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedAttachmentsStep.java index 0663fe0b801ecc5c3b5410135bf226d0fdb1ee6a..18efe2857be1ba65402eb15070c6a2ad43a7b48c 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedAttachmentsStep.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedAttachmentsStep.java @@ -25,5 +25,9 @@ public interface EncryptedAttachmentsStep { */ EncryptedAttachmentsStep addEncryptedAttachment(UUID id, String content); + /** + * Constructs a new sendable encrypted submission from the data that is set. + * @return SendableEncryptedSubmission + */ SendableEncryptedSubmission build(); } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedBuildStep.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedBuildStep.java index 81cf0ffb415443be0f4e2ad1e09471507e060ca4..450d9bd3e890c92522037c32cc37bc3d0e853e87 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedBuildStep.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/encrypted/EncryptedBuildStep.java @@ -4,5 +4,9 @@ import dev.fitko.fitconnect.client.sender.model.SendableEncryptedSubmission; public interface EncryptedBuildStep { + /** + * Constructs a new sendable encrypted submission from the data that is set. + * @return SendableEncryptedSubmission + */ SendableEncryptedSubmission build(); } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/BuildStep.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/BuildStep.java index 5ac27408c87c9970947ede5e74333e378dd5614f..8577afd40e2ab449b5fc61d36b2480f4fc6a137c 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/BuildStep.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/BuildStep.java @@ -4,5 +4,9 @@ import dev.fitko.fitconnect.client.sender.model.SendableSubmission; public interface BuildStep { + /** + * Constructs a new sendable submission from the data that is set. + * @return SendableSubmission + */ SendableSubmission build(); } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/OptionalPropertiesStep.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/OptionalPropertiesStep.java index 014d8e47bff914d8a17465bd96f2522d9332cd42..f1032d082681e35e0fbd4db4ec3adb8b4ef85d46 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/OptionalPropertiesStep.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/steps/unencrypted/OptionalPropertiesStep.java @@ -44,5 +44,9 @@ public interface OptionalPropertiesStep { OptionalPropertiesStep setPaymentInformation(PaymentInformation paymentInformation); + /** + * Constructs a new sendable submission from the data that is set. + * @return SendableSubmission + */ SendableSubmission build(); } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendEncryptedSubmissionStrategy.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendEncryptedSubmissionStrategy.java index 41e2c405e7f1ac1b78a2fbcd1b8d934bbfe2f79d..0b9044b5ac53c75a76f1ea88482ad0ca86ff946f 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendEncryptedSubmissionStrategy.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendEncryptedSubmissionStrategy.java @@ -5,8 +5,6 @@ import dev.fitko.fitconnect.api.domain.model.submission.CreateSubmission; import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.SubmissionNotCreatedException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.model.SendableEncryptedSubmission; import dev.fitko.fitconnect.core.util.StopWatch; @@ -33,34 +31,25 @@ public class SendEncryptedSubmissionStrategy { public SentSubmission send(final SendableEncryptedSubmission submissionPayload) { - try { + final Map<UUID, String> encryptedAttachments = submissionPayload.getAttachments(); + final String encryptedData = submissionPayload.getData(); + final String encryptedMetadata = submissionPayload.getMetadata(); - final Map<UUID, String> encryptedAttachments = submissionPayload.getAttachments(); - final String encryptedData = submissionPayload.getData(); - final String encryptedMetadata = submissionPayload.getMetadata(); + final UUID submissionId = announceNewSubmission(submissionPayload, encryptedAttachments); + final SubmitSubmission submitSubmission = buildSubmitSubmission(submissionId, encryptedData, encryptedMetadata); - final UUID submissionId = announceNewSubmission(submissionPayload, encryptedAttachments); - final SubmitSubmission submitSubmission = buildSubmitSubmission(submissionId, encryptedData, encryptedMetadata); + final var startTimeAttachmentUpload = StopWatch.start(); + uploadAttachments(encryptedAttachments, submissionId); + LOGGER.info("Uploading attachments took {}", StopWatch.stopWithFormattedTime(startTimeAttachmentUpload)); - final var startTimeAttachmentUpload = StopWatch.start(); - uploadAttachments(encryptedAttachments, submissionId); - LOGGER.info("Uploading attachments took {}", StopWatch.stopWithFormattedTime(startTimeAttachmentUpload)); + final var startTimeSubmissionUpload = StopWatch.start(); + final Submission submission = sender.sendSubmission(submitSubmission); + LOGGER.info("Uploading submission took {}", StopWatch.stopWithFormattedTime(startTimeSubmissionUpload)); - final var startTimeSubmissionUpload = StopWatch.start(); - final Submission submission = sender.sendSubmission(submitSubmission); - LOGGER.info("Uploading submission took {}", StopWatch.stopWithFormattedTime(startTimeSubmissionUpload)); + LOGGER.info("SUCCESSFULLY HANDED IN SUBMISSION ! \n"); + final AuthenticationTags authenticationTags = buildAuthenticationTagsForEncryptedSubmission(encryptedAttachments, encryptedData, encryptedMetadata); + return buildSentSubmission(authenticationTags, submission); - LOGGER.info("SUCCESSFULLY HANDED IN SUBMISSION ! \n"); - final AuthenticationTags authenticationTags = buildAuthenticationTagsForEncryptedSubmission(encryptedAttachments, encryptedData, encryptedMetadata); - return buildSentSubmission(authenticationTags, submission); - - } catch (final RestApiException e) { - LOGGER.error("Sending submission failed", e); - } catch (final SubmissionNotCreatedException e) { - LOGGER.error("Failed to announce new submission", e); - } - - return null; } private UUID announceNewSubmission(final SendableEncryptedSubmission submissionPayload, final Map<UUID, String> encryptedAttachments) { 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 e36adbc7be91a6499c7c2c8f1c2527d6c4ec3437..b1af51fa937b7a6ba67dbf85462c4edd0704d6c4 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 @@ -1,8 +1,6 @@ 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.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.model.metadata.ContentStructure; import dev.fitko.fitconnect.api.domain.model.metadata.Hash; @@ -18,13 +16,6 @@ import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.AttachmentCreationException; -import dev.fitko.fitconnect.api.exceptions.EncryptionException; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; -import dev.fitko.fitconnect.api.exceptions.KeyNotRetrievedException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -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.Attachment; import dev.fitko.fitconnect.client.sender.model.AttachmentPayload; @@ -35,14 +26,16 @@ import org.slf4j.LoggerFactory; import java.net.URI; import java.nio.charset.StandardCharsets; -import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; -import static dev.fitko.fitconnect.api.config.SchemaConfig.METADATA_V_1_0_0; -import static dev.fitko.fitconnect.client.util.SubmissionUtil.*; +import static dev.fitko.fitconnect.api.config.defaults.SchemaConfig.METADATA_V_1_0_0; +import static dev.fitko.fitconnect.client.util.SubmissionUtil.buildAuthenticationTags; +import static dev.fitko.fitconnect.client.util.SubmissionUtil.buildCreateSubmission; +import static dev.fitko.fitconnect.client.util.SubmissionUtil.buildSentSubmission; +import static dev.fitko.fitconnect.client.util.SubmissionUtil.buildSubmitSubmission; public class SendNewSubmissionStrategy { @@ -57,70 +50,48 @@ public class SendNewSubmissionStrategy { public SentSubmission send(final SendableSubmission sendableSubmission) { final UUID destinationId = sendableSubmission.getDestinationId(); + final RSAKey encryptionKey = sender.getEncryptionKeyForDestination(destinationId); - try { - - final RSAKey encryptionKey = sender.getEncryptionKeyForDestination(destinationId); - final Destination destination = sender.getDestination(destinationId); - - LOGGER.info("Encrypting attachments ..."); - final List<AttachmentPayload> encryptedAttachments = encryptAndHashAttachments(encryptionKey, sendableSubmission.getAttachments()); - final CreateSubmission newSubmission = buildCreateSubmission(sendableSubmission, encryptedAttachments); - - final SubmissionForPickup announcedSubmission = sender.createSubmission(newSubmission); - final UUID announcedSubmissionId = announcedSubmission.getSubmissionId(); - - final var startTimeAttachmentUpload = StopWatch.start(); - uploadAttachments(encryptedAttachments, announcedSubmissionId); - LOGGER.info("Uploading attachments took {}", StopWatch.stopWithFormattedTime(startTimeAttachmentUpload)); - - LOGGER.info("Creating metadata"); - final Metadata metadata = buildMetadata(sendableSubmission, destination, encryptedAttachments); - - final ValidationResult validatedMetadata = sender.validateMetadata(metadata); - if (validatedMetadata.hasError()) { - LOGGER.error("Metadata does not match schema", validatedMetadata.getError()); - return null; - } - - LOGGER.info("Encrypting submission data ..."); - final String encryptedData = sender.encryptBytes(encryptionKey, sendableSubmission.getData().getBytes(StandardCharsets.UTF_8)); - - LOGGER.info("Encrypting metadata ..."); - final String encryptedMetadata = sender.encryptObject(encryptionKey, metadata); - - final var startTimeSubmissionUpload = StopWatch.start(); - final Submission submission = sender.sendSubmission(buildSubmitSubmission(announcedSubmissionId, encryptedData, encryptedMetadata)); - LOGGER.info("Uploading submission took {}", StopWatch.stopWithFormattedTime(startTimeSubmissionUpload)); - - LOGGER.info("SUCCESSFULLY HANDED IN SUBMISSION ! \n"); - final AuthenticationTags authenticationTags = buildAuthenticationTags(encryptedAttachments, encryptedData, encryptedMetadata); - return buildSentSubmission(authenticationTags, submission); - - } catch (final EncryptionException e) { - LOGGER.error("Encrypting submission failed", e); - } catch (final RestApiException e) { - LOGGER.error("Sending submission failed", e); - } catch (final SchemaNotFoundException e) { - LOGGER.error("Required schema to send valid submission not found", e); - } catch (final SubmissionNotCreatedException e) { - LOGGER.error("Failed to announce new submission", e); - } catch (final KeyNotRetrievedException e) { - LOGGER.error("Getting encryption key for destination {} failed", destinationId, e); - } catch (final InvalidKeyException e) { - LOGGER.error("Key for destination {} is invalid", destinationId, e); - } catch (final AttachmentCreationException e) { - LOGGER.error("Reading file failed. Attachment will not be created.", e); + LOGGER.info("Encrypting attachments ..."); + final List<AttachmentPayload> encryptedAttachments = encryptAndHashAttachments(encryptionKey, sendableSubmission.getAttachments()); + final CreateSubmission newSubmission = buildCreateSubmission(sendableSubmission, encryptedAttachments); + + final SubmissionForPickup announcedSubmission = sender.createSubmission(newSubmission); + final UUID announcedSubmissionId = announcedSubmission.getSubmissionId(); + + final var startTimeAttachmentUpload = StopWatch.start(); + uploadAttachments(encryptedAttachments, announcedSubmissionId); + LOGGER.info("Uploading attachments took {}", StopWatch.stopWithFormattedTime(startTimeAttachmentUpload)); + + LOGGER.info("Creating metadata"); + final Metadata metadata = buildMetadata(sendableSubmission, encryptedAttachments); + + final ValidationResult validatedMetadata = sender.validateMetadata(metadata); + if (validatedMetadata.hasError()) { + LOGGER.error("Metadata does not match schema", validatedMetadata.getError()); + return null; } - return null; + LOGGER.info("Encrypting submission data ..."); + final String encryptedData = sender.encryptBytes(encryptionKey, sendableSubmission.getData().getBytes(StandardCharsets.UTF_8)); + + LOGGER.info("Encrypting metadata ..."); + final String encryptedMetadata = sender.encryptObject(encryptionKey, metadata); + + final var startTimeSubmissionUpload = StopWatch.start(); + final Submission submission = sender.sendSubmission(buildSubmitSubmission(announcedSubmissionId, encryptedData, encryptedMetadata)); + LOGGER.info("Uploading submission took {}", StopWatch.stopWithFormattedTime(startTimeSubmissionUpload)); + + LOGGER.info("SUCCESSFULLY HANDED IN SUBMISSION ! \n"); + final AuthenticationTags authenticationTags = buildAuthenticationTags(encryptedAttachments, encryptedData, encryptedMetadata); + return buildSentSubmission(authenticationTags, submission); + } - private Metadata buildMetadata(final SendableSubmission sendableSubmission, final Destination destination, final List<AttachmentPayload> encryptedAttachments) { + private Metadata buildMetadata(final SendableSubmission sendableSubmission, final List<AttachmentPayload> encryptedAttachments) { final String hashedData = sender.createHash(sendableSubmission.getData().getBytes(StandardCharsets.UTF_8)); final String dataMimeType = sendableSubmission.getDataMimeType(); - final URI schemaUri = getSubmissionSchemaFromDestination(destination, dataMimeType); final Data data = createData(dataMimeType, hashedData, sendableSubmission.getSchemaUri()); final List<ApiAttachment> attachmentMetadata = encryptedAttachments.stream().map(this::toHashedAttachment).collect(Collectors.toList()); @@ -138,13 +109,13 @@ public class SendNewSubmissionStrategy { } private void setOptionalProperties(final SendableSubmission sendableSubmission, final Metadata metadata) { - if(sendableSubmission.getAuthenticationInformation() != null){ + if (sendableSubmission.getAuthenticationInformation() != null) { metadata.setAuthenticationInformation(sendableSubmission.getAuthenticationInformation()); } - if(sendableSubmission.getReplyChannel() != null){ + if (sendableSubmission.getReplyChannel() != null) { metadata.setReplyChannel(sendableSubmission.getReplyChannel()); } - if(sendableSubmission.getPaymentInformation() != null){ + if (sendableSubmission.getPaymentInformation() != null) { metadata.setPaymentInformation(sendableSubmission.getPaymentInformation()); } } @@ -179,16 +150,6 @@ public class SendNewSubmissionStrategy { return attachment; } - private URI getSubmissionSchemaFromDestination(final Destination destination, final String mimeType) { - return destination.getServices().stream() - .map(DestinationService::getSubmissionSchemas) - .flatMap(Collection::stream) - .filter(schema -> schema.getMimeType().value().equals(mimeType)) - .map(SubmissionSchema::getSchemaUri) - .findFirst() - .orElseThrow(() -> new SchemaNotFoundException("Destination does not support data with mime-type " + mimeType)); - } - private void uploadAttachments(final List<AttachmentPayload> attachmentPayloads, final UUID submissionId) { if (attachmentPayloads.isEmpty()) { LOGGER.info("No attachments to upload"); @@ -206,19 +167,15 @@ public class SendNewSubmissionStrategy { } private AttachmentPayload encryptAndHashAttachment(final RSAKey encryptionKey, final Attachment attachment) { - try { - final String encryptedAttachment = sender.encryptBytes(encryptionKey, attachment.getDataAsBytes()); - final String hashedBytes = sender.createHash(attachment.getDataAsBytes()); - return AttachmentPayload.builder() - .attachmentId(UUID.randomUUID()) - .hashedData(hashedBytes) - .encryptedData(encryptedAttachment) - .mimeType(attachment.getMimeType()) - .fileName(attachment.getFileName()) - .description(attachment.getDescription()) - .build(); - } catch (final EncryptionException e) { - throw new AttachmentCreationException("Attachment '" + attachment.getFileName() + "' could not be encrypted ", e); - } + final String encryptedAttachment = sender.encryptBytes(encryptionKey, attachment.getDataAsBytes()); + final String hashedBytes = sender.createHash(attachment.getDataAsBytes()); + return AttachmentPayload.builder() + .attachmentId(UUID.randomUUID()) + .hashedData(hashedBytes) + .encryptedData(encryptedAttachment) + .mimeType(attachment.getMimeType()) + .fileName(attachment.getFileName()) + .description(attachment.getDescription()) + .build(); } } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/subscriber/ReceivedSubmission.java b/client/src/main/java/dev/fitko/fitconnect/client/subscriber/ReceivedSubmission.java index af264014b0c38f64960aba24113d38c44c09cf19..f89507bcb6b0df0463625f145dea625c7693040d 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/subscriber/ReceivedSubmission.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/subscriber/ReceivedSubmission.java @@ -5,6 +5,7 @@ import dev.fitko.fitconnect.api.domain.model.event.EventPayload; import dev.fitko.fitconnect.api.domain.model.event.problems.Problem; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; import dev.fitko.fitconnect.api.domain.model.submission.Submission; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSubscriberException; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.client.sender.model.Attachment; import dev.fitko.fitconnect.client.subscriber.model.ReceivedData; @@ -14,6 +15,8 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import static dev.fitko.fitconnect.api.domain.model.event.EventPayload.*; + public class ReceivedSubmission { private final transient Subscriber subscriber; @@ -40,7 +43,11 @@ public class ReceivedSubmission { * @see <a href="https://docs.fitko.de/fit-connect/docs/getting-started/event-log/events">FIT-Connect Events</a> */ public void acceptSubmission(final Problem... problems) { - subscriber.acceptSubmission(EventPayload.forAcceptEventWithAttachments(submission, encryptedAttachments, problems)); + try { + subscriber.acceptSubmission(getEventPayload(problems)); + } catch (final Exception e) { + throw new FitConnectSubscriberException("Accepting submission failed", e.getCause() != null ? e.getCause() : e); + } } /** @@ -50,7 +57,11 @@ public class ReceivedSubmission { * @see <a href="https://docs.fitko.de/fit-connect/docs/getting-started/event-log/events">FIT-Connect Events</a> */ public void rejectSubmission(final List<Problem> rejectionProblems) { - subscriber.rejectSubmission(EventPayload.forRejectEvent(submission, rejectionProblems)); + try { + subscriber.rejectSubmission(forRejectEvent(submission, rejectionProblems)); + } catch (final Exception e) { + throw new FitConnectSubscriberException("Rejecting submission failed", e.getCause() != null ? e.getCause() : e); + } } /** @@ -125,4 +136,8 @@ public class ReceivedSubmission { return submission.getSubmissionId(); } + private EventPayload getEventPayload(final Problem[] problems) { + return attachments.isEmpty() ? forAcceptEvent(submission, problems) : forAcceptEventWithAttachments(submission, encryptedAttachments, problems); + } + } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java b/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java index ab00bfff2f4e3c136ae98a771c5a07473b1a26bb..c86b38e662c1d8bfd24ce04d9aae83bb159600a1 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java @@ -22,12 +22,12 @@ import dev.fitko.fitconnect.api.domain.model.metadata.attachment.AttachmentForVa import dev.fitko.fitconnect.api.domain.model.metadata.data.MimeType; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.AuthenticationTagsEmptyException; -import dev.fitko.fitconnect.api.exceptions.DecryptionException; -import dev.fitko.fitconnect.api.exceptions.EventLogException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.SubmissionRequestException; -import dev.fitko.fitconnect.api.exceptions.SubmitEventNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.AuthenticationTagsEmptyException; +import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.SubmissionRequestException; +import dev.fitko.fitconnect.api.exceptions.internal.SubmitEventNotFoundException; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.client.sender.model.Attachment; import dev.fitko.fitconnect.client.subscriber.model.ReceivedData; @@ -245,7 +245,7 @@ public class SubmissionReceiver { } private void reject(final Submission submission, final List<Problem> problems) { - if (config.isEnableAutoReject()) { + if (config.isAutoRejectEnabled()) { subscriber.rejectSubmission(EventPayload.forRejectEvent(submission, problems)); } } 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 aabf37acdf8163927080dec66188026cb997aa7f..3f0bac9e7471edb68f392be3e3771570a76f8ec4 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 @@ -27,7 +27,6 @@ public class ValidDataGuard { * * @param sendableEncryptedSubmission payload to be checked * @throws IllegalArgumentException if one of the checks fails - * @throws IllegalStateException if the destination does not have a declared service type */ public void ensureValidDataPayload(final SendableEncryptedSubmission sendableEncryptedSubmission) { if (sendableEncryptedSubmission == null) { @@ -39,7 +38,7 @@ public class ValidDataGuard { if (sendableEncryptedSubmission.getMetadata() == null) { throw new IllegalArgumentException("Encrypted metadata must not be null."); } - testDefaults(sendableEncryptedSubmission.getDestinationId(), sendableEncryptedSubmission.getServiceName(), sendableEncryptedSubmission.getServiceIdentifier()); + testDefaults(sendableEncryptedSubmission.getDestinationId(), sendableEncryptedSubmission.getServiceIdentifier()); } /** @@ -59,7 +58,7 @@ public class ValidDataGuard { testDefaults(sendableSubmission); } - private void testDefaults(final UUID destinationId, final String serviceName, final String serviceIdentifier) { + private void testDefaults(final UUID destinationId, final String serviceIdentifier) { if (destinationId == null) { throw new IllegalArgumentException("DestinationId is mandatory, but was null."); } else if (serviceIdentifier == null) { @@ -68,14 +67,13 @@ public class ValidDataGuard { throw new IllegalArgumentException("LeikaKey has invalid format, please follow: ^urn:[a-z0-9][a-z0-9-]{0,31}:[a-z0-9()+,.:=@;$_!*'%/?#-]+$."); } - Destination destination = sender.getDestination(destinationId); + final Destination destination = sender.getDestination(destinationId); if (serviceTypeDoesNotMatchDestination(destination, serviceIdentifier)) { throw new IllegalArgumentException("Provided service type '" + serviceIdentifier + "' is not allowed by the destination "); } } private void testDefaults(final SendableSubmission sendableSubmission) { - if (sendableSubmission.getDestinationId() == null) { throw new IllegalArgumentException("DestinationId is mandatory, but was null."); } else if (sendableSubmission.getServiceIdentifier() == null) { @@ -84,7 +82,7 @@ public class ValidDataGuard { throw new IllegalArgumentException("LeikaKey has invalid format, please follow: ^urn:[a-z0-9][a-z0-9-]{0,31}:[a-z0-9()+,.:=@;$_!*'%/?#-]+$."); } - Destination destination = sender.getDestination(sendableSubmission.getDestinationId()); + final Destination destination = sender.getDestination(sendableSubmission.getDestinationId()); if (serviceTypeDoesNotMatchDestination(destination, sendableSubmission.getServiceIdentifier())) { throw new IllegalArgumentException("Provided service type '" + sendableSubmission.getServiceIdentifier() + "' is not allowed by the destination "); } diff --git a/client/src/test/java/dev/fitko/fitconnect/client/RoutingClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/RouterClientTest.java similarity index 90% rename from client/src/test/java/dev/fitko/fitconnect/client/RoutingClientTest.java rename to client/src/test/java/dev/fitko/fitconnect/client/RouterClientTest.java index a0ee2b95c8f06a868455ae56c7707f4917b4697a..bddbfdfb8281a39bb794b3645983b50af7fe1b30 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/RoutingClientTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/RouterClientTest.java @@ -5,7 +5,7 @@ import dev.fitko.fitconnect.api.domain.model.route.AreaResult; import dev.fitko.fitconnect.api.domain.model.route.Route; import dev.fitko.fitconnect.api.domain.model.route.RouteResult; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.RoutingException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectRouterException; import dev.fitko.fitconnect.api.services.routing.RoutingService; import dev.fitko.fitconnect.client.router.DestinationSearch; import dev.fitko.fitconnect.core.routing.RouteVerifier; @@ -25,19 +25,19 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -class RoutingClientTest { +class RouterClientTest { RoutingService routingServiceMock; RouteVerifier routeVerifierMock; - RoutingClient underTest; + RouterClient underTest; @BeforeEach void setup() { routingServiceMock = mock(RoutingService.class); routeVerifierMock = mock(RouteVerifier.class); - underTest = new RoutingClient(routingServiceMock, routeVerifierMock); + underTest = new RouterClient(routingServiceMock, routeVerifierMock); } @Test @@ -82,7 +82,7 @@ class RoutingClientTest { expectedRouteResult.setRoutes(List.of(expectedRoute)); when(routingServiceMock.getRoutes(any(), any(), any(), any(), anyInt(), anyInt())).thenReturn(expectedRouteResult); - when(routeVerifierMock.validateRouteDestinations(any(), any(), any())).thenReturn(ValidationResult.error(new RoutingException("Route validation failed"))); + when(routeVerifierMock.validateRouteDestinations(any(), any(), any())).thenReturn(ValidationResult.error(new FitConnectRouterException("Route validation failed", new Exception()))); final DestinationSearch search = DestinationSearch.Builder() .withLeikaKey("99400048079000") @@ -91,7 +91,7 @@ class RoutingClientTest { .build(); // When - final RoutingException exception = assertThrows(RoutingException.class, () -> underTest.findDestinations(search)); + final FitConnectRouterException exception = assertThrows(FitConnectRouterException.class, () -> underTest.findDestinations(search)); // Then assertThat(exception.getMessage(), containsString("Route validation failed")); 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 e3b9095a362e63ad288a3d7702b19389f223e064..b468f8731a5dfb038a4f9c2d39f937ffaf931441 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java @@ -17,12 +17,10 @@ import dev.fitko.fitconnect.api.domain.model.submission.SentSubmission; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.AttachmentCreationException; -import dev.fitko.fitconnect.api.exceptions.EncryptionException; -import dev.fitko.fitconnect.api.exceptions.KeyNotRetrievedException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.SubmissionNotCreatedException; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSenderException; +import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.client.sender.model.Attachment; import dev.fitko.fitconnect.client.sender.model.SendableEncryptedSubmission; @@ -213,10 +211,11 @@ public class SenderClientTest { .setJsonData("{}", URI.create("https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json")) .build(); - final var exception = assertThrows(IllegalArgumentException.class, () -> senderClient.send(submission)); + final var exception = assertThrows(FitConnectSenderException.class, () -> senderClient.send(submission)); // Then - assertThat(exception.getMessage(), equalTo("Combination of provided MIME type 'application/json' and schema URI " + + assertThat(exception.getMessage(), equalTo("Sending submission failed.")); + assertThat(exception.getCause().getMessage(), equalTo("Combination of provided MIME type 'application/json' and schema URI " + "'https://schema.fitko.de/fim/s00000000009_1.0.0.schema.json' is not allowed by the destination")); } @@ -265,7 +264,7 @@ public class SenderClientTest { final var path = Path.of("/non/existing/path"); // When - final AttachmentCreationException exception = assertThrows(AttachmentCreationException.class, () -> Attachment.fromPath(path, "plain/text")); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> Attachment.fromPath(path, "plain/text")); // Then assertThat(exception.getMessage(), containsString("Reading attachment from path '" + path + "' failed")); @@ -283,7 +282,7 @@ public class SenderClientTest { }; // When - final AttachmentCreationException exception = assertThrows(AttachmentCreationException.class, () -> Attachment.fromInputStream(inputStream, "plain/text", "non-existing-file", "test")); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> Attachment.fromInputStream(inputStream, "plain/text", "non-existing-file", "test")); // Then assertThat(exception.getMessage(), containsString("Attachment could not be read from input-stream")); @@ -302,18 +301,18 @@ public class SenderClientTest { .build(); // When - final var sentSubmission = senderClient.send(submission); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> senderClient.send(submission)); // Then - assertNull(sentSubmission); - logs.assertContains("Encrypting submission failed"); + assertThat(exception.getMessage(), containsString("Sending submission failed")); + assertThat(exception.getCause().getMessage(), containsString("Encryption failed")); } @Test void testAnnouncingSubmissionFailed() { // Given - when(senderMock.createSubmission(any())).thenThrow(new SubmissionNotCreatedException("Announcing submission failed")); + when(senderMock.createSubmission(any())).thenThrow(new RestApiException("Announcing submission failed")); final var submission = SendableSubmission.Builder() .setDestination(destinationId) @@ -322,11 +321,11 @@ public class SenderClientTest { .build(); // When - final var sentSubmission = senderClient.send(submission); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> senderClient.send(submission)); // Then - assertNull(sentSubmission); - logs.assertContains("Failed to announce new submission"); + assertThat(exception.getMessage(), containsString("Sending submission failed")); + assertThat(exception.getCause().getMessage(), containsString("Announcing submission failed")); } @@ -343,11 +342,11 @@ public class SenderClientTest { .build(); // When - final var sentSubmission = senderClient.send(submission); - - assertNull(sentSubmission); - logs.assertContains("Sending submission failed"); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> senderClient.send(submission)); + // Then + assertThat(exception.getMessage(), containsString("Sending submission failed")); + assertThat(exception.getCause().getMessage(), containsString("Announcing submission failed")); } @Test @@ -355,7 +354,7 @@ public class SenderClientTest { // Given - when(senderMock.getEncryptionKeyForDestination(any())).thenThrow(new KeyNotRetrievedException("Getting encryption key failed")); + when(senderMock.getEncryptionKeyForDestination(any())).thenThrow(new RestApiException("Getting encryption key failed")); // When final SendableSubmission submission = SendableSubmission.Builder() @@ -364,10 +363,13 @@ public class SenderClientTest { .setJsonData("{}", URI.create("https://mimetype.test.de")) .build(); - final var sentSubmission = senderClient.send(submission); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> senderClient.send(submission)); - assertNull(sentSubmission); - logs.assertContains("Getting encryption key for destination " + destinationId + " failed"); + //Then + assertThat(exception.getMessage(), containsString("Sending submission failed")); + assertThat(exception.getCause().getMessage(), containsString("Getting encryption key failed")); + + //logs.assertContains("Getting encryption key for destination " + destinationId + " failed"); } @Test diff --git a/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java index ad116a730dcf6f1544427d56595f02b976bf1eb5..5a0eaf56155f44116b057cc0d0adc4bd2656acf8 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.config.ApplicationConfig; +import dev.fitko.fitconnect.api.config.Environment; +import dev.fitko.fitconnect.api.config.EnvironmentName; import dev.fitko.fitconnect.api.domain.model.event.Event; import dev.fitko.fitconnect.api.domain.model.event.EventPayload; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; @@ -28,13 +30,13 @@ import dev.fitko.fitconnect.api.domain.model.metadata.data.SubmissionSchema; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.AuthenticationTagsEmptyException; -import dev.fitko.fitconnect.api.exceptions.DecryptionException; -import dev.fitko.fitconnect.api.exceptions.EventLogException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.SubmissionRequestException; -import dev.fitko.fitconnect.api.exceptions.SubmitEventNotFoundException; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.AuthenticationTagsEmptyException; +import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSubscriberException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.SubmitEventNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.client.subscriber.SubmissionReceiver; @@ -82,7 +84,12 @@ class SubscriberClientTest { @BeforeEach public void setup() throws IOException, ParseException { - final ApplicationConfig config = new ApplicationConfig(); + final EnvironmentName environmentName = new EnvironmentName("TESTING"); + final ApplicationConfig config = ApplicationConfig.builder() + .environments(Map.of(environmentName, new Environment())) + .activeEnvironment(environmentName) + .build(); + privateKey = RSAKey.parse(getResourceAsString("private_decryption_test_key.json")); subscriberMock = Mockito.mock(Subscriber.class); underTest = new SubscriberClient(subscriberMock, new SubmissionReceiver(subscriberMock, privateKey, config)); @@ -104,10 +111,11 @@ class SubscriberClientTest { when(subscriberMock.getSubmission(any())).thenThrow(new RestApiException("Submission not found")); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(UUID.randomUUID())); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(UUID.randomUUID())); // Then - assertThat(exception.getMessage(), containsString("Submission not found")); + assertThat(exception.getMessage(), containsString("Submission could not be retrieved")); + assertThat(exception.getCause().getMessage(), containsString("Submission not found")); } @Test @@ -129,10 +137,10 @@ class SubscriberClientTest { when(subscriberMock.decryptStringContent(any(), any())).thenThrow(new DecryptionException("Decryption failed")); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Decryption failed")); + assertThat(exception.getCause().getMessage(), containsString("Decryption failed")); } @Test @@ -250,10 +258,10 @@ class SubscriberClientTest { when(subscriberMock.decryptStringContent(any(), any())).thenReturn("encryptedMetadata".getBytes()); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Unrecognized token 'encryptedMetadata'")); + assertThat(exception.getCause().getMessage(), containsString("Unrecognized token 'encryptedMetadata'")); } @Test @@ -345,10 +353,10 @@ class SubscriberClientTest { when(subscriberMock.getSubmission(any())).thenThrow(new RestApiException("Submission not found")); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(UUID.randomUUID())); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(UUID.randomUUID())); // Then - assertThat(exception.getMessage(), containsString("Submission not found")); + assertThat(exception.getMessage(), containsString("Submission could not be retrieved")); } @Test @@ -378,10 +386,10 @@ class SubscriberClientTest { when(subscriberMock.validateMetadata(any(), any(), any())).thenReturn(ValidationResult.problem(problem)); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Metadata is invalid")); + assertThat(exception.getCause().getMessage(), containsString("Metadata is invalid")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(problem))); } @@ -545,10 +553,10 @@ class SubscriberClientTest { when(subscriberMock.getAuthenticationTagsForEvent(any(), any())).thenReturn(authenticationTags); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Data is invalid")); + assertThat(exception.getCause().getMessage(), containsString("Data is invalid")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(problem))); } @@ -602,10 +610,10 @@ class SubscriberClientTest { when(subscriberMock.validateData(any(), any(), any(), any())).thenReturn(ValidationResult.problem(problem)); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Data is invalid")); + assertThat(exception.getCause().getMessage(), containsString("Data is invalid")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(problem))); } @@ -671,10 +679,10 @@ class SubscriberClientTest { when(subscriberMock.validateAttachments(anyList(), any())).thenReturn(ValidationResult.problem(problem)); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Attachment validation failed")); + assertThat(exception.getCause().getMessage(), containsString("Attachment validation failed")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(problem))); } @@ -734,10 +742,10 @@ class SubscriberClientTest { when(subscriberMock.fetchAttachment(any(), any())).thenThrow(new RestApiException("Attachment download failed", 404)); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Attachment download failed")); + assertThat(exception.getCause().getMessage(), containsString("Attachment download failed")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(new MissingAttachment(attachment.getAttachmentId())))); } @@ -798,10 +806,10 @@ class SubscriberClientTest { when(subscriberMock.fetchAttachment(any(), any())).thenReturn("encrypt$dAtt@chm$nt"); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submissionId)); // Then - assertThat(exception.getMessage(), containsString("Decrypting attachment failed")); + assertThat(exception.getCause().getMessage(), containsString("Decrypting attachment failed")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(new AttachmentEncryptionIssue(attachment.getAttachmentId())))); } @@ -818,10 +826,10 @@ class SubscriberClientTest { when(subscriberMock.getAuthenticationTagsForEvent(Event.SUBMIT, submission)).thenThrow(new SubmitEventNotFoundException("no submit event in log")); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submission.getSubmissionId())); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submission.getSubmissionId())); // Then - assertThat(exception.getMessage(), containsString("The Event-Log is inconsistent because it does not contain exactly one 'submit' event.")); + assertThat(exception.getCause().getMessage(), containsString("The Event-Log is inconsistent because it does not contain exactly one 'submit' event.")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(expectedProblem))); } @@ -838,10 +846,10 @@ class SubscriberClientTest { when(subscriberMock.getAuthenticationTagsForEvent(Event.SUBMIT, submission)).thenThrow(new AuthenticationTagsEmptyException("empty auth tags")); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submission.getSubmissionId())); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submission.getSubmissionId())); // Then - assertThat(exception.getMessage(), containsString("The 'submit-submission' event does not contain authentication tags")); + assertThat(exception.getCause().getMessage(), containsString("The 'submit-submission' event does not contain authentication tags")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(expectedProblem))); } @@ -855,13 +863,13 @@ class SubscriberClientTest { final InvalidEventLog expectedProblem = new InvalidEventLog(); when(subscriberMock.getSubmission(submission.getSubmissionId())).thenReturn(submission); - when(subscriberMock.getAuthenticationTagsForEvent(Event.SUBMIT, submission)).thenThrow(new EventLogException("Invalid log")); + when(subscriberMock.getAuthenticationTagsForEvent(Event.SUBMIT, submission)).thenThrow(new EventLogException("The Event-Log is inconsistent")); // When - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submission.getSubmissionId())); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> underTest.requestSubmission(submission.getSubmissionId())); // Then - assertThat(exception.getMessage(), containsString("The Event-Log is inconsistent")); + assertThat(exception.getCause().getMessage(), containsString("The Event-Log is inconsistent")); verify(subscriberMock, times(1)).rejectSubmission(EventPayload.forRejectEvent(submission, List.of(expectedProblem))); } diff --git a/client/src/test/java/dev/fitko/fitconnect/client/bootstrap/ApplicationConfigLoaderTest.java b/client/src/test/java/dev/fitko/fitconnect/client/bootstrap/ApplicationConfigLoaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bb2aa55d803d387ccf086e4387fa8aa125796c0f --- /dev/null +++ b/client/src/test/java/dev/fitko/fitconnect/client/bootstrap/ApplicationConfigLoaderTest.java @@ -0,0 +1,190 @@ +package dev.fitko.fitconnect.client.bootstrap; + +import dev.fitko.fitconnect.api.config.ApplicationConfig; +import dev.fitko.fitconnect.api.config.Environment; +import dev.fitko.fitconnect.api.config.EnvironmentName; +import dev.fitko.fitconnect.api.config.SenderConfig; +import dev.fitko.fitconnect.api.config.defaults.DefaultEnvironments; +import dev.fitko.fitconnect.api.config.defaults.ResourcePaths; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static dev.fitko.fitconnect.api.config.defaults.DefaultEnvironments.PROD; +import static dev.fitko.fitconnect.api.config.defaults.DefaultEnvironments.STAGE; +import static dev.fitko.fitconnect.api.config.defaults.DefaultEnvironments.TEST; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ApplicationConfigLoaderTest { + + @Test + void testLoadMissingConfigFile() { + Assertions.assertThrows(FitConnectInitialisationException.class, () -> ApplicationConfigLoader.loadConfigFromPath(Path.of("/no/path"))); + } + + @Test + void testEnvironmentNotAvailable() throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config-with-missing-env.yml"); + final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromYamlString(testConfigYaml); + + //When + final FitConnectInitialisationException exception = Assertions.assertThrowsExactly(FitConnectInitialisationException.class, config::getCurrentEnvironment); + + //Then + assertThat(exception.getMessage(), containsString("No environment with name 'ENVIRONMENT_THAT_DOES_NOT_EXIST' found")); + } + + @Test + void testLoadTestConfigFromString() throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config.yml"); + + final Environment devEnv = new Environment( + "https://auth-testing.fit-connect.fitko.dev", + "https://routing-api-testing.fit-connect.fitko.dev", + List.of("https://submission-api-testing.fit-connect.fitko.dev"), + "https://portal.auth-testing.fit-connect.fitko.dev", + true, + false, + false + ); + + final SenderConfig senderConfig = new SenderConfig("1", "123"); + + // When + final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfigFromYamlString(testConfigYaml); + + // Then + assertNotNull(testConfig); + assertThat(testConfig.getCurrentEnvironment(), equalTo(devEnv)); + assertThat(testConfig.getSenderConfig(), equalTo(senderConfig)); + } + + @Test + void testLoadTestConfigFromPath(@TempDir final Path tempDir) throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config.yml"); + + final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config.yml"), testConfigYaml); + + // When + final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfigFromPath(configPath); + + // Then + assertNotNull(testConfig); + assertThat(testConfig.getActiveEnvironment(), is(new EnvironmentName("TEST"))); + } + + @Test + void testSubscriberConfigContainsListOfPrivateDecryptionKeys(@TempDir final Path tempDir) throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config.yml"); + final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config.yml"), testConfigYaml); + + // When + final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfigFromPath(configPath); + + // Then + assertNotNull(testConfig); + assertThat(testConfig.getSubscriberConfig().getPrivateDecryptionKeyPaths(), hasSize(2)); + } + + @Test + void testUseDefaultEnvironment(@TempDir final Path tempDir) throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config-default.yml"); + final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config-default.yml"), testConfigYaml); + + // When + final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromPath(configPath); + + // Then + assertEquals(DefaultEnvironments.getEnvironmentsAsMap().size(), config.getEnvironments().size()); + + assertThat(config.getEnvironments().get(PROD.getEnvironmentName()), is(PROD.getEnvironment())); + assertThat(config.getEnvironments().get(STAGE.getEnvironmentName()), is(STAGE.getEnvironment())); + assertThat(config.getEnvironments().get(TEST.getEnvironmentName()), is(TEST.getEnvironment())); + + } + + @Test + void testOverridePropertiesOnDefaultEnvironment(@TempDir final Path tempDir) throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config.yml"); + final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config.yml"), testConfigYaml); + + assertTrue(TEST.getEnvironment().getAllowInsecurePublicKey()); + + // When + final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromPath(configPath); + final Environment envWithChangedDefaults = config.getEnvironments().get(TEST.getEnvironmentName()); + + // Then + assertFalse(envWithChangedDefaults.getAllowInsecurePublicKey()); + } + + @Test + void testLoadingAdditionalCustomEnvironment(@TempDir final Path tempDir) throws IOException { + + // Given + final String testConfigYaml = getResourceAsString("test-config-with-custom-env.yml"); + final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config-with-custom-env.yml"), testConfigYaml); + + final Environment customEnvironment = new Environment(); + customEnvironment.setEnableAutoReject(true); + customEnvironment.setAllowInsecurePublicKey(false); + customEnvironment.setSkipSubmissionDataValidation(false); + customEnvironment.setAuthBaseUrl("https://auth-url.test.net"); + customEnvironment.setRoutingBaseUrl("https://routing-url.test.net"); + customEnvironment.setSubmissionBaseUrls(List.of("https://submission-url-1.test.net", "https://submission-url-2.test.net")); + customEnvironment.setSelfServicePortalBaseUrl("https://portal-url.test.net"); + + // When + final ApplicationConfig configWithCustomEnvironment = ApplicationConfigLoader.loadConfigFromPath(configPath); + + // Then + assertNotNull(configWithCustomEnvironment); + + final Map<EnvironmentName, Environment> environments = configWithCustomEnvironment.getEnvironments(); + + assertThat(environments.size(), is(DefaultEnvironments.getEnvironmentsAsMap().size() + 1)); + assertThat(environments.get(new EnvironmentName("CUSTOM_ENVIRONMENT")), is(customEnvironment)); + + // currently there is only one url supported + assertThat(configWithCustomEnvironment.getSubmissionEndpoint(), is("https://submission-url-1.test.net" + ResourcePaths.SUBMISSION_PATH)); + + assertThat(environments.get(PROD.getEnvironmentName()), is(PROD.getEnvironment())); + assertThat(environments.get(STAGE.getEnvironmentName()), is(STAGE.getEnvironment())); + assertThat(environments.get(TEST.getEnvironmentName()), is(TEST.getEnvironment())); + } + + private String getResourceAsString(final String name) throws IOException { + final ClassLoader classLoader = getClass().getClassLoader(); + final File file = new File(Objects.requireNonNull(classLoader.getResource(name)).getFile()); + return Files.readString(file.toPath()); + } +} \ No newline at end of file diff --git a/client/src/test/java/dev/fitko/fitconnect/client/factory/ClientFactoryTest.java b/client/src/test/java/dev/fitko/fitconnect/client/bootstrap/ClientFactoryTest.java similarity index 79% rename from client/src/test/java/dev/fitko/fitconnect/client/factory/ClientFactoryTest.java rename to client/src/test/java/dev/fitko/fitconnect/client/bootstrap/ClientFactoryTest.java index 3967ac3ef8365520fdddee7ac4379d046f7c808b..252ee3444ad1ae4c0cb02216cbf3a4b51b12f729 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/factory/ClientFactoryTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/bootstrap/ClientFactoryTest.java @@ -1,8 +1,11 @@ -package dev.fitko.fitconnect.client.factory; - -import dev.fitko.fitconnect.api.config.*; -import dev.fitko.fitconnect.api.exceptions.InitializationException; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; +package dev.fitko.fitconnect.client.bootstrap; + +import dev.fitko.fitconnect.api.config.ApplicationConfig; +import dev.fitko.fitconnect.api.config.Environment; +import dev.fitko.fitconnect.api.config.EnvironmentName; +import dev.fitko.fitconnect.api.config.SenderConfig; +import dev.fitko.fitconnect.api.config.SubscriberConfig; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; import org.junit.jupiter.api.Test; import java.util.List; @@ -17,16 +20,16 @@ class ClientFactoryTest { @Test void testMissingConfiguration() { - assertThrows(InitializationException.class, () -> ClientFactory.getSenderClient(null)); - assertThrows(InitializationException.class, () -> ClientFactory.getSubscriberClient(null)); - assertThrows(InitializationException.class, () -> ClientFactory.getRoutingClient(null)); + assertThrows(FitConnectInitialisationException.class, () -> ClientFactory.getSenderClient(null)); + assertThrows(FitConnectInitialisationException.class, () -> ClientFactory.getSubscriberClient(null)); + assertThrows(FitConnectInitialisationException.class, () -> ClientFactory.getRouterClient(null)); } @Test void testSenderClientConstruction() { final var envName = new EnvironmentName("DEV"); - final var environments = Map.of(envName, new Environment("https://auth", "", "", "", true, false)); + final var environments = Map.of(envName, new Environment("https://auth", "", List.of(), "", true, false, false)); final var sender = new SenderConfig("123", "abc"); @@ -45,7 +48,7 @@ class ClientFactoryTest { void testSubscriberClientConstruction() { final var envName = new EnvironmentName("DEV"); - final var environments = Map.of(envName, new Environment("https://auth", "", "", "", true, false)); + final var environments = Map.of(envName, new Environment("https://auth", "", List.of(), "", true, false, false)); final var subscriber = SubscriberConfig.builder() .clientSecret("123") @@ -66,10 +69,10 @@ class ClientFactoryTest { } @Test - void testRoutingClientConstruction() { + void testRouterClientConstruction() { final var envName = new EnvironmentName("DEV"); - final var environment = new Environment("", "https://routing.fitko.fitconnect.de", "", "", true, false); + final var environment = new Environment("", "https://routing.fitko.fitconnect.de", List.of(), "", true, false, false); final var senderConfig = new SenderConfig("1234", "abcd"); @@ -79,14 +82,14 @@ class ClientFactoryTest { .senderConfig(senderConfig) .build(); - assertNotNull(ClientFactory.getRoutingClient(routingConfig)); + assertNotNull(ClientFactory.getRouterClient(routingConfig)); } @Test void testSigningKeyCannotBeParsed() { final var envName = new EnvironmentName("DEV"); - final var environments = Map.of(envName, new Environment("https://auth", "", "", "", true, false)); + final var environments = Map.of(envName, new Environment("https://auth", "", List.of(), "", true, false, false)); final var subscriberConfig = SubscriberConfig.builder() .clientSecret("123") @@ -104,7 +107,7 @@ class ClientFactoryTest { .build(); assertThrows( - InvalidKeyException.class, + FitConnectInitialisationException.class, () -> ClientFactory.getSubscriberClient(config), "Expected new ClientFactoryTest() to throw, but nothing was thrown" ); @@ -114,7 +117,7 @@ class ClientFactoryTest { void testDecryptionKeyCannotBeParsed() { final var envName = new EnvironmentName("DEV"); - final var environments = Map.of(envName, new Environment("https://auth", "", "", "", true, false)); + final var environments = Map.of(envName, new Environment("https://auth", "", List.of(), "", true, false, false)); final var subscriberConfigWithoutKey = SubscriberConfig.builder() .clientSecret("123") @@ -132,7 +135,7 @@ class ClientFactoryTest { .build(); assertThrows( - InvalidKeyException.class, + FitConnectInitialisationException.class, () -> ClientFactory.getSubscriberClient(config)); } @@ -140,7 +143,7 @@ class ClientFactoryTest { void testMultipleDecryptionKeysNotYetSupported() { final var envName = new EnvironmentName("DEV"); - final var environments = Map.of(envName, new Environment("https://auth", "", "", "", true, false)); + final var environments = Map.of(envName, new Environment("https://auth", "", List.of(), "", true, false, false)); final var subscriberConfigWithoutKey = SubscriberConfig.builder() .clientSecret("123") @@ -157,8 +160,8 @@ class ClientFactoryTest { .activeEnvironment(envName) .build(); - final InitializationException exception = assertThrows( - InitializationException.class, + final FitConnectInitialisationException exception = assertThrows( + FitConnectInitialisationException.class, () -> ClientFactory.getSubscriberClient(config)); assertThat(exception.getMessage(), containsString("Currently only one configured private key per subscriber is allowed !")); diff --git a/client/src/test/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java b/client/src/test/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java index a0b7d85cd63165022f11a567039a1e2b91430432..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java @@ -1,108 +0,0 @@ -package dev.fitko.fitconnect.client.factory; - -import dev.fitko.fitconnect.api.config.ApplicationConfig; -import dev.fitko.fitconnect.api.config.Environment; -import dev.fitko.fitconnect.api.config.EnvironmentName; -import dev.fitko.fitconnect.api.config.SenderConfig; -import dev.fitko.fitconnect.api.exceptions.InitializationException; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -class ApplicationConfigLoaderTest { - - @Test - void testLoadMissingConfigFile() { - Assertions.assertThrows(InitializationException.class, () -> ApplicationConfigLoader.loadConfigFromPath(Path.of("/no/path"))); - } - - @Test - void testEnvironmentNotAvailable() throws IOException { - - // Given - final String testConfigYaml = getResourceAsString("test-config-with-missing-env.yml"); - final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromYamlString(testConfigYaml); - - //When - final InitializationException exception = Assertions.assertThrowsExactly(InitializationException.class, config::getCurrentEnvironment); - - //Then - assertThat(exception.getMessage(), containsString("Available environments are: prod | dev | testing")); - } - - @Test - void testLoadTestConfigFromString() throws IOException { - - // Given - final String testConfigYaml = getResourceAsString("test-config.yml"); - - final Environment devEnv = new Environment( - "https://auth-testing.fit-connect.fitko.dev", - "https://routing-api-testing.fit-connect.fitko.dev", - "https://submission-api-testing.fit-connect.fitko.dev", - "https://portal.auth-testing.fit-connect.fitko.dev", - true, - false - ); - - final SenderConfig senderConfig = new SenderConfig("1", "123"); - - // When - final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfigFromYamlString(testConfigYaml); - - // Then - assertNotNull(testConfig); - assertThat(testConfig.getCurrentEnvironment(), equalTo(devEnv)); - assertThat(testConfig.getSenderConfig(), equalTo(senderConfig)); - } - - @Test - void testLoadTestConfigFromPath(@TempDir final Path tempDir) throws IOException { - - // Given - final String testConfigYaml = getResourceAsString("test-config.yml"); - - final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config.yml"), testConfigYaml); - - // When - final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfigFromPath(configPath); - - // Then - assertNotNull(testConfig); - assertThat(testConfig.getActiveEnvironment(), is(new EnvironmentName("dev"))); - } - - @Test - void testSubscriberConfigContainsListOfPrivateDecryptionKeys(@TempDir final Path tempDir) throws IOException { - - // Given - final String testConfigYaml = getResourceAsString("test-config.yml"); - final Path configPath = Files.writeString(Path.of(tempDir.toString(), "test-config.yml"), testConfigYaml); - - // When - final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfigFromPath(configPath); - - // Then - assertNotNull(testConfig); - assertThat(testConfig.getSubscriberConfig().getPrivateDecryptionKeyPaths(), hasSize(2)); - } - - private String getResourceAsString(final String name) throws IOException { - final ClassLoader classLoader = getClass().getClassLoader(); - final File file = new File(Objects.requireNonNull(classLoader.getResource(name)).getFile()); - return Files.readString(file.toPath()); - } -} \ No newline at end of file diff --git a/client/src/test/resources/test-config-default.yml b/client/src/test/resources/test-config-default.yml new file mode 100644 index 0000000000000000000000000000000000000000..de05efbab54374e95e750ee802b44da3f13a4960 --- /dev/null +++ b/client/src/test/resources/test-config-default.yml @@ -0,0 +1,12 @@ +senderConfig: + clientId: "1" + clientSecret: "123" + +subscriberConfig: + clientId: "2" + clientSecret: "456" + privateDecryptionKeyPaths: ["client/src/test/java/resources/private_decryption_test_key.json", "path/to/fake_key.json"] + privateSigningKeyPath: "client/src/test/java/resources/private_test_signing_key.json" + +activeEnvironment: PROD + diff --git a/client/src/test/resources/test-config-with-custom-env.yml b/client/src/test/resources/test-config-with-custom-env.yml new file mode 100644 index 0000000000000000000000000000000000000000..22ff56d499758d14dd0354b8434b5c08c4bb3a0c --- /dev/null +++ b/client/src/test/resources/test-config-with-custom-env.yml @@ -0,0 +1,21 @@ +senderConfig: + clientId: "1" + clientSecret: "123" + +subscriberConfig: + clientId: "2" + clientSecret: "456" + privateDecryptionKeyPaths: ["client/src/test/java/resources/private_decryption_test_key.json", "path/to/fake_key.json"] + privateSigningKeyPath: "client/src/test/java/resources/private_test_signing_key.json" + +activeEnvironment: CUSTOM_ENVIRONMENT + +environments: + CUSTOM_ENVIRONMENT: + authBaseUrl: "https://auth-url.test.net" + routingBaseUrl: "https://routing-url.test.net" + submissionBaseUrls: ["https://submission-url-1.test.net", "https://submission-url-2.test.net"] + selfServicePortalBaseUrl: "https://portal-url.test.net" + enableAutoReject: true + allowInsecurePublicKey: false + skipSubmissionDataValidation: false diff --git a/client/src/test/resources/test-config-with-missing-env.yml b/client/src/test/resources/test-config-with-missing-env.yml index 06f2c02522a284e94c724ff1694861291ca7ba93..5e7814b8783170883993255e1158253a4f55928d 100644 --- a/client/src/test/resources/test-config-with-missing-env.yml +++ b/client/src/test/resources/test-config-with-missing-env.yml @@ -8,24 +8,5 @@ subscriberConfig: privateDecryptionKeyPaths: ["client/src/test/java/resources/private_decryption_test_key.json"] privateSigningKeyPath: "client/src/test/java/resources/private_test_signing_key.json" -activeEnvironment: environment_that_does_not_exist +activeEnvironment: ENVIRONMENT_THAT_DOES_NOT_EXIST -environments: - prod: - authBaseUrl: "https://auth-prod.fit-connect.fitko.net" - routingBaseUrl: "https://routing-api-prod.fit-connect.fitko.net" - submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.net" - selfServicePortalBaseUrl: "https://portal.auth-prod.fit-connect.fitko.net" - allowInsecurePublicKey: false - dev: - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" - routingBaseUrl: "https://routing-api-testing.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - selfServicePortalBaseUrl: "https://portal.auth-testing.fit-connect.fitko.dev" - allowInsecurePublicKey: true - testing: - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" - routingBaseUrl: "https://routing-api-testing.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - selfServicePortalBaseUrl: "https://portal.auth-testing.fit-connect.fitko.dev" - allowInsecurePublicKey: true diff --git a/client/src/test/resources/test-config.yml b/client/src/test/resources/test-config.yml index bc70ce10c52fb51944035eaa38431eeb3452ca57..f4417751d33707da24cb87ee3658ac88e95317ea 100644 --- a/client/src/test/resources/test-config.yml +++ b/client/src/test/resources/test-config.yml @@ -8,24 +8,16 @@ subscriberConfig: privateDecryptionKeyPaths: ["client/src/test/java/resources/private_decryption_test_key.json", "path/to/fake_key.json"] privateSigningKeyPath: "client/src/test/java/resources/private_test_signing_key.json" -activeEnvironment: dev +activeEnvironment: TEST environments: - prod: - authBaseUrl: "https://auth-prod.fit-connect.fitko.net" - routingBaseUrl: "https://routing-api-prod.fit-connect.fitko.net" - submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.net" - selfServicePortalBaseUrl: "https://portal.auth-prod.fit-connect.fitko.net" + PROD: + enableAutoReject: true allowInsecurePublicKey: false - dev: - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" - routingBaseUrl: "https://routing-api-testing.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - selfServicePortalBaseUrl: "https://portal.auth-testing.fit-connect.fitko.dev" - allowInsecurePublicKey: true - testing: - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" - routingBaseUrl: "https://routing-api-testing.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - selfServicePortalBaseUrl: "https://portal.auth-testing.fit-connect.fitko.dev" - allowInsecurePublicKey: true \ No newline at end of file + STAGE: + enableAutoReject: true + allowInsecurePublicKey: false + TEST: + enableAutoReject: true + allowInsecurePublicKey: false + skipSubmissionDataValidation: false diff --git a/config.yml b/config.yml index d2234eb6196472ab65a9ceb37f0a55b502e11926..f237f70ac74420c0165eceb3b678ee04034c0f65 100644 --- a/config.yml +++ b/config.yml @@ -29,32 +29,35 @@ subscriberConfig: privateSigningKeyPath: "path/to/signing_key.json" # Name of the used environment (from environments config below). -# In this case the options are prod | testing -activeEnvironment: testing +# In this case the options are PROD | STAGE | TEST +activeEnvironment: TEST -# Configured environments that can be added in the form: +# environments config +environments: + PROD: + enableAutoReject: true + allowInsecurePublicKey: false + skipSubmissionDataValidation: false + TEST: + enableAutoReject: true + allowInsecurePublicKey: true + skipSubmissionDataValidation: false + +# Custom environments can be added in the form: # # name: -- identifier that can be referenced in 'activeEnvironment' + # authBaseUrl: "URL" -- base URL for OAuth requests # routingBaseUrl: "URL" -- base URL for routing and area search requests # submissionBaseUrl: "URL" -- base URL for submission/destination requests -# allowInsecurePublicKey: true | false -- allow public keys that failed a validation for e.g. testing purposes +# selfServicePortalBaseUrl: "URL" -- base URL for portal/public key requests + +# enableAutoReject: true | false -- automatically reject submission on receive if a validation failed +# allowInsecurePublicKey: true | false -- allow insecure public keys that failed a validation for e.g. testing purposes +# skipSubmissionDataValidation: true | false -- allow data validation against a given schema to be switched on/off # # also see: https://docs.fitko.de/fit-connect/docs/apis/submission-api -environments: - prod: - authBaseUrl: "https://auth-prod.fit-connect.fitko.net" - routingBaseUrl: "https://routing-api-prod.fit-connect.fitko.net" - submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.net" - selfServicePortalBaseUrl: "https://portal.auth-prod.fit-connect.fitko.net" - allowInsecurePublicKey: false - testing: - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" - routingBaseUrl: "https://routing-api-testing.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - selfServicePortalBaseUrl: "https://portal.auth-testing.fit-connect.fitko.dev" - allowInsecurePublicKey: true ##################################################################### # OPTIONAL SETTINGS # 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 b21ceb2876e08a01226566d6c522f801dd5dff13..611403975a434798d7bc409cce130ffae6566151 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java @@ -11,6 +11,10 @@ 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.exceptions.internal.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.InvalidKeyException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.api.services.events.EventLogService; @@ -61,12 +65,12 @@ public class SubmissionSender implements Sender { } @Override - public String encryptBytes(final RSAKey publicKey, final byte[] data) { + public String encryptBytes(final RSAKey publicKey, final byte[] data) throws EncryptionException { return cryptoService.encryptBytes(publicKey, data); } @Override - public String encryptObject(final RSAKey encryptionKey, final Object obj) { + public String encryptObject(final RSAKey encryptionKey, final Object obj) throws EncryptionException { return cryptoService.encryptObject(encryptionKey, obj); } @@ -77,31 +81,31 @@ public class SubmissionSender implements Sender { } @Override - public SubmissionForPickup createSubmission(final CreateSubmission submission) { + public SubmissionForPickup createSubmission(final CreateSubmission submission) throws RestApiException { LOGGER.info("Announcing new submission for destination {}", submission.getDestinationId()); return submissionService.announceSubmission(submission); } @Override - public void uploadAttachment(final UUID submissionId, final UUID attachmentId, final String encryptedAttachment) { + public void uploadAttachment(final UUID submissionId, final UUID attachmentId, final String encryptedAttachment) throws RestApiException{ LOGGER.info("Uploading attachment {} for submission {}", attachmentId, submissionId); submissionService.uploadAttachment(submissionId, attachmentId, encryptedAttachment); } @Override - public Destination getDestination(final UUID destinationId) { + public Destination getDestination(final UUID destinationId) throws RestApiException { LOGGER.info("Loading destination {}", destinationId); return submissionService.getDestination(destinationId); } @Override - public RSAKey getEncryptionKeyForDestination(final UUID destinationId) { + public RSAKey getEncryptionKeyForDestination(final UUID destinationId) throws RestApiException, InvalidKeyException { LOGGER.info("Loading encryption key for destination id {}", destinationId); return keyService.getPublicEncryptionKey(destinationId); } @Override - public Submission sendSubmission(final SubmitSubmission submission) { + public Submission sendSubmission(final SubmitSubmission submission) throws RestApiException { LOGGER.info("Sending submission {}", submission.getSubmissionId()); return submissionService.sendSubmission(submission); } @@ -119,13 +123,13 @@ public class SubmissionSender implements Sender { } @Override - public List<EventLogEntry> getEventLog(final UUID caseId, final UUID destinationId) { + public List<EventLogEntry> getEventLog(final UUID caseId, final UUID destinationId) throws RestApiException, EventLogException { LOGGER.info("Loading event log for destination {}", destinationId); return eventLogService.getEventLog(caseId, destinationId); } @Override - public SubmissionStatus getLastedEvent(final SentSubmission sentSubmission) { + public SubmissionStatus getLastedEvent(final SentSubmission sentSubmission) throws RestApiException, EventLogException { LOGGER.info("Loading latest status for submission {}", sentSubmission.getSubmissionId()); return eventLogService.getLastedEvent(sentSubmission.getDestinationId(), sentSubmission.getCaseId(), sentSubmission.getSubmissionId(), sentSubmission.getAuthenticationTags()); } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSubscriber.java b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSubscriber.java index a5caafd681e38161f8999f5e753e574efc24da91..376de1ac15e81a389545a4a71dc1addca287f5a9 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSubscriber.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSubscriber.java @@ -13,9 +13,10 @@ import dev.fitko.fitconnect.api.domain.model.metadata.attachment.AttachmentForVa import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.DecryptionException; -import dev.fitko.fitconnect.api.exceptions.EventCreationException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EventCreationException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.api.services.events.EventLogService; @@ -59,13 +60,13 @@ public class SubmissionSubscriber implements Subscriber { } @Override - public Set<SubmissionForPickup> pollAvailableSubmissionsForDestination(final UUID destinationId, final int offset, final int limit) { + public Set<SubmissionForPickup> pollAvailableSubmissionsForDestination(final UUID destinationId, final int offset, final int limit) throws RestApiException { LOGGER.info("Loading submission {}-{} for destination {}", offset, limit, destinationId); return submissionService.pollAvailableSubmissionsForDestination(destinationId, offset, limit).getSubmissions(); } @Override - public Set<SubmissionForPickup> pollAvailableSubmissions(final int offset, final int limit) { + public Set<SubmissionForPickup> pollAvailableSubmissions(final int offset, final int limit) throws RestApiException { LOGGER.info("Loading submission {}-{}", offset, limit); return submissionService.pollAvailableSubmissions(offset, limit).getSubmissions(); } @@ -83,24 +84,24 @@ public class SubmissionSubscriber implements Subscriber { } @Override - public List<EventLogEntry> getEventLog(final UUID caseId, final UUID destinationId) throws RestApiException { + public List<EventLogEntry> getEventLog(final UUID caseId, final UUID destinationId) throws RestApiException, EventLogException { LOGGER.info("Loading event log for destination {}", destinationId); return eventLogService.getEventLog(caseId, destinationId); } @Override - public AuthenticationTags getAuthenticationTagsForEvent(final Event event, final Submission submission) { + public AuthenticationTags getAuthenticationTagsForEvent(final Event event, final Submission submission) throws RestApiException, EventLogException { LOGGER.info("Loading authentication tags of {} event for submission {}", event, submission.getSubmissionId()); return eventLogService.getAuthenticationTagsForEvent(event, submission); } @Override - public SubmissionStatus getLastedEvent(final UUID destinationId, final UUID caseId, final UUID submissionId) throws RestApiException { + public SubmissionStatus getLastedEvent(final UUID destinationId, final UUID caseId, final UUID submissionId) throws RestApiException, EventLogException { LOGGER.info("Loading current status for submission {}", submissionId); return eventLogService.getLastedEventWithoutAuthTagValidation(destinationId, caseId, submissionId); } @Override - public ValidationResult validateMetadata(final Metadata metadata, final Submission submission, final AuthenticationTags authenticationTags) { + public ValidationResult validateMetadata(final Metadata metadata, final Submission submission, final AuthenticationTags authenticationTags) throws RestApiException { LOGGER.info("Validating metadata"); final Destination destination = submissionService.getDestination(submission.getDestinationId()); return validationService.validateMetadata(metadata, submission, destination, authenticationTags); @@ -119,9 +120,9 @@ public class SubmissionSubscriber implements Subscriber { } @Override - public ValidationResult validateSubmissionDataSchema(final String submissiondata, final URI schemaUri) { + public ValidationResult validateSubmissionDataSchema(final String submissionData, final URI schemaUri) { LOGGER.info("Validating submission data schema"); - return validationService.validateSubmissionDataSchema(submissiondata, schemaUri); + return validationService.validateSubmissionDataSchema(submissionData, schemaUri); } @Override diff --git a/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java b/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java index 53989cd4fed0369df177b24d8a15711c8aeea2a4..5e66adbc33c76f1c72fe9930214f1984eabeb8c1 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java @@ -1,8 +1,7 @@ package dev.fitko.fitconnect.core.auth; import dev.fitko.fitconnect.api.domain.auth.OAuthToken; -import dev.fitko.fitconnect.api.exceptions.AuthenticationException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.core.http.HttpClient; import org.slf4j.Logger; @@ -63,7 +62,7 @@ public class DefaultOAuthService implements OAuthService { tokenExpirationTime = null; } - private void authenticate() throws AuthenticationException { + private void authenticate() { final String requestBody = buildRequestBody(clientId, clientSecret); currentToken = performTokenRequest(requestBody); tokenExpirationTime = LocalDateTime.now().plusSeconds(currentToken.getExpiresIn()); diff --git a/core/src/main/java/dev/fitko/fitconnect/core/crypto/CryptoConstants.java b/core/src/main/java/dev/fitko/fitconnect/core/crypto/CryptoConstants.java index c723046e8b9a3e34fb6ca888b4c24cdfddf409ab..863677df18f088d58c57731237c665ce22f1f0e3 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/crypto/CryptoConstants.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/crypto/CryptoConstants.java @@ -7,8 +7,8 @@ import com.nimbusds.jose.JWEAlgorithm; public class CryptoConstants { public final static String DEFAULT_HASH_ALGORITHM = HashAlgorithm.SHA_512.getIdentifyer(); - public final static String DEFAULT_SYMMETRIC_ENCRYPTION_ALGORITHM = SymmetricEncryptionAlgorithm.AES.getIdentifyer(); - public final static String DEFAULT_HMAC_ALGORITHM = HmacAlgorithm.HMAC_SHA_512.getIdentifyer(); + public final static String DEFAULT_SYMMETRIC_ENCRYPTION_ALGORITHM = SymmetricEncryptionAlgorithm.AES.getIdentifier(); + public final static String DEFAULT_HMAC_ALGORITHM = HmacAlgorithm.HMAC_SHA_512.getIdentifier(); public final static EncryptionMethod DEFAULT_JWE_ENCRYPTION_METHOD = EncryptionMethod.A256GCM; public static final JWEAlgorithm DEFAULT_JWE_ALGORITHM = JWEAlgorithm.RSA_OAEP_256; public static final CompressionAlgorithm DEFAULT_JWE_COMPRESSION_ALGORITHM = CompressionAlgorithm.DEF; diff --git a/core/src/main/java/dev/fitko/fitconnect/core/crypto/HashService.java b/core/src/main/java/dev/fitko/fitconnect/core/crypto/HashService.java index 12b95583b05f029056889a6a15e3cdc515f3620a..82b0e4d8a9899ecd30df6f5a6b2ef679f48c0890 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/crypto/HashService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/crypto/HashService.java @@ -1,7 +1,7 @@ package dev.fitko.fitconnect.core.crypto; -import dev.fitko.fitconnect.api.exceptions.EncryptionException; -import dev.fitko.fitconnect.api.exceptions.InitializationException; +import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; import dev.fitko.fitconnect.api.services.crypto.MessageDigestService; import javax.crypto.Mac; @@ -22,7 +22,7 @@ public class HashService implements MessageDigestService { try { messageDigest = MessageDigest.getInstance(DEFAULT_HASH_ALGORITHM); } catch (final NoSuchAlgorithmException e) { - throw new InitializationException(e.getMessage(), e); + throw new FitConnectInitialisationException(e.getMessage(), e); } } @@ -67,7 +67,6 @@ public class HashService implements MessageDigestService { @Override public String calculateHMAC(final String data, final String key) { - try { final String hmacAlgorithm = DEFAULT_HMAC_ALGORITHM; final SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), hmacAlgorithm); diff --git a/core/src/main/java/dev/fitko/fitconnect/core/crypto/HmacAlgorithm.java b/core/src/main/java/dev/fitko/fitconnect/core/crypto/HmacAlgorithm.java index f468b836928f745c3cd3b5cb36a41923b7387030..6ec7cb8b8cf199895bcf16d5cb1d4ead911a8c89 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/crypto/HmacAlgorithm.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/crypto/HmacAlgorithm.java @@ -4,13 +4,13 @@ public enum HmacAlgorithm { HMAC_SHA_512("HmacSHA512"); - private final String identifyer; + private final String identifier; - HmacAlgorithm(String identifyer) { - this.identifyer = identifyer; + HmacAlgorithm(final String identifier) { + this.identifier = identifier; } - public String getIdentifyer() { - return identifyer; + public String getIdentifier() { + return identifier; } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java b/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java index cd7232a96ba4a15f251402f217089b6b5d808bcf..1f7b084e78602fcf25e141238fb792d08cdd904e 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java @@ -9,8 +9,8 @@ import com.nimbusds.jose.Payload; import com.nimbusds.jose.crypto.RSADecrypter; import com.nimbusds.jose.crypto.RSAEncrypter; import com.nimbusds.jose.jwk.RSAKey; -import dev.fitko.fitconnect.api.exceptions.DecryptionException; -import dev.fitko.fitconnect.api.exceptions.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.api.services.crypto.MessageDigestService; import dev.fitko.fitconnect.core.util.StopWatch; diff --git a/core/src/main/java/dev/fitko/fitconnect/core/crypto/SymmetricEncryptionAlgorithm.java b/core/src/main/java/dev/fitko/fitconnect/core/crypto/SymmetricEncryptionAlgorithm.java index 0b7f909a1dd22963ab1afbd3d5bbb33bf8db1c5e..a75a9ad3f6118fd1c59f34cacc79113c7829d359 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/crypto/SymmetricEncryptionAlgorithm.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/crypto/SymmetricEncryptionAlgorithm.java @@ -4,13 +4,13 @@ public enum SymmetricEncryptionAlgorithm { AES("AES"); - private final String identifyer; + private final String identifier; - SymmetricEncryptionAlgorithm(String identifyer) { - this.identifyer = identifyer; + SymmetricEncryptionAlgorithm(final String identifier) { + this.identifier = identifier; } - public String getIdentifyer() { - return identifyer; + public String getIdentifier() { + return identifier; } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java b/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java index 3f6abdcc0c0ed46747845bf1a9b04313c55a7cab..b960365ca4c3920e09cf43721536ce697a13cd52 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java @@ -10,10 +10,10 @@ import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.validation.ValidationContext; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.AuthenticationTagsEmptyException; -import dev.fitko.fitconnect.api.exceptions.EventLogException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.SubmitEventNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.AuthenticationTagsEmptyException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.SubmitEventNotFoundException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.events.EventLogService; import dev.fitko.fitconnect.api.services.events.EventLogVerificationService; @@ -59,7 +59,7 @@ public class EventLogApiService implements EventLogService { } @Override - public List<EventLogEntry> getEventLog(final UUID caseId, final UUID destinationId) throws EventLogException { + public List<EventLogEntry> getEventLog(final UUID caseId, final UUID destinationId) throws RestApiException, EventLogException { final EventLog eventLog = loadEventLog(caseId); final List<SignedJWT> jwtEvents = getJWTSFromEvents(eventLog.getEventLogs()); @@ -69,7 +69,7 @@ public class EventLogApiService implements EventLogService { } @Override - public AuthenticationTags getAuthenticationTagsForEvent(final Event event, final Submission submission) throws EventLogException { + public AuthenticationTags getAuthenticationTagsForEvent(final Event event, final Submission submission) throws RestApiException, EventLogException { final EventLog eventLog = loadEventLog(submission.getCaseId()); final List<SignedJWT> submitEvents = getJwtsFromEvent(event, submission, eventLog); @@ -122,7 +122,7 @@ public class EventLogApiService implements EventLogService { try { return this.httpClient.get(url, getHttpHeaders(MimeTypes.APPLICATION_JSON), EventLog.class).getBody(); } catch (final RestApiException e) { - throw new EventLogException("EventLog query failed", e); + throw new RestApiException("EventLog query failed", e); } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogVerifier.java b/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogVerifier.java index e77cf01de403b159cbafdadb1b73259832204bf3..dda3ba6a882301774ac16af3baef11fd41ba0c30 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogVerifier.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogVerifier.java @@ -14,7 +14,7 @@ import dev.fitko.fitconnect.api.domain.model.event.EventIssuer; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.validation.ValidationContext; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; import dev.fitko.fitconnect.api.services.events.EventLogVerificationService; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.validation.ValidationService; diff --git a/core/src/main/java/dev/fitko/fitconnect/core/events/SecurityEventTokenService.java b/core/src/main/java/dev/fitko/fitconnect/core/events/SecurityEventTokenService.java index 0191811982550a7774f4cea128b76a09de31eeec..ac366d87c77505bc1ae3958b1ec2ce984f2fcff8 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/events/SecurityEventTokenService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/events/SecurityEventTokenService.java @@ -15,8 +15,8 @@ import dev.fitko.fitconnect.api.domain.model.event.EventPayload; import dev.fitko.fitconnect.api.domain.model.event.EventClaimFields; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.EventCreationException; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.EventCreationException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.events.SecurityEventService; import dev.fitko.fitconnect.api.services.validation.ValidationService; diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java b/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java index 6aa9ec61c3240ccf7df75d5336340c792d009468..927269f17b3f3665becc27f92e3b036041a87737 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java @@ -16,10 +16,10 @@ public class UserAgentInterceptor implements Interceptor { private final String productVersion; private final String commit; - public UserAgentInterceptor(BuildInfo buildInfo) { - this.productName = buildInfo.getProductName(); - this.productVersion = buildInfo.getProductVersion(); - this.commit = buildInfo.getCommit(); + public UserAgentInterceptor(final BuildInfo buildInfo) { + productName = buildInfo.getProductName(); + productVersion = buildInfo.getProductVersion(); + commit = buildInfo.getCommit(); } @NotNull diff --git a/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java b/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java index 4e3c2c2137347681551c575d8eb8cefde377be95..35ccdb32f91518fa19d03e86c81814f8b72c4e84 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java @@ -9,8 +9,8 @@ import dev.fitko.fitconnect.api.domain.model.destination.Destination; import dev.fitko.fitconnect.api.domain.model.jwk.ApiJwk; import dev.fitko.fitconnect.api.domain.model.jwk.ApiJwkSet; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.InvalidKeyException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; @@ -119,7 +119,7 @@ public class PublicKeyService implements KeyService { private void validateResult(final ValidationResult validationResult, final String message) { if (validationResult.hasError()) { - if (config.getCurrentEnvironment().isAllowInsecurePublicKey()) { + if (config.isAllowInsecurePublicKey()) { LOGGER.warn(message, validationResult.getError()); } else { throw new InvalidKeyException(message, validationResult.getError()); diff --git a/core/src/main/java/dev/fitko/fitconnect/core/routing/RouteVerifier.java b/core/src/main/java/dev/fitko/fitconnect/core/routing/RouteVerifier.java index b1920628b492018dd022329d4126b9edc7c6f94c..51a03baefe70e57e22a4091e3785ad07bc549abe 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/routing/RouteVerifier.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/routing/RouteVerifier.java @@ -16,9 +16,9 @@ import com.nimbusds.jwt.SignedJWT; import dev.fitko.fitconnect.api.domain.model.route.Route; import dev.fitko.fitconnect.api.domain.model.route.RouteDestination; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.InvalidKeyException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.routing.RoutingVerificationService; import dev.fitko.fitconnect.api.services.validation.ValidationService; @@ -64,7 +64,7 @@ public class RouteVerifier implements RoutingVerificationService { } catch (final ValidationException e) { return error(e); } catch (final InvalidKeyException e) { - return error(new ValidationException("Public signature key is invalid: " + e.getMessage())); + return error(new ValidationException("Public signature key is invalid: " + e.getCause().getMessage())); } catch (final RestApiException e) { return error(new ValidationException("Could not retrieve public signature key: " + e.getMessage())); } catch (final ParseException | JOSEException | JsonProcessingException e) { diff --git a/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java b/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java index b0517a27f4f35b196510f156012355e971d435e1..59b59c891285e531d044c5db164ff6536a21088e 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java @@ -3,7 +3,7 @@ package dev.fitko.fitconnect.core.routing; import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.domain.model.route.AreaResult; import dev.fitko.fitconnect.api.domain.model.route.RouteResult; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.routing.RoutingService; import dev.fitko.fitconnect.core.http.HttpClient; import dev.fitko.fitconnect.core.http.HttpHeaders; @@ -30,7 +30,7 @@ public class RoutingApiService implements RoutingService { } @Override - public AreaResult getAreas(final List<String> searchExpressions, final int offset, final int limit) { + public AreaResult getAreas(final List<String> searchExpressions, final int offset, final int limit) throws RestApiException { final String url = config.getAreaEndpoint(); @@ -48,7 +48,7 @@ public class RoutingApiService implements RoutingService { } @Override - public RouteResult getRoutes(final String leikaKey, final String ars, final String ags, final String areaId, final int offset, final int limit) { + public RouteResult getRoutes(final String leikaKey, final String ars, final String ags, final String areaId, final int offset, final int limit) throws RestApiException { testIfSearchCriterionIsSet(ars, ags, areaId); 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 da51addd8dbecb5a03278360f3cb4078be6aa2fb..1465c37a681ea8945333e5f823209525c0d553c4 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 @@ -2,10 +2,10 @@ package dev.fitko.fitconnect.core.schema; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import dev.fitko.fitconnect.api.config.SchemaConfig; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; import dev.fitko.fitconnect.api.domain.schema.SchemaResources; -import dev.fitko.fitconnect.api.exceptions.InitializationException; -import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectInitialisationException; +import dev.fitko.fitconnect.api.exceptions.internal.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import dev.fitko.fitconnect.core.http.HttpClient; import org.slf4j.Logger; @@ -124,14 +124,15 @@ public class SchemaResourceProvider implements SchemaProvider { } LOGGER.warn("Fetching schema " + schemaUri + " from local files failed, attempting to retrieve a remote version."); - if (schemaUri.getScheme().equals("https")) { - try { - return this.httpClient.get(schemaUri.toString(), String.class).getBody(); - } catch (Exception exception) { - throw new SchemaNotFoundException("Submission data schema " + schemaUri + " is not available."); - } + if (!schemaUri.getScheme().equals("https")) { + throw new SchemaNotFoundException("Fetching schema " + schemaUri + " from remote was skipped, since the URI does not support HTTPS."); + } + + try { + return this.httpClient.get(schemaUri.toString(), String.class).getBody(); + } catch (final Exception exception) { + throw new SchemaNotFoundException("Submission data schema " + schemaUri + " is not available."); } - throw new SchemaNotFoundException("Fetching schema " + schemaUri + " from remote was skipped, since the URI does not support HTTPS."); } private void addSetSchema(final String schema) { @@ -176,7 +177,7 @@ public class SchemaResourceProvider implements SchemaProvider { private List<String> getResourceFiles(final String schemaPath) { - File schemaFolder = new File(Objects.requireNonNull(SchemaResourceProvider.class.getClassLoader().getResource(schemaPath)).getFile()); + final File schemaFolder = new File(Objects.requireNonNull(SchemaResourceProvider.class.getClassLoader().getResource(schemaPath)).getFile()); return Arrays.stream(Objects.requireNonNull(schemaFolder.listFiles())) .map(file -> "/" + schemaPath + "/" + file.getName()) @@ -188,7 +189,7 @@ public class SchemaResourceProvider implements SchemaProvider { final BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { return reader.lines().collect(Collectors.joining(System.lineSeparator())); } catch (final Exception e) { - throw new InitializationException("Could not read schema file " + schemaFile, e); + throw new FitConnectInitialisationException("Could not read schema file " + schemaFile, e); } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java b/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java index 2cb475d6ad31c7dd83f63c3726efbc50530b4090..2d70b8131b9765298513d64d6071f8c4146c2c75 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java @@ -7,7 +7,7 @@ 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.SubmissionsForPickup; import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; import dev.fitko.fitconnect.core.http.HttpClient; @@ -56,14 +56,17 @@ public class SubmissionApiService implements SubmissionService { @Override public void uploadAttachment(final UUID submissionId, final UUID attachmentId, final String encryptedAttachment) throws RestApiException { - - final String url = String.format(config.getAttachmentEndpoint(), submissionId, attachmentId); - - try { - this.httpClient.put(url, getHeaders("application/jose"), encryptedAttachment, Void.class); - } catch (RestApiException e) { - throw new RestApiException("Could not upload attachment", e); - } + final Map<String, Object> params = new HashMap<>(); + params.put("submissionId", submissionId); + params.put("attachmentId", attachmentId); + final RequestSettings requestSettings = RequestSettings.builder() + .url(config.getAttachmentEndpoint()) + .method(HttpMethod.PUT) + .responseType(Void.class) + .entity(getHttpEntity(encryptedAttachment, getHeaders("application/jose"))) + .params(params) + .build(); + performRequest(requestSettings); } @Override diff --git a/core/src/main/java/dev/fitko/fitconnect/core/util/CertificateLoader.java b/core/src/main/java/dev/fitko/fitconnect/core/util/CertificateLoader.java index ba87f40e8620fce0975fad3f71dcdb3fdb3ff392..0cd61bf249a41aac67513dede44828a4c7ae70c9 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/util/CertificateLoader.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/util/CertificateLoader.java @@ -1,7 +1,7 @@ package dev.fitko.fitconnect.core.util; import com.nimbusds.jose.util.Base64; -import dev.fitko.fitconnect.api.exceptions.RootCertificateException; +import dev.fitko.fitconnect.api.exceptions.internal.RootCertificateException; import java.io.ByteArrayInputStream; import java.io.File; diff --git a/core/src/main/java/dev/fitko/fitconnect/core/util/EventLogUtil.java b/core/src/main/java/dev/fitko/fitconnect/core/util/EventLogUtil.java index 00af98f2298134f0e2e577f0387616c4e3e48725..f64826daaeb84726d2c9dc2de7ae888d9a1747d8 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/util/EventLogUtil.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/util/EventLogUtil.java @@ -14,8 +14,8 @@ import dev.fitko.fitconnect.api.domain.model.event.TypeAndUUID; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.model.event.problems.Problem; import dev.fitko.fitconnect.api.domain.model.submission.Submission; -import dev.fitko.fitconnect.api.exceptions.EventCreationException; -import dev.fitko.fitconnect.api.exceptions.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.EventCreationException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; import java.text.ParseException; import java.util.ArrayList; 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 30f40284366243c0fca07bfc3872aa8c64ad467a..e6ec919c3dde7f7dc7dea7191b1a1d995122b20b 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 @@ -10,7 +10,6 @@ import com.networknt.schema.SpecVersion; import com.networknt.schema.ValidationMessage; import com.nimbusds.jose.jwk.KeyOperation; import com.nimbusds.jose.jwk.RSAKey; -import com.nimbusds.jose.util.Base64; import com.nimbusds.jose.util.StandardCharset; import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.domain.model.destination.Destination; @@ -22,6 +21,7 @@ import dev.fitko.fitconnect.api.domain.model.event.problems.attachment.Attachmen import dev.fitko.fitconnect.api.domain.model.event.problems.attachment.IncorrectAttachmentAuthenticationTag; import dev.fitko.fitconnect.api.domain.model.event.problems.data.DataHashMismatch; import dev.fitko.fitconnect.api.domain.model.event.problems.data.DataJsonSyntaxViolation; +import dev.fitko.fitconnect.api.domain.model.event.problems.data.DataSchemaViolation; import dev.fitko.fitconnect.api.domain.model.event.problems.data.DataXmlSyntaxViolation; import dev.fitko.fitconnect.api.domain.model.event.problems.data.IncorrectDataAuthenticationTag; import dev.fitko.fitconnect.api.domain.model.event.problems.metadata.AttachmentsMismatch; @@ -33,8 +33,6 @@ import dev.fitko.fitconnect.api.domain.model.event.problems.metadata.Unsupported import dev.fitko.fitconnect.api.domain.model.event.problems.metadata.UnsupportedMetadataSchema; import dev.fitko.fitconnect.api.domain.model.event.problems.metadata.UnsupportedReplyChannel; import dev.fitko.fitconnect.api.domain.model.event.problems.metadata.UnsupportedService; -import dev.fitko.fitconnect.api.domain.model.event.problems.data.*; -import dev.fitko.fitconnect.api.domain.model.event.problems.metadata.*; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; import dev.fitko.fitconnect.api.domain.model.metadata.attachment.ApiAttachment; import dev.fitko.fitconnect.api.domain.model.metadata.attachment.AttachmentForValidation; @@ -44,9 +42,9 @@ import dev.fitko.fitconnect.api.domain.model.metadata.data.SubmissionSchema; import dev.fitko.fitconnect.api.domain.model.replychannel.ReplyChannel; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.DataIntegrityException; -import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.DataIntegrityException; +import dev.fitko.fitconnect.api.exceptions.internal.SchemaNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.crypto.MessageDigestService; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import dev.fitko.fitconnect.api.services.validation.ValidationService; @@ -63,6 +61,7 @@ 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; @@ -74,7 +73,13 @@ import java.text.SimpleDateFormat; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -141,7 +146,7 @@ public class DefaultValidationService implements ValidationService { final String metadataJson = MAPPER.writeValueAsString(metadata); final JsonNode inputNode = MAPPER.readTree(metadataJson); return validate2020JsonSchema(schemaProvider.loadMetadataSchema(config.getMetadataSchemaWriteVersion()), inputNode); - } catch (final JsonProcessingException e) { + } catch (final JsonProcessingException | SchemaNotFoundException e) { // https://docs.fitko.de/fit-connect/docs/receiving/verification/#schema-pr%C3%BCfung return ValidationResult.withErrorAndProblem(e, new MetadataSchemaViolation()); } @@ -177,12 +182,12 @@ public class DefaultValidationService implements ValidationService { @Override public ValidationResult validateSubmissionDataSchema(final String json, final URI schemaUri) { - if (config.getCurrentEnvironment().isSkipSubmissionDataValidation()) { + if (config.isSkipSubmissionDataValidation()) { LOGGER.warn("Submission data validation is deactivated. This should be done only on secure test environments."); return ValidationResult.ok(); } - String schema = schemaProvider.loadSubmissionDataSchema(schemaUri); + final String schema = schemaProvider.loadSubmissionDataSchema(schemaUri); try { return returnValidationResult(SCHEMA_FACTORY_DRAFT_2020.getSchema(schema).validate(MAPPER.readTree(json))); } catch (final JacksonException e) { @@ -376,7 +381,7 @@ public class DefaultValidationService implements ValidationService { } private ValidationResult validateKey(final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException { - if (config.getCurrentEnvironment().isAllowInsecurePublicKey()) { + if (config.isAllowInsecurePublicKey()) { return validateWithoutCertChain(publicKey, purpose); } else { return validateCertChain(publicKey, purpose); @@ -397,7 +402,7 @@ public class DefaultValidationService implements ValidationService { private ValidationResult validateWithoutCertChain(final RSAKey publicKey, final KeyOperation purpose) { LOGGER.info("Validating public key without XC5 certificate chain"); try { - final LogLevel logLevel = config.getCurrentEnvironment().isAllowInsecurePublicKey() ? LogLevel.WARN : LogLevel.ERROR; + final LogLevel logLevel = config.isAllowInsecurePublicKey() ? LogLevel.WARN : LogLevel.ERROR; withoutX5CValidation().withErrorLogLevel(logLevel).build().validate(publicKey, purpose); } catch (final JWKValidationException exception) { return ValidationResult.error(exception); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/RestEndpointBase.java b/core/src/test/java/dev/fitko/fitconnect/core/RestEndpointBase.java index bfac3e87b8dad9262638afd2909c737449369a24..cb9c881bd61453693618846be13bd573afe95331 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/RestEndpointBase.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/RestEndpointBase.java @@ -8,6 +8,7 @@ import dev.fitko.fitconnect.api.config.EnvironmentName; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import java.util.List; import java.util.Map; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; @@ -30,7 +31,7 @@ public abstract class RestEndpointBase { protected ApplicationConfig getTestConfig(final String fakeBaseUrl) { final var envName = new EnvironmentName("TESTING"); - final var environments = Map.of(envName, new Environment(fakeBaseUrl, fakeBaseUrl, fakeBaseUrl, fakeBaseUrl, false, false)); + final var environments = Map.of(envName, new Environment(fakeBaseUrl, fakeBaseUrl, List.of(fakeBaseUrl), fakeBaseUrl, false, false, false)); return ApplicationConfig.builder() .environments(environments) 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 0dbc9bd4f7c4d17b7b38cf90130b05879f2eb24c..27cb30f7e4b7d24dd02474a7aeac8fbc9496b154 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java @@ -24,10 +24,10 @@ 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.exceptions.EncryptionException; -import dev.fitko.fitconnect.api.exceptions.EventLogException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.Sender; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.api.services.events.EventLogService; diff --git a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSubscriberTest.java b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSubscriberTest.java index fc81efa09817057194950517c9099c2d4c930558..7fc169b1cb0510431c6e94dcb8392c076f7c4455 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSubscriberTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSubscriberTest.java @@ -22,9 +22,9 @@ 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.SubmissionsForPickup; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.DataIntegrityException; -import dev.fitko.fitconnect.api.exceptions.EventLogException; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.DataIntegrityException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.Subscriber; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.api.services.events.EventLogService; diff --git a/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java index 9db27e1fb2cf685864cafca3c9e2e7b4a4dba616..c7d5a69ea88e2ae8b2061c20e6b2976e658f6df4 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java @@ -10,7 +10,7 @@ import dev.fitko.fitconnect.api.domain.model.event.SubmissionState; import dev.fitko.fitconnect.api.domain.model.event.SubmissionStatus; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.events.EventLogService; import dev.fitko.fitconnect.api.services.events.EventLogVerificationService; diff --git a/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogVerifierTest.java b/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogVerifierTest.java index 59a2478ce9b71de1d001108c71c84a17d4d64445..0a2592453ead7680ce2b368b2321e7757ea96016 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogVerifierTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogVerifierTest.java @@ -14,7 +14,7 @@ import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.model.event.problems.Problem; import dev.fitko.fitconnect.api.domain.validation.ValidationContext; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.events.EventLogVerificationService; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.validation.ValidationService; 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 c90c7c7e3282d84ef71454e0ad88ac6816c13165..a86171c25e6377858ceacd345351bb59eef3faa3 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 @@ -10,13 +10,13 @@ import com.nimbusds.jwt.SignedJWT; import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.config.Environment; import dev.fitko.fitconnect.api.config.EnvironmentName; -import dev.fitko.fitconnect.api.config.SchemaConfig; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; import dev.fitko.fitconnect.api.domain.model.event.Event; import dev.fitko.fitconnect.api.domain.model.event.EventPayload; import dev.fitko.fitconnect.api.domain.model.event.problems.submission.AttachmentsMismatch; import dev.fitko.fitconnect.api.domain.model.submission.Submission; import dev.fitko.fitconnect.api.domain.schema.SchemaResources; -import dev.fitko.fitconnect.api.exceptions.EventCreationException; +import dev.fitko.fitconnect.api.exceptions.internal.EventCreationException; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.api.services.events.SecurityEventService; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; @@ -261,10 +261,10 @@ class SecurityEventTokenServiceTest { final var envName = new EnvironmentName("testing"); final var testing = new Environment(); testing.setAllowInsecurePublicKey(true); - final var config = new ApplicationConfig(); - config.setEnvironments(Map.of(envName, testing)); - config.setActiveEnvironment(envName); - return config; + return ApplicationConfig.builder() + .activeEnvironment(envName) + .environments(Map.of(envName, testing)) + .build(); } private String getResourceAsString(final String name) throws IOException { diff --git a/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java index 14d04f580160285895ff9a2f93fc344043fa6e7f..2f375e7c0a108973e7bfe65cd6b067f62863d4ee 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java @@ -10,7 +10,7 @@ import dev.fitko.fitconnect.api.config.EnvironmentName; import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.api.domain.model.destination.Destination; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.InvalidKeyException; +import dev.fitko.fitconnect.api.exceptions.internal.InvalidKeyException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.text.ParseException; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -57,13 +58,14 @@ class PublicKeyServiceTest extends RestEndpointBase { final EnvironmentName envName = new EnvironmentName("TESTING"); final Environment environment = new Environment(); - environment.setSubmissionBaseUrl(baseUrl); + environment.setSubmissionBaseUrls(List.of(baseUrl)); environment.setSelfServicePortalBaseUrl(baseUrl); environment.setAllowInsecurePublicKey(true); - final ApplicationConfig config = new ApplicationConfig(); - config.setEnvironments(Map.of(envName, environment)); - config.setActiveEnvironment(envName); + final ApplicationConfig config = ApplicationConfig.builder() + .environments(Map.of(envName, environment)) + .activeEnvironment(envName) + .build(); underTest = new PublicKeyService(config, new HttpClient(), authServiceMock, submissionServiceMock, validationServiceMock); } @@ -115,12 +117,13 @@ class PublicKeyServiceTest extends RestEndpointBase { final EnvironmentName envName = new EnvironmentName("PROD"); final Environment environment = new Environment(); - environment.setSubmissionBaseUrl("http://localhost:" + wireMockServer.port()); + environment.setSubmissionBaseUrls(List.of("http://localhost:" + wireMockServer.port())); environment.setAllowInsecurePublicKey(false); - final ApplicationConfig config = new ApplicationConfig(); - config.setEnvironments(Map.of(envName, environment)); - config.setActiveEnvironment(envName); + final ApplicationConfig config = ApplicationConfig.builder() + .environments(Map.of(envName, environment)) + .activeEnvironment(envName) + .build(); final PublicKeyService keyService = new PublicKeyService(config, new HttpClient(), authServiceMock, submissionServiceMock, validationServiceMock); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/routing/RouteVerifierTest.java b/core/src/test/java/dev/fitko/fitconnect/core/routing/RouteVerifierTest.java index 4b441543955a154e657bbe5b228cfb2d64d78c3e..02fb3557709bc7728e5cf30e3167ce630a707499 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/routing/RouteVerifierTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/routing/RouteVerifierTest.java @@ -9,7 +9,7 @@ import com.nimbusds.jose.util.Base64URL; import com.nimbusds.jwt.SignedJWT; import dev.fitko.fitconnect.api.domain.model.route.Route; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; -import dev.fitko.fitconnect.api.exceptions.ValidationException; +import dev.fitko.fitconnect.api.exceptions.internal.ValidationException; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.validation.ValidationService; import dev.fitko.fitconnect.core.SubmissionSenderTest; diff --git a/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java index d489846033ca7a1725574365601ff4ac24c56f62..56b59e9443e75f756fdfdee486b0496a43a839dc 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java @@ -9,7 +9,7 @@ import dev.fitko.fitconnect.api.domain.model.route.Area; import dev.fitko.fitconnect.api.domain.model.route.AreaResult; import dev.fitko.fitconnect.api.domain.model.route.Route; import dev.fitko.fitconnect.api.domain.model.route.RouteResult; -import dev.fitko.fitconnect.api.exceptions.RestApiException; +import dev.fitko.fitconnect.api.exceptions.internal.RestApiException; import dev.fitko.fitconnect.api.services.routing.RoutingService; import dev.fitko.fitconnect.core.RestEndpointBase; import dev.fitko.fitconnect.core.http.HttpClient; @@ -44,9 +44,10 @@ public class RoutingApiServiceTest extends RestEndpointBase { final Environment environment = new Environment(); environment.setRoutingBaseUrl(fakeBaseUrl); - final ApplicationConfig config = new ApplicationConfig(); - config.setEnvironments(Map.of(envName, environment)); - config.setActiveEnvironment(envName); + final ApplicationConfig config = ApplicationConfig.builder() + .environments(Map.of(envName, environment)) + .activeEnvironment(envName) + .build(); underTest = new RoutingApiService(config, new HttpClient()); } 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 81034bf5e024a7e12b0eb2a49642ded906dc4e9b..89cecd8278fa2166ebfbc3a3d348ca2d8f689fb4 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 @@ -2,9 +2,9 @@ package dev.fitko.fitconnect.core.schema; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import dev.fitko.fitconnect.api.config.SchemaConfig; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; import dev.fitko.fitconnect.api.domain.schema.SchemaResources; -import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; +import dev.fitko.fitconnect.api.exceptions.internal.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import dev.fitko.fitconnect.core.http.HttpClient; import dev.fitko.fitconnect.core.http.HttpResponse; diff --git a/core/src/test/java/dev/fitko/fitconnect/core/util/EventLogUtilTest.java b/core/src/test/java/dev/fitko/fitconnect/core/util/EventLogUtilTest.java index 4ba6454ce2cc4e9b9fa5527b4f2fcb2037743d3a..41016b54c84e12d8c7b2fe88d67c7cc7063579dc 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/util/EventLogUtilTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/util/EventLogUtilTest.java @@ -5,9 +5,8 @@ import dev.fitko.fitconnect.api.domain.model.event.Event; import dev.fitko.fitconnect.api.domain.model.event.EventIssuer; import dev.fitko.fitconnect.api.domain.model.event.EventLog; import dev.fitko.fitconnect.api.domain.model.event.EventLogEntry; -import dev.fitko.fitconnect.api.domain.model.event.problems.data.DataEncryptionIssue; import dev.fitko.fitconnect.api.domain.model.event.problems.submission.InvalidEventLog; -import dev.fitko.fitconnect.api.exceptions.EventLogException; +import dev.fitko.fitconnect.api.exceptions.internal.EventLogException; import org.junit.jupiter.api.Test; import java.io.IOException; 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 512078accbb450843f6f32af43735057783866ae..38c1ee1e018e21bb190c481f9d797e39b7d0163f 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 @@ -11,7 +11,7 @@ import com.nimbusds.jose.util.Base64URL; import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.config.Environment; import dev.fitko.fitconnect.api.config.EnvironmentName; -import dev.fitko.fitconnect.api.config.SchemaConfig; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; 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.event.authtags.AuthenticationTags; @@ -152,13 +152,14 @@ class DefaultValidationServiceTest { //Given final String urlDummy = "https://localhost"; final EnvironmentName envName = new EnvironmentName("DEV"); - final Environment env = new Environment(urlDummy, urlDummy, urlDummy, urlDummy, false, false); + final Environment env = new Environment(urlDummy, urlDummy, List.of(urlDummy), urlDummy, false, false, false); - final var config = new ApplicationConfig(); - config.setHttpProxyHost(urlDummy); - config.setHttpProxyPort(8080); - config.setEnvironments(Map.of(envName, env)); - config.setActiveEnvironment(envName); + final var config = ApplicationConfig.builder() + .httpProxyHost(urlDummy) + .httpProxyPort(8080) + .environments(Map.of(envName, env)) + .activeEnvironment(envName) + .build(); final DefaultValidationService underTest = new DefaultValidationService(config, hashService, schemaProvider, Collections.emptyList()); @@ -261,7 +262,7 @@ class DefaultValidationServiceTest { data.setSubmissionSchema(submissionSchema); data.setHash(hash); - final Hash attachmentOneHash = new Hash(); + final Hash attachmentOneHash = new Hash(); attachmentOneHash.setContent(hashService.toHexString(hashService.createHash("someHash".getBytes()))); attachmentOneHash.setSignatureType(SignatureType.SHA_512); @@ -271,7 +272,7 @@ class DefaultValidationServiceTest { attachmentOne.setMimeType("application/pdf"); attachmentOne.setHash(attachmentOneHash); - final Hash attachmentTwoHash = new Hash(); + final Hash attachmentTwoHash = new Hash(); attachmentTwoHash.setContent(hashService.toHexString(hashService.createHash("someHash".getBytes()))); attachmentTwoHash.setSignatureType(SignatureType.SHA_512); @@ -586,7 +587,7 @@ class DefaultValidationServiceTest { // attachmentId that were announced submission.setAttachments(List.of(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())); - final Hash attachmentHash = new Hash(); + final Hash attachmentHash = new Hash(); attachmentHash.setContent(hashService.toHexString(hashService.createHash("someHash".getBytes()))); attachmentHash.setSignatureType(SignatureType.SHA_512); @@ -1403,9 +1404,10 @@ class DefaultValidationServiceTest { final var testing = new Environment(); testing.setAllowInsecurePublicKey(allowInsecureKey); testing.setSkipSubmissionDataValidation(skipSubmissionDataValidation); - final var config = new ApplicationConfig(); - config.setEnvironments(Map.of(envName, testing)); - config.setActiveEnvironment(envName); + final var config = ApplicationConfig.builder() + .environments(Map.of(envName, testing)) + .activeEnvironment(envName) + .build(); return config; } diff --git a/client/src/test/java/dev/fitko/fitconnect/client/ClientIntegrationTest.java b/integration-tests/README.md similarity index 100% rename from client/src/test/java/dev/fitko/fitconnect/client/ClientIntegrationTest.java rename to integration-tests/README.md diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java index 2037094728c6eac936749f7d13f2126b3281ba04..bee40f79b0dbedfa83a41fca4847a8ee831310de 100644 --- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java +++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java @@ -1,5 +1,6 @@ package dev.fitko.fitconnect.integrationtests; +import dev.fitko.fitconnect.api.config.build.BuildInfo; import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.core.auth.DefaultOAuthService; import dev.fitko.fitconnect.core.http.HttpClient; diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/IntegrationTestBase.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/IntegrationTestBase.java index 3a9f129a0392d62325cc21662da4d24f27d037dc..ec7764c11d9ed60c22afca1bcf317760976e9df5 100644 --- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/IntegrationTestBase.java +++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/IntegrationTestBase.java @@ -7,7 +7,7 @@ import dev.fitko.fitconnect.api.config.SenderConfig; import dev.fitko.fitconnect.api.config.SubscriberConfig; import dev.fitko.fitconnect.api.domain.model.event.problems.Problem; import dev.fitko.fitconnect.client.SubscriberClient; -import dev.fitko.fitconnect.client.factory.ClientFactory; +import dev.fitko.fitconnect.client.bootstrap.ClientFactory; import java.io.IOException; import java.util.List; @@ -50,7 +50,7 @@ public class IntegrationTestBase { .build(); final EnvironmentName envName = new EnvironmentName(environmentName); - final Environment env = new Environment(authBaseUrl, routingBaseUrl, submissionBaseUrl, selfServicePortalUrl, allowInsecurePublicKey, false); + final Environment env = new Environment(authBaseUrl, routingBaseUrl, List.of(submissionBaseUrl), selfServicePortalUrl, true, allowInsecurePublicKey, false); return ApplicationConfig.builder() .senderConfig(sender) diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/RoutingIT.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/RoutingIT.java index adab025fa0ceb0843011aa24cc7447d6cc72d05b..bdbd0b203874e58945075c6fd033b532a56495e1 100644 --- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/RoutingIT.java +++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/RoutingIT.java @@ -3,8 +3,8 @@ package dev.fitko.fitconnect.integrationtests; import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.domain.model.route.Area; import dev.fitko.fitconnect.api.domain.model.route.Route; -import dev.fitko.fitconnect.client.RoutingClient; -import dev.fitko.fitconnect.client.factory.ClientFactory; +import dev.fitko.fitconnect.client.RouterClient; +import dev.fitko.fitconnect.client.bootstrap.ClientFactory; import dev.fitko.fitconnect.client.router.DestinationSearch; import dev.fitko.fitconnect.integrationtests.condition.EnableIfEnvironmentVariablesAreSet; import org.hamcrest.Matchers; @@ -25,7 +25,7 @@ public class RoutingIT extends IntegrationTestBase { // Given final ApplicationConfig config = getConfigWithCredentialsFromEnvironment("TESTING", true); - final RoutingClient routingClient = ClientFactory.getRoutingClient(config); + final RouterClient routerClient = ClientFactory.getRouterClient(config); final DestinationSearch search = DestinationSearch.Builder() .withLeikaKey("99123456760610") @@ -33,7 +33,7 @@ public class RoutingIT extends IntegrationTestBase { .build(); // When - final List<Route> routes = routingClient.findDestinations(search); + final List<Route> routes = routerClient.findDestinations(search); // Then assertThat(routes, Matchers.hasSize(1)); @@ -46,7 +46,7 @@ public class RoutingIT extends IntegrationTestBase { // Given final ApplicationConfig config = getConfigWithCredentialsFromEnvironment("TESTING", true); - final RoutingClient routingClient = ClientFactory.getRoutingClient(config); + final RouterClient routerClient = ClientFactory.getRouterClient(config); final DestinationSearch search = DestinationSearch.Builder() .withLeikaKey("99123456760610") @@ -54,7 +54,7 @@ public class RoutingIT extends IntegrationTestBase { .build(); // When - final List<Route> routes = routingClient.findDestinations(search); + final List<Route> routes = routerClient.findDestinations(search); // Then assertThat(routes, Matchers.hasSize(1)); @@ -67,10 +67,10 @@ public class RoutingIT extends IntegrationTestBase { // Given final ApplicationConfig config = getConfigWithCredentialsFromEnvironment("TESTING", true); - final RoutingClient routingClient = ClientFactory.getRoutingClient(config); + final RouterClient routerClient = ClientFactory.getRouterClient(config); // When - final List<Area> areas = routingClient.findAreas(List.of("Leip*", "04229"), 0, 10); + final List<Area> areas = routerClient.findAreas(List.of("Leip*", "04229"), 0, 10); // Then assertThat(areas, Matchers.is(Matchers.not(Matchers.empty()))); diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java index cb71cf46dfe838bce4863114e72ca74dff22c970..905c1b078b22bb97a3a829b459620a9161465a17 100644 --- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java +++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java @@ -3,7 +3,7 @@ package dev.fitko.fitconnect.integrationtests; import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.jwk.RSAKey; import dev.fitko.fitconnect.api.config.ApplicationConfig; -import dev.fitko.fitconnect.api.config.SchemaConfig; +import dev.fitko.fitconnect.api.config.defaults.SchemaConfig; import dev.fitko.fitconnect.api.domain.model.event.Event; import dev.fitko.fitconnect.api.domain.model.event.SubmissionStatus; import dev.fitko.fitconnect.api.domain.model.metadata.ContentStructure; @@ -16,10 +16,11 @@ import dev.fitko.fitconnect.api.domain.model.metadata.data.Data; import dev.fitko.fitconnect.api.domain.model.metadata.data.MimeType; import dev.fitko.fitconnect.api.domain.model.metadata.data.SubmissionSchema; import dev.fitko.fitconnect.api.domain.model.replychannel.ReplyChannel; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSenderException; import dev.fitko.fitconnect.api.services.crypto.CryptoService; import dev.fitko.fitconnect.client.SenderClient; import dev.fitko.fitconnect.client.SubscriberClient; -import dev.fitko.fitconnect.client.factory.ClientFactory; +import dev.fitko.fitconnect.client.bootstrap.ClientFactory; import dev.fitko.fitconnect.client.sender.model.Attachment; import dev.fitko.fitconnect.client.sender.model.SendableEncryptedSubmission; import dev.fitko.fitconnect.client.sender.model.SendableSubmission; @@ -47,9 +48,11 @@ import java.util.List; import java.util.UUID; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; @EnableIfEnvironmentVariablesAreSet public class SenderClientIT extends IntegrationTestBase { @@ -184,10 +187,11 @@ public class SenderClientIT extends IntegrationTestBase { .setJsonData(getResourceAsString("/submission_data.json"), URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json")) .build(); - final var sentSubmission = ClientFactory.getSenderClient(config).send(submission); + final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> ClientFactory.getSenderClient(config).send(submission)); // Then - Assertions.assertNull(sentSubmission); + assertThat(exception.getMessage(), containsString("Sending submission failed")); + assertThat(exception.getCause().getMessage(), containsString("JWK with id jsMQHFiA2uMGtiG3Ro8RJnYdEhp5W5KjGW-Vcf3-YMk has an invalid amount of certificates. Is 1 but should be 3.")); } @Test diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SubscriberClientIT.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SubscriberClientIT.java index 71524ce6b326656e4b3efca8e51956e8769a0b88..dcb2d642aff6c6f1da4cbf8164364e16bbeaf8a0 100644 --- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SubscriberClientIT.java +++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SubscriberClientIT.java @@ -9,10 +9,10 @@ import dev.fitko.fitconnect.api.domain.model.event.problems.data.IncorrectDataAu import dev.fitko.fitconnect.api.domain.model.event.problems.submission.InvalidEventLog; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.exceptions.RestApiException; -import dev.fitko.fitconnect.api.exceptions.SubmissionRequestException; +import dev.fitko.fitconnect.api.exceptions.client.FitConnectSubscriberException; import dev.fitko.fitconnect.client.SenderClient; import dev.fitko.fitconnect.client.SubscriberClient; -import dev.fitko.fitconnect.client.factory.ClientFactory; +import dev.fitko.fitconnect.client.bootstrap.ClientFactory; import dev.fitko.fitconnect.client.sender.model.Attachment; import dev.fitko.fitconnect.client.sender.model.SendableSubmission; import dev.fitko.fitconnect.client.subscriber.ReceivedSubmission; @@ -172,7 +172,7 @@ public class SubscriberClientIT extends IntegrationTestBase { // second attempt to receive and reject the submission should return an empty result // since the submission is gone after being rejected - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> subscriberClient.requestSubmission(sentSubmissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> subscriberClient.requestSubmission(sentSubmissionId)); assertThat(exception.getCause(), instanceOf(RestApiException.class)); assertThat(((RestApiException) exception.getCause()).getStatusCode(), is(404)); } @@ -212,7 +212,7 @@ public class SubscriberClientIT extends IntegrationTestBase { // second attempt to receive the submission should return an empty result // since the submission is gone after being accepted - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> subscriberClient.requestSubmission(sentSubmissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> subscriberClient.requestSubmission(sentSubmissionId)); assertThat(exception.getCause(), instanceOf(RestApiException.class)); assertThat(((RestApiException) exception.getCause()).getStatusCode(), is(404)); } @@ -252,7 +252,7 @@ public class SubscriberClientIT extends IntegrationTestBase { // second attempt to receive the submission should return an empty result // since the submission is gone after being accepted - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> subscriberClient.requestSubmission(sentSubmissionId)); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> subscriberClient.requestSubmission(sentSubmissionId)); assertThat(exception.getCause(), instanceOf(RestApiException.class)); assertThat(((RestApiException) exception.getCause()).getStatusCode(), is(404)); } @@ -295,7 +295,7 @@ public class SubscriberClientIT extends IntegrationTestBase { assertThat(senderClient.getStatusForSubmission(sentSubmission).getStatus(), is(SubmissionState.REJECTED)); // second attempt to receive and reject the submission should return an empty result since the submission is gone after being rejected - final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> subscriberClient.requestSubmission(sentSubmission.getSubmissionId())); + final FitConnectSubscriberException exception = assertThrows(FitConnectSubscriberException.class, () -> subscriberClient.requestSubmission(sentSubmission.getSubmissionId())); assertThat(exception.getCause(), instanceOf(RestApiException.class)); assertThat(((RestApiException) exception.getCause()).getStatusCode(), is(404)); } diff --git a/pom.xml b/pom.xml index b7fa9108f9936d4f8a8e293055b2a36455b5cfaf..2108a9c3e9f3d86dbdecb93aba5e3a53cc64127a 100644 --- a/pom.xml +++ b/pom.xml @@ -62,8 +62,8 @@ <!-- 3rd party dependencies --> <nimbus.version>9.31</nimbus.version> <okhttp.version>4.10.0</okhttp.version> - <jackson-databind.version>2.14.2</jackson-databind.version> - <jackson-annotations.version>2.14.2</jackson-annotations.version> + <jackson-databind.version>2.15.0</jackson-databind.version> + <jackson-annotations.version>2.15.0</jackson-annotations.version> <lombock.version>1.18.26</lombock.version> <logback.version>1.4.7</logback.version> <slf4j.version>2.0.7</slf4j.version> @@ -95,7 +95,7 @@ <nexus-staging-maven-plugin.version>1.6.13</nexus-staging-maven-plugin.version> <git-commit-id-maven-plugin.version>5.0.0</git-commit-id-maven-plugin.version> - <jacoco-maven-plugin.version>0.8.9</jacoco-maven-plugin.version> + <jacoco-maven-plugin.version>0.8.10</jacoco-maven-plugin.version> <local-version-suffix>-local</local-version-suffix>