Skip to content
Snippets Groups Projects
Verified Commit d2562eea authored by Sebastian Bergandy's avatar Sebastian Bergandy :keyboard:
Browse files

OZG-7232 add tls

Subtask: OZG-8005
parent 7da9a792
Branches
Tags sprint11_2
1 merge request!4OZG-7232 SmartDocuments zertifikatbasierte Authentifizierung
......@@ -29,12 +29,18 @@ import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.core5.http.HttpHost;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.ssl.NoSuchSslBundleException;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
......@@ -47,6 +53,8 @@ class SmartDocumentsConfiguration {
@Autowired
private SmartDocumentsProperties properties;
@Autowired
private SslBundles sslBundles;
@Bean("smartDocuments")
RestClient smartDocumentsRestClient() {
......@@ -59,17 +67,22 @@ class SmartDocumentsConfiguration {
CloseableHttpClient buildHttpClient() {
if (properties.getProxy() != null) {
return createProxyHttpClient();
return createHttpClientUsingProxy();
}
return createNoProxyHttpClient();
}
HttpClientBuilder createDefulatHttpClientBuilder() {
return HttpClients.custom()
.setConnectionManager(createConnectionManagerWithClientCertificateIfConfigured());
}
CloseableHttpClient createNoProxyHttpClient() {
return HttpClients.createDefault();
return createDefulatHttpClientBuilder().build();
}
CloseableHttpClient createProxyHttpClient() {
return HttpClients.custom()
CloseableHttpClient createHttpClientUsingProxy() {
return createDefulatHttpClientBuilder()
.setRoutePlanner(createProxyRoutePlanner())
.setDefaultCredentialsProvider(createProxyCredentialsProvider())
.build();
......@@ -94,4 +107,17 @@ class SmartDocumentsConfiguration {
}
}
HttpClientConnectionManager createConnectionManagerWithClientCertificateIfConfigured() {
var builder = PoolingHttpClientConnectionManagerBuilder.create();
try {
var sslBundleName = properties.getSslBundleName();
if (Objects.nonNull(sslBundleName)) {
builder.setTlsSocketStrategy(new DefaultClientTlsStrategy(sslBundles.getBundle(sslBundleName).createSslContext()));
}
return builder.build();
} catch (NoSuchSslBundleException e) {
return builder.build();
}
}
}
......@@ -52,10 +52,14 @@ public class SmartDocumentsProperties {
/**
* Credential for basic auth to the Smart Documents Server
*/
@NotNull
@Valid
private UsernamePassword basicAuth;
/**
* Name of SSL bundle need for client certificate authentication.
*/
private String sslBundleName;
/**
* Smart Documents Template Group
*/
......
......@@ -3,19 +3,28 @@ package de.ozgcloud.document.bescheid.smartdocuments;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import javax.net.ssl.SSLContext;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Spy;
import org.springframework.boot.ssl.NoSuchSslBundleException;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.http.HttpHeaders;
import de.ozgcloud.document.bescheid.smartdocuments.SmartDocumentsProperties.ProxyConfiguration;
......@@ -28,9 +37,11 @@ class SmartDocumentsConfigurationTest {
@Mock
private SmartDocumentsProperties properties;
@Mock
private SslBundles sslBundles;
@Nested
class CreateProxyCredentialsProviderTest {
class TestCreateProxyCredentialsProvider {
private final String user = "max";
private final String password = "max2";
......@@ -61,7 +72,7 @@ class SmartDocumentsConfigurationTest {
}
@Nested
class CreateProxyRoutePlannerTest {
class TestCreateProxyRoutePlanner {
private final String host = "test-proxy.local";
private final int port = 8080;
......@@ -88,7 +99,7 @@ class SmartDocumentsConfigurationTest {
}
@Nested
class BuildHttpClientTest {
class TestBuildHttpClient {
private final CloseableHttpClient proxyHttpClient = HttpClients.createDefault();
private final CloseableHttpClient nonProxyHttpClient = HttpClients.createDefault();
......@@ -98,7 +109,7 @@ class SmartDocumentsConfigurationTest {
@Test
void shouldReturnProxyHttpClient() {
doReturn(proxyHttpClient).when(smartDocumentsConfiguration).createProxyHttpClient();
doReturn(proxyHttpClient).when(smartDocumentsConfiguration).createHttpClientUsingProxy();
when(properties.getProxy()).thenReturn(new ProxyConfiguration());
var httpClient = smartDocumentsConfiguration.buildHttpClient();
......@@ -118,7 +129,7 @@ class SmartDocumentsConfigurationTest {
}
@Nested
class AddBasicAuthenticationIfConfiguredTest {
class TestAddBasicAuthenticationIfConfigured {
@Test
void shouldNotAddBasicAuthentication() {
......@@ -142,4 +153,92 @@ class SmartDocumentsConfigurationTest {
.containsExactly(UsernamePasswordTestFactory.getAsBasicAuthenticationHeader());
}
}
@Nested
class TestCreateConnectionManagerWithClientCertificateIfConfigured {
private MockedStatic<PoolingHttpClientConnectionManagerBuilder> staticBuilder;
@Mock
private PoolingHttpClientConnectionManagerBuilder builder;
@Mock
private SslBundle sslBundle;
@Mock
private SSLContext sslContext;
private final String bundleName = "smartdocuments_bundle";
private final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
@BeforeEach
void setUp() {
staticBuilder = mockStatic(PoolingHttpClientConnectionManagerBuilder.class);
staticBuilder.when(PoolingHttpClientConnectionManagerBuilder::create).thenReturn(builder);
when(builder.build()).thenReturn(connectionManager);
}
@AfterEach
void tearDown() {
staticBuilder.close();
}
@Test
void shouldCreateWithBuilder() {
smartDocumentsConfiguration.createConnectionManagerWithClientCertificateIfConfigured();
staticBuilder.verify(() -> PoolingHttpClientConnectionManagerBuilder.create());
}
@Nested
class OnMissingClientCertificateConfiguration {
@Test
void shouldCreateWithoutTlsStrategyOnMissingBundleName() {
when(properties.getSslBundleName()).thenReturn(null);
var created = smartDocumentsConfiguration.createConnectionManagerWithClientCertificateIfConfigured();
verify(builder, never()).setTlsSocketStrategy(any());
assertThat(created).isSameAs(connectionManager);
}
@Test
void shouldCreateWithoutTlsStrategyOnMissingBundleConfiguration() {
when(properties.getSslBundleName()).thenReturn(bundleName);
when(sslBundles.getBundle(anyString())).thenThrow(new NoSuchSslBundleException("some_bundle", "error message"));
var created = smartDocumentsConfiguration.createConnectionManagerWithClientCertificateIfConfigured();
verify(builder, never()).setTlsSocketStrategy(any());
assertThat(created).isSameAs(connectionManager);
}
}
@Nested
class OnExistingClientCertificateConfiguration {
@BeforeEach
void setUp() {
when(properties.getSslBundleName()).thenReturn(bundleName);
when(sslBundles.getBundle(any())).thenReturn(sslBundle);
when(sslBundle.createSslContext()).thenReturn(sslContext);
}
@Test
void shouldGetSslBundle() {
smartDocumentsConfiguration.createConnectionManagerWithClientCertificateIfConfigured();
verify(sslBundles).getBundle(bundleName);
}
@Test
void shouldCreateWithTlsStrategy() {
var created = smartDocumentsConfiguration.createConnectionManagerWithClientCertificateIfConfigured();
verify(builder).setTlsSocketStrategy(any());
assertThat(created).isSameAs(connectionManager);
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment