Skip to content
Snippets Groups Projects
Commit 9e35e7c2 authored by Jan Zickermann's avatar Jan Zickermann
Browse files

OZG-4097 Delay validation of api client configuration

parent 141f040f
No related branches found
No related tags found
No related merge requests found
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);
}
}
......@@ -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";
......
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("");
}
}
......@@ -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");
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment