From 9e35e7c26a710839829aa6493dcec2bfc9fe07f1 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Tue, 4 Mar 2025 12:50:39 +0100 Subject: [PATCH] OZG-4097 Delay validation of api client configuration --- .../osiv2/config/ApiClientConfiguration.java | 45 ++++++++++++++++++ .../osiv2/config/Osi2PostfachProperties.java | 6 --- .../osiv2/config/Osi2PropertiesValidator.java | 47 ------------------- ...t.java => ApiClientConfigurationTest.java} | 14 +++--- 4 files changed, 52 insertions(+), 60 deletions(-) delete mode 100644 src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidator.java rename src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/{Osi2PropertiesValidatorTest.java => ApiClientConfigurationTest.java} (90%) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java index d5403ac..af114b9 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfiguration.java @@ -1,5 +1,13 @@ package de.ozgcloud.nachrichten.postfach.osiv2.config; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validator; + import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; @@ -28,11 +36,15 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.nachrichten.postfach.osiv2.gen.ApiClient; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.QuarantineApi; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +@Log4j2 @Configuration @RequiredArgsConstructor @ConditionalOnProperty(prefix = Osi2PostfachProperties.PREFIX, name = "enabled", havingValue = "true") @@ -42,6 +54,8 @@ public class ApiClientConfiguration { private final Osi2PostfachProperties.ApiConfiguration apiConfiguration; private final Osi2PostfachProperties.ProxyConfiguration proxyConfiguration; + private final Validator validator; + private static final String CLIENT_REGISTRATION_ID = "osi2"; @Bean @@ -55,8 +69,11 @@ public class ApiClientConfiguration { } @Bean + @SneakyThrows ApiClient apiClient() { + getErrorMessageOfViolations(); var apiClient = new ApiClient(restClient()); + LOG.debug("Setting api client base path to {}", apiConfiguration.getUrl()); apiClient.setBasePath(apiConfiguration.getUrl()); return apiClient; } @@ -78,6 +95,7 @@ public class ApiClientConfiguration { private ClientHttpRequestFactory createProxyRequestFactory() { var requestFactory = new HttpComponentsClientHttpRequestFactory(); if (proxyConfiguration.isEnabled()) { + LOG.debug("Using proxy configuration: {}:{}", proxyConfiguration.getHost(), proxyConfiguration.getPort()); requestFactory.setHttpClient( HttpClientBuilder.create() .setProxy(new HttpHost(proxyConfiguration.getHost(), proxyConfiguration.getPort())) @@ -93,6 +111,7 @@ public class ApiClientConfiguration { var username = proxyConfiguration.getUsername(); var password = proxyConfiguration.getPassword(); if (username != null && password != null) { + LOG.debug("Using proxy authentication with username {}", username); credentialsProvider.setCredentials(new AuthScope(proxyConfiguration.getHost(), proxyConfiguration.getPort()), new UsernamePasswordCredentials(username, password.toCharArray())); } @@ -116,6 +135,8 @@ public class ApiClientConfiguration { } private ClientRegistration osi2ClientRegistration() { + LOG.debug("Creating client registration with clientId: {}, tokenUri: {}, scope: {}, resource: {}", authConfiguration.getClientId(), + authConfiguration.getTokenUri(), authConfiguration.getScope(), authConfiguration.getResource()); return ClientRegistration.withRegistrationId(CLIENT_REGISTRATION_ID) .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) @@ -161,4 +182,28 @@ public class ApiClientConfiguration { }); } + void getErrorMessageOfViolations() { + String violationMessage = Stream.<Optional<String>>of(getErrorMessageOfViolations(authConfiguration), + getErrorMessageOfViolations(apiConfiguration), + proxyConfiguration.isEnabled() ? getErrorMessageOfViolations(proxyConfiguration) : Optional.empty() + ).flatMap(Optional::stream) + .collect(Collectors.joining(System.lineSeparator())); + + if (!violationMessage.isEmpty()) { + throw new TechnicalException( + "Configuration of api client is invalid:%s%s".formatted(System.lineSeparator(), violationMessage)); + } + } + + private <T> Optional<String> getErrorMessageOfViolations(T configuration) { + return formatConstraintValidation(validator.validate(configuration)) + .map(message -> "%s is invalid: %s".formatted(configuration.getClass().getSimpleName(), message)); + } + + private <T> Optional<String> formatConstraintValidation(Set<ConstraintViolation<T>> constraints) { + return constraints.stream() + .map(violation -> String.format("%s: %s", violation.getPropertyPath(), violation.getMessage())) + .reduce((a, b) -> a + ", " + b); + } + } diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java index d9bce3e..e4b53fb 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PostfachProperties.java @@ -8,7 +8,6 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.context.annotation.Configuration; import lombok.Getter; @@ -18,7 +17,6 @@ import lombok.Setter; @Setter @Configuration @ConfigurationProperties(prefix = Osi2PostfachProperties.PREFIX) -@ConfigurationPropertiesScan public class Osi2PostfachProperties { // From de.ozgcloud.nachrichten.NachrichtenManagerConfiguration public static final String GRPC_FILE_MANAGER_NAME = "file-manager"; @@ -29,12 +27,10 @@ public class Osi2PostfachProperties { private boolean enabled; - @Getter @Setter @Configuration @ConfigurationProperties(prefix = AuthConfiguration.PREFIX) - @ConfigurationPropertiesScan public static class AuthConfiguration { public static final String PREFIX = Osi2PostfachProperties.PREFIX + ".auth"; @@ -55,7 +51,6 @@ public class Osi2PostfachProperties { @Setter @Configuration @ConfigurationProperties(prefix = ApiConfiguration.PREFIX) - @ConfigurationPropertiesScan public static class ApiConfiguration { public static final String PREFIX = Osi2PostfachProperties.PREFIX + ".api"; @@ -75,7 +70,6 @@ public class Osi2PostfachProperties { @Setter @Configuration @ConfigurationProperties(prefix = ProxyConfiguration.PREFIX) - @ConfigurationPropertiesScan public static class ProxyConfiguration { public static final String PREFIX = Osi2PostfachProperties.PREFIX + ".proxy"; diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidator.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidator.java deleted file mode 100644 index 19f2454..0000000 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidator.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.ozgcloud.nachrichten.postfach.osiv2.config; - -import java.util.Set; - -import javax.annotation.PostConstruct; - -import jakarta.validation.ConstraintViolation; -import jakarta.validation.Validator; - -import de.ozgcloud.common.errorhandling.TechnicalException; -import de.ozgcloud.nachrichten.postfach.osiv2.ServiceIfOsi2Enabled; -import lombok.RequiredArgsConstructor; - -@ServiceIfOsi2Enabled -@RequiredArgsConstructor -public class Osi2PropertiesValidator { - - private final Osi2PostfachProperties.AuthConfiguration authConfiguration; - private final Osi2PostfachProperties.ApiConfiguration apiConfiguration; - private final Osi2PostfachProperties.ProxyConfiguration proxyConfiguration; - private final Validator validator; - - @PostConstruct - public void validateConfiguration() { - validateConfiguration(authConfiguration); - validateConfiguration(apiConfiguration); - if (proxyConfiguration.isEnabled()) { - validateConfiguration(proxyConfiguration); - } - } - - private <T> void validateConfiguration(T configuration) { - var violations = validator.validate(configuration); - if (!violations.isEmpty()) { - throw new TechnicalException( - "%s is invalid: %s".formatted(configuration.getClass().getSimpleName(), formatConstraintValidation(violations))); - } - } - - private <T> String formatConstraintValidation(Set<ConstraintViolation<T>> constraints) { - return constraints.stream() - .map(violation -> String.format("%s: %s", violation.getPropertyPath(), violation.getMessage())) - .reduce((a, b) -> a + ", " + b) - .orElse(""); - } -} - diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidatorTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfigurationTest.java similarity index 90% rename from src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidatorTest.java rename to src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfigurationTest.java index 0a22469..95bbcef 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/Osi2PropertiesValidatorTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/config/ApiClientConfigurationTest.java @@ -17,7 +17,7 @@ import org.junit.jupiter.params.provider.MethodSource; import de.ozgcloud.common.errorhandling.TechnicalException; -class Osi2PropertiesValidatorTest { +class ApiClientConfigurationTest { private static final Validator VALIDATOR; @@ -34,27 +34,27 @@ class Osi2PropertiesValidatorTest { @DisplayName("should return if is valid") @Test void shouldReturnIfIsValid() { - var validator = new Osi2PropertiesValidator( + var validator = new ApiClientConfiguration( createAuthConfiguration(), createApiConfiguration(), createProxyConfiguration(), VALIDATOR ); - assertThatCode(validator::validateConfiguration).doesNotThrowAnyException(); + assertThatCode(validator::getErrorMessageOfViolations).doesNotThrowAnyException(); } @DisplayName("should return if is valid with disabled proxy") @Test void shouldReturnIfIsValidWithDisabledProxy() { - var validator = new Osi2PropertiesValidator( + var validator = new ApiClientConfiguration( createAuthConfiguration(), createApiConfiguration(), createDisabledProxyConfiguration(), VALIDATOR ); - assertThatCode(validator::validateConfiguration).doesNotThrowAnyException(); + assertThatCode(validator::getErrorMessageOfViolations).doesNotThrowAnyException(); } static Stream<Arguments> invalidValidatorConfigurations() { @@ -85,14 +85,14 @@ class Osi2PropertiesValidatorTest { Osi2PostfachProperties.ApiConfiguration apiConfiguration, Osi2PostfachProperties.ProxyConfiguration proxyConfiguration ) { - var validator = new Osi2PropertiesValidator( + var validator = new ApiClientConfiguration( authConfiguration, apiConfiguration, proxyConfiguration, VALIDATOR ); - assertThatThrownBy(validator::validateConfiguration) + assertThatThrownBy(validator::getErrorMessageOfViolations) .isInstanceOf(TechnicalException.class) .hasMessageContaining("is invalid"); } -- GitLab