diff --git a/README.md b/README.md index 57899a968dcccf4236a80a19fc32a993bfed8251..e8d5f696d5935a9077dc75f99eaab99360cd336e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Further 3rd party dependencies: * Spring Web/HTTP * Jackson FasterXMl * JCommander -* Typesafe Config +* Snakeyaml ## Getting Started @@ -63,17 +63,16 @@ _The following steps show how to get the SDK running_ ```sh mvn clean install ``` -5. Enter your API keys and references to your private decryption key in `sdk.conf` +5. Enter your API keys and references to your private decryption key in `config.yml` <p align="right">(<a href="#top">back to top</a>)</p> ### External Configuration -Configuration properties e.g. for REST-API urls and proxy settings can be found in the [HOCON](https://github.com/lightbend/config/blob/main/HOCON.md) -config ``sdk.conf`` within the root folder of the project. +Configuration properties e.g. for REST-API urls and proxy settings can be found in the YAML config ``config.yml`` within the root folder of the project. -In order to run the SDK client a configuration needs to be provided as file in the same path as the jar (e.g. when the commandline client is used) or via reference using the environment variable ``CONFIG_LOCATION`` (e.g. when the SDK i used programmatically). +In order to run the SDK client a configuration needs to be provided as file in the same path as the jar (e.g. when the commandline client is used) or via reference using the environment variable ``CONFIG_LOCATION`` (e.g. when the SDK is used programmatically). <p align="right">(<a href="#top">back to top</a>)</p> diff --git a/api/pom.xml b/api/pom.xml index e61c9c5ad4f79a90c0552bd4c76a68b69ba65602..254edec8f51855f947de0f000f76ce02f2c210c5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -33,10 +33,6 @@ <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> - <dependency> - <groupId>com.typesafe</groupId> - <artifactId>config</artifactId> - </dependency> </dependencies> </project> \ No newline at end of file diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/ApplicationConfig.java b/api/src/main/java/de/fitko/fitconnect/api/config/ApplicationConfig.java index e5ba97d3cc5cc8fcd9ab5b83200b46fc84151e3e..b3b152fb917e255a1b581b75910e50578f109f84 100644 --- a/api/src/main/java/de/fitko/fitconnect/api/config/ApplicationConfig.java +++ b/api/src/main/java/de/fitko/fitconnect/api/config/ApplicationConfig.java @@ -1,61 +1,73 @@ package de.fitko.fitconnect.api.config; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; @Data +@Builder +@NoArgsConstructor +@AllArgsConstructor public class ApplicationConfig { - + + @Builder.Default private String httpProxyHost = ""; + @Builder.Default private Integer httpProxyPort = 0; - private Integer requestTimeoutInSeconds; + @Builder.Default + private Integer requestTimeoutInSeconds = 30; private String metadataSchemaPath; private String privateSigningKeyPath; - private Sender sender; - private Subscriber subscriber; + private SenderConfig senderConfig; + private SubscriberConfig subscriberConfig; - private Environments environments; - private UsedEnvironment usedEnvironment; + private Map<EnvironmentName, Environment> environments; + private EnvironmentName activeEnvironment; private ResourcePaths resourcePaths; - public Environment getActiveEnvironment() { - switch (usedEnvironment) { - case PROD: - return environments.getProd(); - case TEST: - return environments.getTest(); - default: - return environments.getDev(); - } + public Environment getEnvironmentByName(final EnvironmentName environmentName) { + return environments.get(environmentName); + } + + public Environment getCurrentEnvironment() { + return getEnvironmentByName(activeEnvironment); } - public String getOAuthTokenEndpoint(){ - return getActiveEnvironment().getAuthBaseUrl() + resourcePaths.getAuthTokenPath(); + public String getOAuthTokenEndpoint() { + return getCurrentEnvironment().getAuthBaseUrl() + resourcePaths.getAuthTokenPath(); } public String getSubmissionsEndpoint() { - return getActiveEnvironment().getSubmissionBaseUrl() + resourcePaths.getSubmissionsPath(); + return getSubmissionBaseUrl() + resourcePaths.getSubmissionsPath(); } public String getSubmissionEndpoint() { - return getActiveEnvironment().getSubmissionBaseUrl() + resourcePaths.getSubmissionPath(); + return getSubmissionBaseUrl() + resourcePaths.getSubmissionPath(); } public String getAttachmentEndpoint() { - return getActiveEnvironment().getSubmissionBaseUrl() + resourcePaths.getSubmissionAttachmentPath(); + return getSubmissionBaseUrl() + resourcePaths.getSubmissionAttachmentPath(); } public String getEventLogEndpoint() { - return getActiveEnvironment().getSubmissionBaseUrl() + resourcePaths.getEventLogPath(); + return getSubmissionBaseUrl() + resourcePaths.getEventLogPath(); } public String destinationEndpoint() { - return getActiveEnvironment().getSubmissionBaseUrl() + resourcePaths.getDestinationPath(); + return getSubmissionBaseUrl() + resourcePaths.getDestinationPath(); } public String destinationKeyEndpoint() { - return getActiveEnvironment().getSubmissionBaseUrl() + resourcePaths.getDestinationKeyPath(); + return getSubmissionBaseUrl() + resourcePaths.getDestinationKeyPath(); + } + + private String getSubmissionBaseUrl() { + return getCurrentEnvironment().getSubmissionBaseUrl(); } } diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/Environment.java b/api/src/main/java/de/fitko/fitconnect/api/config/Environment.java index 12f9e474d2ef50567f1862b7d49937344f2d90eb..638e1a5e34439c052a2901e3194c82a8e5bb798f 100644 --- a/api/src/main/java/de/fitko/fitconnect/api/config/Environment.java +++ b/api/src/main/java/de/fitko/fitconnect/api/config/Environment.java @@ -3,8 +3,10 @@ package de.fitko.fitconnect.api.config; import lombok.*; @Data +@AllArgsConstructor @NoArgsConstructor public class Environment { private String authBaseUrl; private String submissionBaseUrl; + private boolean silentKeyValidation; } diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/EnvironmentName.java b/api/src/main/java/de/fitko/fitconnect/api/config/EnvironmentName.java new file mode 100644 index 0000000000000000000000000000000000000000..a793ee2b59d90aeafcb4a3b9ef4648171ee34288 --- /dev/null +++ b/api/src/main/java/de/fitko/fitconnect/api/config/EnvironmentName.java @@ -0,0 +1,10 @@ +package de.fitko.fitconnect.api.config; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class EnvironmentName { + private String name; +} diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/Environments.java b/api/src/main/java/de/fitko/fitconnect/api/config/Environments.java deleted file mode 100644 index ed4aa3e22c2a65801ed39b5da5877725e476e5ad..0000000000000000000000000000000000000000 --- a/api/src/main/java/de/fitko/fitconnect/api/config/Environments.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.fitko.fitconnect.api.config; - -import lombok.*; - -@Data -@NoArgsConstructor -public class Environments { - - private Environment dev; - private Environment prod; - private Environment test; -} diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/ResourcePaths.java b/api/src/main/java/de/fitko/fitconnect/api/config/ResourcePaths.java index 11f2ebe143aee21192f5d89ab9c43b35aa111ce1..0d71a7e991803d7db2a10fff041487eb13c99ff2 100644 --- a/api/src/main/java/de/fitko/fitconnect/api/config/ResourcePaths.java +++ b/api/src/main/java/de/fitko/fitconnect/api/config/ResourcePaths.java @@ -1,9 +1,13 @@ package de.fitko.fitconnect.api.config; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data +@Builder +@AllArgsConstructor @NoArgsConstructor public class ResourcePaths { diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/Sender.java b/api/src/main/java/de/fitko/fitconnect/api/config/SenderConfig.java similarity index 75% rename from api/src/main/java/de/fitko/fitconnect/api/config/Sender.java rename to api/src/main/java/de/fitko/fitconnect/api/config/SenderConfig.java index bc655653c859ee5d89974b9be86857c3dced560b..07accd0b17d59c3e24016146ae13ea48be4f1a40 100644 --- a/api/src/main/java/de/fitko/fitconnect/api/config/Sender.java +++ b/api/src/main/java/de/fitko/fitconnect/api/config/SenderConfig.java @@ -4,7 +4,8 @@ import lombok.*; @Data @NoArgsConstructor -public class Sender { +@AllArgsConstructor +public class SenderConfig { private String clientId; private String clientSecret; } diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/Subscriber.java b/api/src/main/java/de/fitko/fitconnect/api/config/SubscriberConfig.java similarity index 79% rename from api/src/main/java/de/fitko/fitconnect/api/config/Subscriber.java rename to api/src/main/java/de/fitko/fitconnect/api/config/SubscriberConfig.java index 6d68a97183b1d6f15f6328dc8583ba9ace5325a5..30fc47decd18b091400c62ae21f88a3cae5af0e9 100644 --- a/api/src/main/java/de/fitko/fitconnect/api/config/Subscriber.java +++ b/api/src/main/java/de/fitko/fitconnect/api/config/SubscriberConfig.java @@ -3,8 +3,10 @@ package de.fitko.fitconnect.api.config; import lombok.*; @Data +@Builder +@AllArgsConstructor @NoArgsConstructor -public class Subscriber { +public class SubscriberConfig { private String clientId; private String clientSecret; private String privateDecryptionKeyPath; diff --git a/api/src/main/java/de/fitko/fitconnect/api/config/UsedEnvironment.java b/api/src/main/java/de/fitko/fitconnect/api/config/UsedEnvironment.java deleted file mode 100644 index 0a6d8df2f0a101c395c314ff4e3e1883920ff249..0000000000000000000000000000000000000000 --- a/api/src/main/java/de/fitko/fitconnect/api/config/UsedEnvironment.java +++ /dev/null @@ -1,5 +0,0 @@ -package de.fitko.fitconnect.api.config; - -public enum UsedEnvironment { - DEV, PROD, TEST -} diff --git a/client/README.md b/client/README.md index c9d337b5fdf15b631c9cb9d53161210cf331e54e..af21910e7b706da3edd92be5d7d5dae10e0de37f 100644 --- a/client/README.md +++ b/client/README.md @@ -6,9 +6,9 @@ The sdk comes with a commandline client to be able to use the sdk without any co #### Setup & Build 1. Build project root wih ``mvn clean package`` 2. Go to client/target and find a runnable jar ``client-VERSION.jar`` -3. set environment variable ``CONFIG_LOCATION`` or drop a configured [sdk.conf](../sdk.conf) file next to the runnable jar - 1. Linux/MacOS: ``export CONFIG_LOCATION=path/to/sdk.conf`` - 2. Windows: ``set CONFIG_LOCATION=C:\Path\To\sdk.conf`` +3. set environment variable ``CONFIG_LOCATION`` or drop a configured [config.yml](../config.yml) file next to the runnable jar + 1. Linux/MacOS: ``export CONFIG_LOCATION=path/to/config.yml`` + 2. Windows: ``set CONFIG_LOCATION=C:\Path\To\config.yml`` 4. run client with ``java -jar client-VERSION.jar [COMMAND] [OPTIONS]`` #### SEND Example diff --git a/client/pom.xml b/client/pom.xml index 028768a7f7cab30f3cb3823574ea3c7653a84467..84652f06cb3b273751cd828b43138c35cb5ddbc1 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -37,6 +37,10 @@ <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> </dependency> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + </dependency> <!-- Tests --> <dependency> @@ -54,11 +58,6 @@ <artifactId>hamcrest-all</artifactId> <scope>test</scope> </dependency> - <dependency> - <groupId>io.github.netmikey.logunit</groupId> - <artifactId>logunit-logback</artifactId> - <scope>test</scope> - </dependency> </dependencies> <build> diff --git a/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java b/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java index f3ce55bb98cf3a0c4cb19c4b69fedfa9d6d62f2d..897d70293bc7d955664767b8c7b6757f6ede168d 100644 --- a/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java +++ b/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java @@ -1,6 +1,7 @@ package de.fitko.fitconnect.client; import com.nimbusds.jose.jwk.RSAKey; +import de.fitko.fitconnect.api.config.Environment; import de.fitko.fitconnect.api.domain.model.destination.Destination; import de.fitko.fitconnect.api.domain.model.destination.DestinationService; import de.fitko.fitconnect.api.domain.model.metadata.ContentStructure; @@ -45,8 +46,8 @@ public class SenderClient { private SenderClient() { } - public static WithDestination build(final Sender sender, final String metadataSchema) { - return new ClientBuilder(sender, metadataSchema); + public static WithDestination build(final Sender sender, final String metadataSchema, final Environment environment) { + return new ClientBuilder(sender, metadataSchema, environment); } public interface WithDestination { @@ -155,16 +156,18 @@ public class SenderClient { public static class ClientBuilder implements WithDestination, WithServiceType, WithAttachments, WithData, Submit { private final Sender sender; + private final Environment environment; + private final String metadataSchema; private DataPayload dataPayload; private UUID destinationId; private ServiceType serviceType; - private final String metadataSchema; private List<File> attachments = new ArrayList<>(); - public ClientBuilder(final Sender sender, final String metadataSchema) { + public ClientBuilder(final Sender sender, final String metadataSchema, final Environment environment) { this.sender = sender; this.metadataSchema = metadataSchema; + this.environment = environment; } @Override @@ -220,8 +223,10 @@ public class SenderClient { final RSAKey encryptionKey = sender.getEncryptionKeyForDestination(destinationId, destination.getEncryptionKid()); final ValidationResult validationResult = sender.validatePublicKey(encryptionKey); if (validationResult.hasError()) { - logger.info("The public key is not valid", validationResult.getError()); - return Optional.empty(); + logger.warn("The public key is not valid, {}", validationResult.getError().getMessage()); + if(!environment.isSilentKeyValidation()){ + return Optional.empty(); + } } /** Create new submission and announce attachments **/ diff --git a/client/src/main/java/de/fitko/fitconnect/client/SubscriberClient.java b/client/src/main/java/de/fitko/fitconnect/client/SubscriberClient.java index bb9b7d5b0cac32a06fe18b4a9ba9522b058842a8..bcb18bea00d2d3dabf9bea6c7f0495886bd23b5d 100644 --- a/client/src/main/java/de/fitko/fitconnect/client/SubscriberClient.java +++ b/client/src/main/java/de/fitko/fitconnect/client/SubscriberClient.java @@ -37,11 +37,11 @@ public class SubscriberClient { public static RequestSubmission builder(final Subscriber subscriber, final String privateKey, final String metadataSchema) { if (privateKey == null) { - logger.error("No decryption key set, please check environment (sdk.conf) and provide a reference to the private decryption key"); + logger.error("No decryption key set, please check environment (config.yml) and provide a reference to the private decryption key"); return null; } if (metadataSchema == null) { - logger.error("No metadata schema present, please check environment (sdk.conf) and provide a metadata json schema"); + logger.error("No metadata schema present, please check environment (config.yml) and provide a metadata json schema"); return null; } return new ClientBuilder(subscriber, privateKey, metadataSchema); diff --git a/client/src/main/java/de/fitko/fitconnect/client/factory/ApplicationConfigLoader.java b/client/src/main/java/de/fitko/fitconnect/client/factory/ApplicationConfigLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..ab336b5da0c110954ad5b522ceb3d02d40763a1e --- /dev/null +++ b/client/src/main/java/de/fitko/fitconnect/client/factory/ApplicationConfigLoader.java @@ -0,0 +1,39 @@ +package de.fitko.fitconnect.client.factory; + +import de.fitko.fitconnect.api.config.ApplicationConfig; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ApplicationConfigLoader { + + /** + * Load ApplicationConfig from path. + * + * @param configPath path to config file + * + * @return ApplicationConfig + * @throws IOException if the default config file could not be loaded + */ + public static ApplicationConfig loadConfig(final Path configPath) throws IOException { + return loadConfig(Files.readString(configPath)); + } + + /** + * Load ApplicationConfig from string. + * + * @param configYaml string of the yaml config file + * + * @return ApplicationConfig + */ + public static ApplicationConfig loadConfig(final String configYaml) { + final Constructor constructor = new Constructor(ApplicationConfig.class); + final Yaml yaml = new Yaml(constructor); + return yaml.load(configYaml); + } +} diff --git a/client/src/main/java/de/fitko/fitconnect/client/factory/ClientFactory.java b/client/src/main/java/de/fitko/fitconnect/client/factory/ClientFactory.java index c157b39840089f42978d0786e2f5f5385aaee821..07103124d045d098dba76e16286d68a453f25bd6 100644 --- a/client/src/main/java/de/fitko/fitconnect/client/factory/ClientFactory.java +++ b/client/src/main/java/de/fitko/fitconnect/client/factory/ClientFactory.java @@ -1,10 +1,7 @@ package de.fitko.fitconnect.client.factory; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigBeanFactory; -import com.typesafe.config.ConfigException; -import com.typesafe.config.ConfigFactory; import de.fitko.fitconnect.api.config.ApplicationConfig; +import de.fitko.fitconnect.api.config.SubscriberConfig; import de.fitko.fitconnect.api.services.Sender; import de.fitko.fitconnect.api.services.Subscriber; import de.fitko.fitconnect.api.services.auth.OAuthService; @@ -44,8 +41,7 @@ public class ClientFactory { private static final Logger logger = LoggerFactory.getLogger(ClientFactory.class); - private static final String CONFIG_CONTEXT = "sdk"; - private static final String CONFIG_DEFAULT_LOCATION = "sdk.conf"; + private static final String CONFIG_DEFAULT_LOCATION = "config.yml"; private static final String CUSTOM_CONFIG_KEY = "CONFIG_LOCATION"; private static final String SENDER_BANNER = getSplashScreenResource("/sender-banner.txt"); @@ -55,7 +51,7 @@ public class ClientFactory { } /** - * Create a new {@link SenderClient} that is automatically configured via the sdk.conf file. + * Create a new {@link SenderClient} that is automatically configured via the config.yml file. * * @return the sender client */ @@ -77,12 +73,12 @@ public class ClientFactory { logger.info("Reading metadata schema from {} ", config.getMetadataSchemaPath()); final String metadataSchema = readPath(config.getMetadataSchemaPath()); - return SenderClient.build(sender, metadataSchema); + return SenderClient.build(sender, metadataSchema, config.getCurrentEnvironment()); } /** - * Create a new {@link SubscriberClient} that is automatically configured via sdk.conf file. + * Create a new {@link SubscriberClient} that is automatically configured via config.yml file. * * @return the subscriber client */ @@ -100,7 +96,7 @@ public class ClientFactory { logger.info(SUBSCRIBER_BANNER); logger.info("Initializing subscriber client ..."); final Subscriber subscriber = getSubscriber(config); - final var subscriberConfig = config.getSubscriber(); + final SubscriberConfig subscriberConfig = config.getSubscriberConfig(); logger.info("Reading private key from {} ", subscriberConfig.getPrivateDecryptionKeyPath()); final String privateKey = readPath(subscriberConfig.getPrivateDecryptionKeyPath()); @@ -114,8 +110,9 @@ public class ClientFactory { private static Subscriber getSubscriber(final ApplicationConfig config) { final CryptoService cryptoService = getCryptoService(); - final ValidationService validator = getValidatorService(); + final ValidationService validator = getValidatorService(config); final RestTemplate restTemplate = getRestTemplate(config); + final OAuthService authService = getSubscriberConfiguredAuthService(config, restTemplate); final EventLogService eventLogService = getEventLogService(config,restTemplate, authService); final SubmissionService submissionService = getSubmissionService(config,restTemplate, authService); @@ -125,8 +122,8 @@ public class ClientFactory { private static Sender getSender(final ApplicationConfig config) { final CryptoService cryptoService = getCryptoService(); - final ValidationService validator = getValidatorService(); final RestTemplate restTemplate = getRestTemplate(config); + final ValidationService validator = getValidatorService(config); final OAuthService authService = getSenderConfiguredAuthService(config, restTemplate); final EventLogService eventLogService = getEventLogService(config,restTemplate, authService); final SubmissionService submissionService = getSubmissionService(config,restTemplate, authService); @@ -136,14 +133,14 @@ public class ClientFactory { } private static OAuthService getSenderConfiguredAuthService(final ApplicationConfig config, final RestTemplate restTemplate) { - final String clientId = config.getSender().getClientId(); - final String clientSecret = config.getSender().getClientSecret(); + final String clientId = config.getSenderConfig().getClientId(); + final String clientSecret = config.getSenderConfig().getClientSecret(); return new DefaultOAuthService(restTemplate, clientId, clientSecret, config.getOAuthTokenEndpoint()); } private static OAuthService getSubscriberConfiguredAuthService(final ApplicationConfig config, final RestTemplate restTemplate) { - final String clientId = config.getSubscriber().getClientId(); - final String clientSecret = config.getSubscriber().getClientSecret(); + final String clientId = config.getSubscriberConfig().getClientId(); + final String clientSecret = config.getSubscriberConfig().getClientSecret(); return new DefaultOAuthService(restTemplate, clientId, clientSecret, config.getOAuthTokenEndpoint()); } @@ -159,9 +156,9 @@ public class ClientFactory { return new DestinationRestService(authService, restTemplate, config); } - private static DefaultValidationService getValidatorService() { + private static DefaultValidationService getValidatorService(final ApplicationConfig config) { final MessageDigestService messageDigestService = getMessageDigestService(); - return new DefaultValidationService(messageDigestService); + return new DefaultValidationService(messageDigestService, config); } private static CryptoService getCryptoService() { @@ -210,15 +207,14 @@ public class ClientFactory { return loadConfigFromPath(customConfigLocation); } - private static ApplicationConfig loadConfigFromPath(final String path) { + private static ApplicationConfig loadConfigFromPath(final String configPath) { try { - final Config configFile = ConfigFactory.parseFile(new File(path)); - final Config sdkConfig = ConfigFactory.load(configFile).getConfig(CONFIG_CONTEXT); - final ApplicationConfig applicationConfig = ConfigBeanFactory.create(sdkConfig, ApplicationConfig.class); - logger.info("Using sdk environment config {} with {}", applicationConfig.getActiveEnvironment(), applicationConfig); + final Path pathToConfig = Path.of(configPath); + final ApplicationConfig applicationConfig = ApplicationConfigLoader.loadConfig(pathToConfig); + logger.info("Using sdk environment config {} with {}", applicationConfig.getCurrentEnvironment(), applicationConfig); return applicationConfig; - } catch (final ConfigException e) { - throw new IllegalStateException("Config could not be loaded, please provide a 'sdk.conf' in the root path or in the ENV-var 'CONFIG_LOCATION'", e); + } catch (final IOException e) { + throw new IllegalStateException("Config could not be loaded, please provide a 'config.yml' in the root path or in the ENV-var 'CONFIG_LOCATION'", e); } } diff --git a/client/src/test/java/de/fitko/fitconnect/client/ClientIntegrationTest.java b/client/src/test/java/de/fitko/fitconnect/client/ClientIntegrationTest.java index 049909a1ec781588a4b61d63a81385395400081d..3b12e19c3b0f303cf9c0e936cc9594b130a5c9d7 100644 --- a/client/src/test/java/de/fitko/fitconnect/client/ClientIntegrationTest.java +++ b/client/src/test/java/de/fitko/fitconnect/client/ClientIntegrationTest.java @@ -7,15 +7,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import java.io.File; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; -import static de.fitko.fitconnect.api.config.UsedEnvironment.TEST; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -24,12 +21,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue; */ public class ClientIntegrationTest { + final String authBaseUrl = "https://auth-testing.fit-connect.fitko.dev"; + final String submissionBaseUrl = "https://submission-api-testing.fit-connect.fitko.dev"; + @Test @EnabledIfEnvironmentVariable(named = "TEST_DESTINATION_ID", matches = ".*") public void testSendAndConfirmCycle() { // Given - final ApplicationConfig config = getConfigWithCredentialsFromGitlab(); + final var testEnv = new Environment(authBaseUrl, submissionBaseUrl, true); + final ApplicationConfig config = getConfigWithCredentialsFromGitlab(testEnv); final var sentSubmission = ClientFactory.senderClient(config) .withDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID"))) @@ -57,7 +58,9 @@ public class ClientIntegrationTest { public void testListSubmissions() { // Given - final ApplicationConfig config = getConfigWithCredentialsFromGitlab(); + final var testEnv = new Environment(authBaseUrl, submissionBaseUrl, true); + final ApplicationConfig config = getConfigWithCredentialsFromGitlab(testEnv); + final var senderClient = ClientFactory.senderClient(config); final var subscriberClient = ClientFactory.subscriberClient(config); @@ -95,42 +98,60 @@ public class ClientIntegrationTest { subscriberClient.requestSubmission(submissionTwo.get().getSubmissionId()); } - private ApplicationConfig getConfigWithCredentialsFromGitlab() { - - final var testEnvironment = new Environment(); - testEnvironment.setAuthBaseUrl("https://auth-testing.fit-connect.fitko.dev"); - testEnvironment.setSubmissionBaseUrl("https://submission-api-testing.fit-connect.fitko.dev"); - - final var environments = new Environments(); - environments.setTest(testEnvironment); - - final var sender = new Sender(); - sender.setClientId(System.getenv("SENDER_CLIENT_ID")); - sender.setClientSecret(System.getenv("SENDER_CLIENT_SECRET")); - - final var subscriber = new Subscriber(); - subscriber.setClientId(System.getenv("SUBSCRIBER_CLIENT_ID")); - subscriber.setClientSecret(System.getenv("SUBSCRIBER_CLIENT_SECRET")); - subscriber.setPrivateDecryptionKeyPath("src/test/resources/private_decryption_test_key.json"); - - final var resourcePaths = new ResourcePaths(); - resourcePaths.setAuthTokenPath("/token"); - resourcePaths.setDestinationPath("/v1/destinations/{destinationId}"); - resourcePaths.setDestinationKeyPath("/v1/destinations/{destinationId}/keys/{kid}"); - resourcePaths.setEventLogPath("/v1/cases/{caseId}/events"); - resourcePaths.setSubmissionsPath("/v1/submissions"); - resourcePaths.setSubmissionPath("/v1/submissions/{submissionId}"); - resourcePaths.setSubmissionAttachmentPath("/v1/submissions/{submissionId}/attachments/{attachmentId}"); - - final var config = new ApplicationConfig(); - config.setSender(sender); - config.setSubscriber(subscriber); - config.setEnvironments(environments); - config.setUsedEnvironment(TEST); - config.setResourcePaths(resourcePaths); - config.setMetadataSchemaPath("src/test/resources/metadata_schema.json"); - config.setPrivateSigningKeyPath("src/test/resources/private_test_signing_key.json"); - - return config; + @Test + @EnabledIfEnvironmentVariable(named = "TEST_DESTINATION_ID", matches = ".*") + public void testAbortedSendSubmissionWithKeyValidationNotSilent() { + + // Given + final var prodEnv = new Environment(authBaseUrl, submissionBaseUrl, false); + final ApplicationConfig config = getConfigWithCredentialsFromGitlab("PROD", prodEnv); + + // When + final var sentSubmission = ClientFactory.senderClient(config) + .withDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID"))) + .withServiceType("Test Service", "urn:de:fim:leika:leistung:99400048079000") + .withAttachment(new File("src/test/resources/attachment.txt")) + .withJsonData("{ data: 'Beispiel Fachdaten' }") + .submit(); + + // Then + assertTrue(sentSubmission.isEmpty()); + } + + private ApplicationConfig getConfigWithCredentialsFromGitlab(final Environment env) { + return getConfigWithCredentialsFromGitlab("TESTING", env); + } + + private ApplicationConfig getConfigWithCredentialsFromGitlab(final String environmentName, final Environment env) { + + final var sender = new SenderConfig(System.getenv("SENDER_CLIENT_ID"), System.getenv("SENDER_CLIENT_SECRET")); + + final var subscriber = SubscriberConfig.builder() + .clientId(System.getenv("SUBSCRIBER_CLIENT_ID")) + .clientSecret(System.getenv("SUBSCRIBER_CLIENT_SECRET")) + .privateDecryptionKeyPath("src/test/resources/private_decryption_test_key.json") + .build(); + + final var resourcePaths = ResourcePaths.builder() + .authTokenPath("/token") + .destinationPath("/v1/destinations/{destinationId}") + .destinationKeyPath("/v1/destinations/{destinationId}/keys/{kid}") + .eventLogPath("/v1/cases/{caseId}/events") + .submissionsPath("/v1/submissions") + .submissionPath("/v1/submissions/{submissionId}") + .submissionAttachmentPath("/v1/submissions/{submissionId}/attachments/{attachmentId}") + .build(); + + final var envName = new EnvironmentName(environmentName); + + return ApplicationConfig.builder() + .senderConfig(sender) + .subscriberConfig(subscriber) + .environments(Map.of(envName, env)) + .resourcePaths(resourcePaths) + .activeEnvironment(envName) + .privateSigningKeyPath("src/test/resources/private_test_signing_key.json") + .metadataSchemaPath("src/test/resources/metadata_schema.json") + .build(); } } diff --git a/client/src/test/java/de/fitko/fitconnect/client/SenderClientTest.java b/client/src/test/java/de/fitko/fitconnect/client/SenderClientTest.java index 40509a1c29e2ae910323ae98f47d3e8695cd493a..c203eee55c58a6378e3793a912306ea32c1a207c 100644 --- a/client/src/test/java/de/fitko/fitconnect/client/SenderClientTest.java +++ b/client/src/test/java/de/fitko/fitconnect/client/SenderClientTest.java @@ -4,6 +4,7 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import de.fitko.fitconnect.api.config.Environment; import de.fitko.fitconnect.api.domain.model.destination.Destination; import de.fitko.fitconnect.api.domain.model.destination.DestinationService; import de.fitko.fitconnect.api.domain.model.metadata.data.MimeType; @@ -13,38 +14,34 @@ import de.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import de.fitko.fitconnect.api.domain.validation.ValidationResult; import de.fitko.fitconnect.api.exceptions.*; import de.fitko.fitconnect.api.services.Sender; -import io.github.netmikey.logunit.api.LogCapturer; +import de.fitko.fitconnect.client.testutil.LogCaptor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.mockito.Mockito; import java.io.File; -import java.io.IOException; import java.net.URI; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class SenderClientTest { - @RegisterExtension - LogCapturer logs = LogCapturer.create().captureForType(SenderClient.class); - private Sender senderMock; private SenderClient.WithDestination underTest; + private Environment environmentMock; + + private final LogCaptor logs = new LogCaptor(); @BeforeEach - public void setup() throws IOException { - senderMock = Mockito.mock(Sender.class); - underTest = SenderClient.build(senderMock, ""); + public void setup() { + senderMock = mock(Sender.class); + environmentMock = mock(Environment.class); + underTest = SenderClient.build(senderMock, "", environmentMock); } @Test diff --git a/client/src/test/java/de/fitko/fitconnect/client/SubscriberClientTest.java b/client/src/test/java/de/fitko/fitconnect/client/SubscriberClientTest.java index 5be1c68b13ab69d749585b26568afd5f95ec28c5..8469c78a8a0bae4632c180dda3e7bb7514dff9b2 100644 --- a/client/src/test/java/de/fitko/fitconnect/client/SubscriberClientTest.java +++ b/client/src/test/java/de/fitko/fitconnect/client/SubscriberClientTest.java @@ -14,12 +14,11 @@ import de.fitko.fitconnect.api.domain.validation.ValidationResult; import de.fitko.fitconnect.api.exceptions.*; import de.fitko.fitconnect.api.services.Subscriber; import de.fitko.fitconnect.api.services.crypto.CryptoService; +import de.fitko.fitconnect.client.testutil.LogCaptor; import de.fitko.fitconnect.core.crypto.HashService; import de.fitko.fitconnect.core.crypto.JWECryptoService; -import io.github.netmikey.logunit.api.LogCapturer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mockito; import java.io.File; @@ -27,10 +26,7 @@ import java.io.IOException; import java.net.URI; import java.nio.file.Files; import java.text.ParseException; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -41,8 +37,8 @@ import static org.mockito.Mockito.*; public class SubscriberClientTest { public static final ObjectMapper mapper = new ObjectMapper(); - @RegisterExtension - LogCapturer logs = LogCapturer.create().captureForType(SubscriberClient.class); + + private final LogCaptor logs = new LogCaptor(); private Subscriber subscriberMock; private String privateKey; diff --git a/client/src/test/java/de/fitko/fitconnect/client/cmd/CommandLineClientTest.java b/client/src/test/java/de/fitko/fitconnect/client/cmd/CommandLineClientTest.java index 3b5053dc1bf9da4bcd8823ad7278b186c3d564a2..2643026bb0804eabb4d39533642a7db29826436f 100644 --- a/client/src/test/java/de/fitko/fitconnect/client/cmd/CommandLineClientTest.java +++ b/client/src/test/java/de/fitko/fitconnect/client/cmd/CommandLineClientTest.java @@ -1,5 +1,7 @@ package de.fitko.fitconnect.client.cmd; +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; import de.fitko.fitconnect.api.domain.model.metadata.attachment.Attachment; import de.fitko.fitconnect.api.domain.model.metadata.attachment.AttachmentWithData; import de.fitko.fitconnect.api.domain.model.metadata.data.MimeType; @@ -8,17 +10,14 @@ import de.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import de.fitko.fitconnect.client.SenderClient; import de.fitko.fitconnect.client.SubscriberClient; import de.fitko.fitconnect.client.SubscriberClient.ReceivedSubmission; -import io.github.netmikey.logunit.api.LogCapturer; +import de.fitko.fitconnect.client.testutil.LogCaptor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.io.TempDir; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.PrintStream; -import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -30,8 +29,7 @@ import static org.mockito.Mockito.when; class CommandLineClientTest { - @RegisterExtension - LogCapturer logs = LogCapturer.create().captureForType(CommandLineClient.class); + private final LogCaptor logs = new LogCaptor(); ByteArrayOutputStream sysoutCaptor = new ByteArrayOutputStream(); diff --git a/client/src/test/java/de/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java b/client/src/test/java/de/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..55c06040ff2c9482b11a2ccdd13d58969e1a5f07 --- /dev/null +++ b/client/src/test/java/de/fitko/fitconnect/client/factory/ApplicationConfigLoaderTest.java @@ -0,0 +1,54 @@ +package de.fitko.fitconnect.client.factory; + +import de.fitko.fitconnect.api.config.ApplicationConfig; +import de.fitko.fitconnect.api.config.Environment; +import de.fitko.fitconnect.api.config.SenderConfig; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +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.equalTo; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ApplicationConfigLoaderTest { + + @Test + void testLoadMissingConfigFile(){ + Assertions.assertThrows(IOException.class, () -> ApplicationConfigLoader.loadConfig(Path.of("/no/path"))); + } + + @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://submission-api-testing.fit-connect.fitko.dev", + true + ); + + final SenderConfig senderConfig = new SenderConfig("1", "123"); + + // When + final ApplicationConfig testConfig = ApplicationConfigLoader.loadConfig(testConfigYaml); + + // Then + assertNotNull(testConfig); + assertThat(testConfig.getCurrentEnvironment(), equalTo(devEnv)); + assertThat(testConfig.getSenderConfig(), equalTo(senderConfig)); + } + + 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/de/fitko/fitconnect/client/factory/ClientFactoryTest.java b/client/src/test/java/de/fitko/fitconnect/client/factory/ClientFactoryTest.java index af7d628c929eb1c56ee50218518520c7aa8ff8d5..c1be40f038f1296e5f441954343d02951ccf71cd 100644 --- a/client/src/test/java/de/fitko/fitconnect/client/factory/ClientFactoryTest.java +++ b/client/src/test/java/de/fitko/fitconnect/client/factory/ClientFactoryTest.java @@ -3,7 +3,8 @@ package de.fitko.fitconnect.client.factory; import de.fitko.fitconnect.api.config.*; import org.junit.jupiter.api.Test; -import static de.fitko.fitconnect.api.config.UsedEnvironment.DEV; +import java.util.Map; + import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -18,26 +19,22 @@ public class ClientFactoryTest { @Test public void testSenderClientConstruction() { - final var devEnvironment = new Environment(); - devEnvironment.setAuthBaseUrl("https://auth"); - - final var environments = new Environments(); - environments.setDev(devEnvironment); + final var envName = new EnvironmentName("DEV"); + final var environments = Map.of(envName, new Environment("https://auth", "", true)); - final var sender = new Sender(); - sender.setClientSecret("123"); - sender.setClientSecret("abc"); + final var sender = new SenderConfig("123", "abc"); final var resourcePaths = new ResourcePaths(); resourcePaths.setAuthTokenPath("/token"); - final var senderConfig = new ApplicationConfig(); - senderConfig.setHttpProxyHost("https://proxy.fitco.de"); - senderConfig.setHttpProxyPort(0); - senderConfig.setEnvironments(environments); - senderConfig.setSender(sender); - senderConfig.setUsedEnvironment(DEV); - senderConfig.setResourcePaths(resourcePaths); + final var senderConfig = ApplicationConfig.builder() + .httpProxyHost("https://proxy.fitco.de") + .httpProxyPort(0) + .environments(environments) + .senderConfig(sender) + .resourcePaths(resourcePaths) + .activeEnvironment(envName) + .build(); senderConfig.setMetadataSchemaPath("src/test/resources/metadata_schema.json"); senderConfig.setPrivateSigningKeyPath("src/test/resources/private_test_signing_key.json"); @@ -46,29 +43,29 @@ public class ClientFactoryTest { @Test public void testSubscriberClientConstruction() { - final var devEnvironment = new Environment(); - devEnvironment.setAuthBaseUrl("https://auth"); - final var environments = new Environments(); - environments.setDev(devEnvironment); + final var envName = new EnvironmentName("DEV"); + final var environments = Map.of(envName, new Environment("https://auth", "", true)); final var resourcePaths = new ResourcePaths(); resourcePaths.setAuthTokenPath("/token"); - final var subscriber = new Subscriber(); - subscriber.setClientSecret("123"); - subscriber.setClientSecret("abc"); - subscriber.setPrivateDecryptionKeyPath("src/test/resources/private_decryption_test_key.json"); - - final var subscriberConfig = new ApplicationConfig(); - subscriberConfig.setHttpProxyHost("https://proxy.fitco.de"); - subscriberConfig.setHttpProxyPort(0); - subscriberConfig.setEnvironments(environments); - subscriberConfig.setSubscriber(subscriber); - subscriberConfig.setUsedEnvironment(DEV); - subscriberConfig.setResourcePaths(resourcePaths); - subscriberConfig.setMetadataSchemaPath("src/test/resources/metadata_schema.json"); - subscriberConfig.setPrivateSigningKeyPath("src/test/resources/private_test_signing_key.json"); + final var subscriber = SubscriberConfig.builder() + .clientSecret("123") + .clientSecret("abc") + .privateDecryptionKeyPath("src/test/resources/private_decryption_test_key.json") + .build(); + + final var subscriberConfig = ApplicationConfig.builder() + .httpProxyHost("https://proxy.fitco.de") + .httpProxyPort(0) + .environments(environments) + .subscriberConfig(subscriber) + .resourcePaths(resourcePaths) + .activeEnvironment(envName) + .privateSigningKeyPath("src/test/resources/private_test_signing_key.json") + .metadataSchemaPath("src/test/resources/metadata_schema.json") + .build(); assertNotNull(ClientFactory.subscriberClient(subscriberConfig)); } diff --git a/client/src/test/java/de/fitko/fitconnect/client/testutil/LogCaptor.java b/client/src/test/java/de/fitko/fitconnect/client/testutil/LogCaptor.java new file mode 100644 index 0000000000000000000000000000000000000000..10e4d69ed685da19e107571f357480459d383368 --- /dev/null +++ b/client/src/test/java/de/fitko/fitconnect/client/testutil/LogCaptor.java @@ -0,0 +1,21 @@ +package de.fitko.fitconnect.client.testutil; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; + +import java.util.ArrayList; +import java.util.List; + +public class LogCaptor extends AppenderBase<LoggingEvent> { + + private static final List<LoggingEvent> events = new ArrayList<>(); + + @Override + protected void append(final LoggingEvent e) { + events.add(e); + } + + public boolean assertContains(final String s){ + return events.stream().map(LoggingEvent::getMessage).anyMatch(m -> m.contains(s)); + } +} \ No newline at end of file diff --git a/client/src/test/resources/sdk-test.conf b/client/src/test/resources/sdk-test.conf deleted file mode 100644 index ac26f2f297af7e9ecf72190394114dbaa8bb0a46..0000000000000000000000000000000000000000 --- a/client/src/test/resources/sdk-test.conf +++ /dev/null @@ -1,48 +0,0 @@ -# SKD application properties and global configurations -sdk { - - # Credentials to authenticate via OAuth - sender { - clientId: "123" - clientSecret: "abc" - } - - subscriber { - clientId: "456" - clientSecret: "def" - - # Path that references the private key file - privateDecryptionKeyPath: "client/src/test/java/resources/private_decryption_test_key.json" - - # Path that references the signing key file - privateSigningKeyPath: "client/src/test/java/resources/private_test_signing_key.json" - - # Enviroment var name that references the metadata schema - metadataSchemaPath: "client/src/test/java/resources/metadata_schema.json" - securityEventTokenSchemaPath: "" - } - - # Proxy config for http api calls - httpProxyHost: "" - httpProxyPort: 0 - requestTimeoutInSeconds: 30 - - # switch between the active environments DEV, PROD or TEST - usedEnvironment: "DEV" - - # Configured environments for all api-urls - environments { - dev { - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev", - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - } - prod { - authBaseUrl: "https://auth-prod.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.dev" - } - test { - authBaseUrl: "https://auth-test.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - } - } -} diff --git a/client/src/test/resources/test-config.yml b/client/src/test/resources/test-config.yml new file mode 100644 index 0000000000000000000000000000000000000000..5d8a7871ba1895bc6770f855c13959277a232de4 --- /dev/null +++ b/client/src/test/resources/test-config.yml @@ -0,0 +1,61 @@ +# Proxy config for http api calls +httpProxyHost: "" +httpProxyPort: 0 +requestTimeoutInSeconds: 30 + +# Name/key of the used environment +activeEnvironment: dev + +# Path that references the signing key file +privateSigningKeyPath: "client/src/test/java/resources/private_test_signing_key.json" + +# Path that references the metadata schema +metadataSchemaPath: "client/src/test/java/resources/metadata_schema.json" + +# Sender Config +senderConfig: + clientId: "1" + clientSecret: "123" + +# Subscriber Config +subscriberConfig: + clientId: "2" + clientSecret: "456" + + # Path that references the private key file + privateDecryptionKeyPath: "client/src/test/java/resources/private_decryption_test_key.json" + + securityEventTokenSchemaPath: "" + +# Configured environments for all api-urls +environments: + prod: + authBaseUrl: "https://auth-prod.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.dev" + silentKeyValidation: false + staging: + authBaseUrl: "https://auth-prod.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.dev" + silentKeyValidation: false + dev: + authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" + silentKeyValidation: true + testing: + authBaseUrl: "https://auth-test.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" + silentKeyValidation: true + local: + authBaseUrl: "https://auth-test.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" + silentKeyValidation: true + +# REST Endpoints for FIT-Connect resources +resourcePaths: + authTokenPath: "/token" + destinationPath: "/v1/destinations/{destinationId}" + destinationKeyPath: "/v1/destinations/{destinationId}/keys/{kid}" + eventLogPath: "/v1/cases/{caseId}/events" + submissionPath: "/v1/submissions/{submissionId}" + submissionsPath: "/v1/submissions" + submissionAttachmentPath: "/v1/submissions/{submissionId}/attachments/{attachmentId}" \ No newline at end of file diff --git a/config.yml b/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..31dff9fba2c62f4314c185b93f902e70ad2d25fa --- /dev/null +++ b/config.yml @@ -0,0 +1,60 @@ +# Proxy config for http api calls +httpProxyHost: "" +httpProxyPort: 0 +requestTimeoutInSeconds: 30 + +# Name/key of the used environment (from environments config below) +activeEnvironment: dev + +# Path that references the metadata schema +metadataSchemaPath: "path/to/metadata_schema.json" + +# Path that references the signing key file +privateSigningKeyPath: "path/to/singning_key.json" + +# Sender Config +sender: + clientId: "SenderClientID" + clientSecret: "SenderSecret" + +# Subscriber Config +subscriber: + clientId: "SubscriberClientID" + clientSecret: "SubscriberSecret" + + # Path that references the private key file + privateDecryptionKeyPath: "path/to/decrpytion_key.json" + securityEventTokenSchemaPath: "" + +# Configured environments for all api-urls +environments: + prod: + authBaseUrl: "https://auth-prod.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.dev" + silentKeyValidation: false + staging: + authBaseUrl: "https://auth-prod.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.dev" + silentKeyValidation: false + dev: + authBaseUrl: "https://auth-testing.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" + silentKeyValidation: true + testing: + authBaseUrl: "https://auth-test.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" + silentKeyValidation: true + local: + authBaseUrl: "https://auth-test.fit-connect.fitko.dev" + submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" + silentKeyValidation: true + +# REST Endpoints for FIT-Connect resources +resourcePaths: + authTokenPath: "/token" + destinationPath: "/v1/destinations/{destinationId}" + destinationKeyPath: "/v1/destinations/{destinationId}/keys/{kid}" + eventLogPath: "/v1/cases/{caseId}/events" + submissionPath: "/v1/submissions/{submissionId}" + submissionsPath: "/v1/submissions" + submissionAttachmentPath: "/v1/submissions/{submissionId}/attachments/{attachmentId}" \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml index d5304944f1521db9346eaf3291fbdb8d621414ff..aa2b7292c8ce982116aaca496507b6506239945d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -17,6 +17,10 @@ <groupId>de.fitko.fitconnect.sdk</groupId> <artifactId>api</artifactId> </dependency> + <dependency> + <groupId>dev.fitko.fitconnect</groupId> + <artifactId>jwkvalidator</artifactId> + </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> @@ -37,11 +41,6 @@ <groupId>com.networknt</groupId> <artifactId>json-schema-validator</artifactId> </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> @@ -49,6 +48,11 @@ </dependency> <!-- Tests --> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> @@ -66,6 +70,4 @@ </dependency> </dependencies> - - </project> \ No newline at end of file diff --git a/core/src/main/java/de/fitko/fitconnect/core/util/Strings.java b/core/src/main/java/de/fitko/fitconnect/core/util/Strings.java index 5633dbaf202cc080b9cdb319b653928ca043dae1..22fce6c7c3a02e9fbc67ab5ce299690d076b52a9 100644 --- a/core/src/main/java/de/fitko/fitconnect/core/util/Strings.java +++ b/core/src/main/java/de/fitko/fitconnect/core/util/Strings.java @@ -10,4 +10,14 @@ public class Strings { public static boolean isNullOrEmpty(final String s){ return s == null || s.isEmpty(); } + + /** + * Tests a given string on not null and not empty + * @param s string to test + * @return true if the string is not null AND not empty, false if one condition does not apply + */ + public static boolean isNotNullOrEmpty(final String s){ + return !isNullOrEmpty(s); + } + } diff --git a/core/src/main/java/de/fitko/fitconnect/core/validation/DefaultValidationService.java b/core/src/main/java/de/fitko/fitconnect/core/validation/DefaultValidationService.java index 1334d3a6bb38ad68b5b47029704bf7b9a93931dc..313f037aba413c6b511f5a0dd9bebd288612aff3 100644 --- a/core/src/main/java/de/fitko/fitconnect/core/validation/DefaultValidationService.java +++ b/core/src/main/java/de/fitko/fitconnect/core/validation/DefaultValidationService.java @@ -8,29 +8,52 @@ import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.SpecVersion; import com.networknt.schema.ValidationMessage; import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.util.Base64; +import de.fitko.fitconnect.api.config.ApplicationConfig; import de.fitko.fitconnect.api.domain.model.metadata.Metadata; import de.fitko.fitconnect.api.domain.validation.ValidationResult; import de.fitko.fitconnect.api.exceptions.DataIntegrityException; import de.fitko.fitconnect.api.exceptions.ValidationException; import de.fitko.fitconnect.api.services.crypto.MessageDigestService; import de.fitko.fitconnect.api.services.validation.ValidationService; +import de.fitko.fitconnect.core.util.Strings; +import dev.fitko.fitconnect.jwkvalidator.JWKValidationException; +import dev.fitko.fitconnect.jwkvalidator.JWKValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class DefaultValidationService implements ValidationService { + private static final Logger logger = LoggerFactory.getLogger(DefaultValidationService.class); + private final MessageDigestService messageDigestService; + private final ApplicationConfig config; - public DefaultValidationService(final MessageDigestService messageDigestService) { + public DefaultValidationService(final MessageDigestService messageDigestService, final ApplicationConfig config) { this.messageDigestService = messageDigestService; + this.config = config; } @Override public ValidationResult validatePublicKey(final RSAKey publicKey) { - // TODO: Call to external Lib - // Will be implemented in dedicated validation lib from Zustelldienst - // That lib is still under development and its API should be used here to call the actual validation + try { + if (keyHasNoCertificateChain(publicKey)) { + validateWithoutCertChain(publicKey); + } else { + validateCertChain(publicKey); + } + } catch (final JWKValidationException | CertificateEncodingException e) { + return ValidationResult.error(e); + } return ValidationResult.ok(); } @@ -50,6 +73,14 @@ public class DefaultValidationService implements ValidationService { } } + @Override + public ValidationResult validateIntegrity(final String originalHexHash, final byte[] data) { + final byte[] originalHash = messageDigestService.fromHexString(originalHexHash); + final boolean hashesAreEqual = messageDigestService.verify(originalHash, data); + return hashesAreEqual ? ValidationResult.ok() : ValidationResult.error(new DataIntegrityException( + "Hash sum of transmitted data does not equal the hash of the sender.")); + } + private ValidationResult returnValidationResult(final Set<ValidationMessage> errors) { if (errors.isEmpty()) { return ValidationResult.ok(); @@ -60,11 +91,60 @@ public class DefaultValidationService implements ValidationService { return ValidationResult.error(new ValidationException(validationErrors)); } - @Override - public ValidationResult validateIntegrity(final String originalHexHash, final byte[] data) { - final byte[] originalHash = messageDigestService.fromHexString(originalHexHash); - final boolean hashesAreEqual = messageDigestService.verify(originalHash, data); - return hashesAreEqual ? ValidationResult.ok() : ValidationResult.error(new DataIntegrityException( - "Hash sum of transmitted data does not equal the hash of the sender.")); + private void validateWithX509AndProxy(final List<String> pemCerts, final RSAKey publicKey) throws JWKValidationException { + final var proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getHttpProxyHost(), config.getHttpProxyPort())); + logger.info("Using proxy {} for key validation", proxy); + JWKValidator.withX5CValidation() + .withProxy(proxy) + .withRootCertificatesAsPEM(pemCerts) + .withThrowingExceptions() + .build() + .validate(publicKey); } + + private void validateWithX509AndWithoutProxy(final List<String> pemCerts, final RSAKey publicKey) throws JWKValidationException { + logger.info("No proxy set for validation"); + JWKValidator.withX5CValidation() + .withoutProxy() + .withRootCertificatesAsPEM(pemCerts) + .withThrowingExceptions() + .build() + .validate(publicKey); + } + + private void validateWithoutCertChain(final RSAKey publicKey) throws JWKValidationException { + logger.info("Validation public key without XC5 certificate chain"); + JWKValidator.withoutX5CValidation().build().validate(publicKey); + } + + private void validateCertChain(final RSAKey publicKey) throws JWKValidationException, CertificateEncodingException { + final List<String> pemCerts = getPemCerts(publicKey.getParsedX509CertChain()); + logger.info("Validation public key with XC5 certificate chain checks"); + if (isProxySet()) { + validateWithX509AndProxy(pemCerts, publicKey); + } else { + validateWithX509AndWithoutProxy(pemCerts, publicKey); + } + } + + private List<String> getPemCerts(final List<X509Certificate> certChain) throws CertificateEncodingException { + final List<String> pemCerts = new ArrayList<>(); + for (final X509Certificate cert : certChain) { + pemCerts.add(getEncodedString(cert)); + } + return pemCerts; + } + + private String getEncodedString(final X509Certificate x509Certificate) throws CertificateEncodingException { + return Base64.encode(x509Certificate.getEncoded()).toString(); + } + + private boolean isProxySet() { + return config.getHttpProxyPort() != null && Strings.isNotNullOrEmpty(config.getHttpProxyHost()); + } + + private boolean keyHasNoCertificateChain(final RSAKey publicKey) { + return publicKey.getParsedX509CertChain() == null || publicKey.getX509CertChain().isEmpty(); + } + } diff --git a/core/src/test/java/de/fitko/fitconnect/core/RestEndpointBase.java b/core/src/test/java/de/fitko/fitconnect/core/RestEndpointBase.java index 79c776bbea3686141b31bbd15d7b0b44c0c1c380..31cf5323aa6fe6a6ace5064e205ced7d7d7334d0 100644 --- a/core/src/test/java/de/fitko/fitconnect/core/RestEndpointBase.java +++ b/core/src/test/java/de/fitko/fitconnect/core/RestEndpointBase.java @@ -4,6 +4,8 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import de.fitko.fitconnect.api.config.*; +import java.util.Map; + import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; public abstract class RestEndpointBase { @@ -17,28 +19,25 @@ public abstract class RestEndpointBase { } protected ApplicationConfig getTestConfig(final String fakeBaseUrl) { - final var testEnv = new Environment(); - testEnv.setSubmissionBaseUrl(fakeBaseUrl); - testEnv.setAuthBaseUrl(fakeBaseUrl); - - final var environments = new Environments(); - environments.setTest(testEnv); - - final var resourcePaths = new ResourcePaths(); - resourcePaths.setAuthTokenPath("/token"); - resourcePaths.setDestinationPath("/v1/destinations/{destinationId}"); - resourcePaths.setDestinationKeyPath("/v1/destinations/{destinationId}/keys/{kid}"); - resourcePaths.setEventLogPath("/v1/cases/{caseId}/events"); - resourcePaths.setSubmissionsPath("/v1/submissions"); - resourcePaths.setSubmissionPath("/v1/submissions/{submissionId}"); - resourcePaths.setSubmissionAttachmentPath("/v1/submissions/{submissionId}/attachments/{attachmentId}"); - - final var config = new ApplicationConfig(); - config.setUsedEnvironment(UsedEnvironment.TEST); - config.setEnvironments(environments); - config.setResourcePaths(resourcePaths); - - return config; + + final var envName = new EnvironmentName("TESTING"); + final var environments = Map.of(envName, new Environment(fakeBaseUrl, fakeBaseUrl, false)); + + final var resourcePaths = ResourcePaths.builder() + .authTokenPath("/token") + .destinationPath("/v1/destinations/{destinationId}") + .destinationKeyPath("/v1/destinations/{destinationId}/keys/{kid}") + .eventLogPath("/v1/cases/{caseId}/events") + .submissionsPath("/v1/submissions") + .submissionPath("/v1/submissions/{submissionId}") + .submissionAttachmentPath("/v1/submissions/{submissionId}/attachments/{attachmentId}") + .build(); + + return ApplicationConfig.builder() + .environments(environments) + .activeEnvironment(envName) + .resourcePaths(resourcePaths) + .build(); } } diff --git a/core/src/test/java/de/fitko/fitconnect/core/SubmissionSenderTest.java b/core/src/test/java/de/fitko/fitconnect/core/SubmissionSenderTestConfig.java similarity index 98% rename from core/src/test/java/de/fitko/fitconnect/core/SubmissionSenderTest.java rename to core/src/test/java/de/fitko/fitconnect/core/SubmissionSenderTestConfig.java index 7cbdc8e37f86f545fc13479e4da0b4fb0dae2217..4af26b5ae718898141508e9c2354ed39554989bf 100644 --- a/core/src/test/java/de/fitko/fitconnect/core/SubmissionSenderTest.java +++ b/core/src/test/java/de/fitko/fitconnect/core/SubmissionSenderTestConfig.java @@ -39,7 +39,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -public class SubmissionSenderTest { +public class SubmissionSenderTestConfig { private DestinationService destinationServiceMock; private SubmissionService submissionServiceMock; @@ -313,6 +313,6 @@ public class SubmissionSenderTest { } private String getResourceAsString(final String filename) throws IOException { - return new String(SubmissionSenderTest.class.getResourceAsStream(filename).readAllBytes()); + return new String(SubmissionSenderTestConfig.class.getResourceAsStream(filename).readAllBytes()); } } \ No newline at end of file diff --git a/core/src/test/java/de/fitko/fitconnect/core/testutil/LogCaptor.java b/core/src/test/java/de/fitko/fitconnect/core/testutil/LogCaptor.java new file mode 100644 index 0000000000000000000000000000000000000000..1089bf85d94819e2e8bd9abcb365e07a95f785ae --- /dev/null +++ b/core/src/test/java/de/fitko/fitconnect/core/testutil/LogCaptor.java @@ -0,0 +1,21 @@ +package de.fitko.fitconnect.core.testutil; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; + +import java.util.ArrayList; +import java.util.List; + +public class LogCaptor extends AppenderBase<LoggingEvent> { + + private static final List<LoggingEvent> events = new ArrayList<>(); + + @Override + protected void append(final LoggingEvent e) { + events.add(e); + } + + public boolean assertContains(final String s){ + return events.stream().map(LoggingEvent::getMessage).anyMatch(m -> m.contains(s)); + } +} \ No newline at end of file diff --git a/core/src/test/java/de/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java b/core/src/test/java/de/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java index 11b226effb0dab8a9f6e564616ec95b4b307e140..81547def95fdae87751fd5a2b14c7a2b89023040 100644 --- a/core/src/test/java/de/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java +++ b/core/src/test/java/de/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java @@ -1,45 +1,57 @@ package de.fitko.fitconnect.core.validation; import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWEAlgorithm; +import com.nimbusds.jose.jwk.KeyOperation; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jose.util.Base64; +import com.nimbusds.jose.util.Base64URL; +import de.fitko.fitconnect.api.config.ApplicationConfig; import de.fitko.fitconnect.api.domain.model.metadata.ContentStructure; import de.fitko.fitconnect.api.domain.model.metadata.Metadata; import de.fitko.fitconnect.api.domain.model.metadata.data.*; import de.fitko.fitconnect.api.domain.validation.ValidationResult; import de.fitko.fitconnect.api.services.crypto.MessageDigestService; import de.fitko.fitconnect.api.services.validation.ValidationService; +import de.fitko.fitconnect.core.testutil.LogCaptor; import de.fitko.fitconnect.core.crypto.HashService; +import dev.fitko.fitconnect.jwkvalidator.JWKValidationException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.URI; -import java.util.Collections; -import java.util.UUID; +import java.util.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertTrue; public class DefaultValidationServiceTest { - ValidationService underTest; - MessageDigestService hashService; + private ValidationService underTest; + private MessageDigestService hashService; + + private final LogCaptor logs = new LogCaptor(); @BeforeEach void setUp() { + final var config = ApplicationConfig.builder().build(); + hashService = new HashService(); - underTest = new DefaultValidationService(hashService); + underTest = new DefaultValidationService(hashService, config); } @Test - public void validatePublicKey() throws JOSEException { + public void testValidKeyWithoutX509CertChain() throws JOSEException { //Given - final RSAKey rsaKey = new RSAKeyGenerator(2048) - .keyUse(KeyUse.ENCRYPTION) + final RSAKey rsaKey = new RSAKeyGenerator(4096) + .keyOperations(Set.of(KeyOperation.ENCRYPT)) + .algorithm(JWEAlgorithm.RSA_OAEP_256) .keyID(UUID.randomUUID().toString()) .generate(); @@ -50,6 +62,46 @@ public class DefaultValidationServiceTest { assertTrue(validationResult.isValid()); } + @Test + public void testInvalidKeyWithWrongAlgorithm() throws JOSEException { + + //Given + final RSAKey rsaKey = new RSAKeyGenerator(4096) + .keyOperations(Set.of(KeyOperation.WRAP_KEY)) + .algorithm(JWEAlgorithm.NONE) + .keyID(UUID.randomUUID().toString()) + .generate(); + + // When + final ValidationResult validationResult = underTest.validatePublicKey(rsaKey); + + // Then + assertTrue(validationResult.hasError()); + assertThat(validationResult.getError(), instanceOf(JWKValidationException.class)); + assertThat(validationResult.getError().getMessage(), containsString("JWK with id " + rsaKey.getKeyID() + " is of type wrapKey but has wrong Alg")); + } + + @Test + public void testValidationWithProxy() { + + //Given + final var config = ApplicationConfig.builder() + .httpProxyHost("https://localhost") + .httpProxyPort(8080) + .build(); + + final DefaultValidationService underTest = new DefaultValidationService(new HashService(), config); + + final RSAKey rsaKey = getRsaKeyWithCertChain(); + + // When + underTest.validatePublicKey(rsaKey); + + // Then + logs.assertContains("Using proxy HTTP @ https://localhost/<unresolved>:8080 for key validation"); + } + + @Test public void validateMetadata() throws IOException { @@ -173,4 +225,22 @@ public class DefaultValidationServiceTest { private String getSchema(final String filename) throws IOException { return new String(DefaultValidationServiceTest.class.getResourceAsStream(filename).readAllBytes()); } + + private RSAKey getRsaKeyWithCertChain() { + return new RSAKey( + Base64URL.from("oSi83-NRxxJ2LG7cWt623K8d1TTc32b2zMOEeBYTvYY9fbPOo-qUpM00e_Q23GajPWkQkZSHllvFXz0E4e9LWc2LVkewDqQc3Usy34NjLLQ6zBr6TZoBwZQv2X65ll8e7nSL9JZyfX_Gde37_wtK5waO483Pwk7cg_zA4XwuxpdKaexErRay7Kd7W3v9Gn61BplFV3zaQ3FIWHMLyj8GyH33UVYnCw7iIUuvGrQG2vEac3Ivx7ObdQ-gRS75n6G3AEouerayFdNkXW12Hz2MDR9QvlA7ZZtQ0_Dq8YgHYqh6A-hXgcXtqrW87l-bph18Zi5RtIPv39VgKgELYm9nnZbVavnfhIt2mJRFjfYnW1GD1E8rkC58-CV4lgzZ5ntQahGOhpsCAckJGlEviefe2HpQ0JEb-pfp-LTe1bycRmkcqaBhfl0Acoayfu48wsZgL9EAUG-1RzFK07EgyMFkpppYpa62Np47gbPJI5vlLY6zRcVGR6y6V2b67X_F-tCLte4XaCHbD0EH59t7ITp44q5qdSP6fMcsG3pSGTU5VoTkpc8BJ43dvufhVJaBL73U32VMBzOTVg6w0nSAuXx8FL4v6lSLfPCDqSEzQl0QKIgF9F2g8sVzhaRKPapRXEcAI9Y2_6WPjVCe7QBcWmI6jGhLQGYy42n1fgI7NyNHkF8"), + Base64URL.from("AQAB"), + KeyUse.ENCRYPTION, + Set.of(KeyOperation.WRAP_KEY), + JWEAlgorithm.RSA_OAEP_256, + "LM0FPR9i-Yg1Cks-f_HG4dHocwLc2MU3rigME-Uc1Lc-wrapKey", + null, null, null, + List.of( + Base64.from("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"), + Base64.from("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"), + Base64.from("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") + ), + null + ); + } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 17226c323f74c0af1b89960adb281da6482631d4..3501ca2795518ca914c90696642c56377ae4122c 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,9 @@ <project.build.sourceEncoding>${encoding}</project.build.sourceEncoding> <project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding> + <!-- FIT-Connect dependencies --> + <jwk-validator.version>1.0.0-SNAPSHOT</jwk-validator.version> + <!-- 3rd party dependencies --> <nimbus.version>9.24.3</nimbus.version> <jackson.version>2.13.4</jackson.version> @@ -26,11 +29,10 @@ <jcommander.version>1.82</jcommander.version> <apache-tika.version>2.4.1</apache-tika.version> <spring-web.version>5.3.22</spring-web.version> - <typesafe-config.version>1.4.2</typesafe-config.version> + <snakeyaml.version>1.31</snakeyaml.version> <json-schema-validator.version>1.0.72</json-schema-validator.version> <junit.version>5.9.0</junit.version> - <logunit.version>1.1.3</logunit.version> <mockito.version>4.7.0</mockito.version> <wiremock.version>2.27.2</wiremock.version> <hamcrest.version>1.3</hamcrest.version> @@ -38,6 +40,7 @@ <maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version> <maven-failsafe-plugin.version>3.0.0-M7</maven-failsafe-plugin.version> <maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version> + </properties> <modules> @@ -67,6 +70,12 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>dev.fitko.fitconnect</groupId> + <artifactId>jwkvalidator</artifactId> + <version>${jwk-validator.version}</version> + </dependency> + <!-- 3rd Party Dependencies --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> @@ -105,9 +114,9 @@ <version>${jcommander.version}</version> </dependency> <dependency> - <groupId>com.typesafe</groupId> - <artifactId>config</artifactId> - <version>${typesafe-config.version}</version> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + <version>${snakeyaml.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> @@ -153,15 +162,16 @@ <version>${wiremock.version}</version> <scope>test</scope> </dependency> - <dependency> - <groupId>io.github.netmikey.logunit</groupId> - <artifactId>logunit-logback</artifactId> - <version>${logunit.version}</version> - <scope>test</scope> - </dependency> </dependencies> </dependencyManagement> + <repositories> + <repository> + <id>maven-snapshots</id> + <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url> + </repository> + </repositories> + <build> <plugins> <plugin> diff --git a/sdk.conf b/sdk.conf deleted file mode 100644 index a099696393950820a462154ae1dffbcf3c9cd71a..0000000000000000000000000000000000000000 --- a/sdk.conf +++ /dev/null @@ -1,63 +0,0 @@ -# SKD application properties and global configurations -sdk { - - # Proxy config for http api calls - httpProxyHost: "" - httpProxyPort: 0 - requestTimeoutInSeconds: 30 - - # Path that references the metadata schema - metadataSchemaPath: "path/to/metadata_schema.json" - - # Path that references the signing key file - privateSigningKeyPath: "path/to/singning_key.json" - - # switch between the active environments DEV, PROD or TEST - usedEnvironment: "DEV" - - # Credentials to authenticate via OAuth - sender { - clientId: "SenderClientID" - clientSecret: "SenderSecret" - } - - subscriber { - clientId: "SubscriberClientID" - clientSecret: "SubscriberSecret" - - # Path that references the private key file - privateDecryptionKeyPath: "path/to/decrpytion_key.json" - - securityEventTokenSchemaPath: "" - } - - # Configured environments for all api-urls - environments { - dev { - authBaseUrl: "https://auth-testing.fit-connect.fitko.dev", - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - } - prod { - authBaseUrl: "https://auth-prod.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-prod.fit-connect.fitko.dev" - } - test { - authBaseUrl: "https://auth-test.fit-connect.fitko.dev" - submissionBaseUrl: "https://submission-api-testing.fit-connect.fitko.dev" - } - } - - # REST endpoint paths - resourcePaths { - authTokenPath: "/token" - - destinationPath: "/v1/destinations/{destinationId}" - destinationKeyPath: "/v1/destinations/{destinationId}/keys/{kid}" - - eventLogPath: "/v1/cases/{caseId}/events" - - submissionPath: "/v1/submissions/{submissionId}" - submissionsPath: "/v1/submissions" - submissionAttachmentPath: "/v1/submissions/{submissionId}/attachments/{attachmentId}" - } -}