From d233142006490a667d0d5b83e768fd27172e5122 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Wed, 27 Mar 2024 14:33:10 +0100 Subject: fix(http): allow SSL host-certificate validation in any case Before, it was only supported in case of SSL client authentication --- .../eaaf/core/impl/http/HttpClientFactory.java | 4 +- .../at/gv/egiz/eaaf/core/impl/http/HttpUtils.java | 28 +++++++++ .../eaaf/core/test/http/HttpClientFactoryTest.java | 69 ++++++++++++++++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java index 5e8edfa3..f929c7eb 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java @@ -37,7 +37,6 @@ import org.apache.hc.core5.http.config.RegistryBuilder; import org.apache.hc.core5.http.io.SocketConfig; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.pool.PoolConcurrencyPolicy; -import org.apache.hc.core5.ssl.SSLContexts; import org.apache.hc.core5.util.TimeValue; import org.springframework.beans.factory.annotation.Autowired; @@ -319,7 +318,8 @@ public class HttpClientFactory implements IHttpClientFactory { } else { log.trace("Initializing default SSL Context ... "); - sslContext = SSLContexts.createDefault(); + sslContext = HttpUtils.buildSslContext(httpClientConfig.isDisableTlsHostCertificateValidation(), + httpClientConfig.getFriendlyName()); } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java index d26672f2..491d641f 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java @@ -257,6 +257,34 @@ public class HttpUtils { } } + /** + * Initialize a {@link SSLContext} + * + * @param trustAllServerCertificates Deactivate SSL server-certificate + * validation + * @param friendlyName FriendlyName of the http client for logging + * purposes + * @return {@link SSLContext} with X509 client authentication + * @throws EaafConfigurationException In case of a configuration error + * @throws EaafFactoryException In case of a {@link SSLContext} + * initialization error + */ + public static SSLContext buildSslContext( + boolean trustAllServerCertificates, @Nonnull String friendlyName) + throws EaafConfigurationException, EaafFactoryException { + try { + EaafSslContextBuilder sslContextBuilder = EaafSslContextBuilder.create(); + + injectTrustStore(sslContextBuilder, null, trustAllServerCertificates, friendlyName); + + return sslContextBuilder.build(); + + } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { + throw new EaafFactoryException(ERROR_03, new Object[] { friendlyName, e.getMessage() }, e); + + } + } + /** * Initialize a {@link SSLContext} with a {@link KeyStore} that uses X509 Client * authentication. diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java index 269c516e..493d966b 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java @@ -1,6 +1,7 @@ package at.gv.egiz.eaaf.core.test.http; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -17,6 +18,8 @@ import java.security.Provider; import java.security.UnrecoverableKeyException; import java.security.cert.X509Certificate; +import javax.net.ssl.SSLHandshakeException; + import org.apache.commons.lang3.RandomStringUtils; import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.classic.methods.HttpGet; @@ -213,6 +216,72 @@ public class HttpClientFactoryTest { } + @Test + public void getCustomClientBasicAuthWithSslTrustAll() throws EaafException, ClientProtocolException, + IOException, KeyStoreException { + final HttpClientConfiguration config = new HttpClientConfiguration("jUnit"); + config.setEnablePreEmptiveHttpBasicAuth(false); + config.setAuthMode("password"); + config.setUsername("jUnit"); + config.setPassword("password"); + config.setDisableTlsHostCertificateValidation(true); + + final CloseableHttpClient client = httpClientFactory.getHttpClient(config); + Assert.assertNotNull("httpClient", client); + + // set-up mock-up web-server with SSL client authentication + final String localhost = InetAddress.getByName("localhost").getCanonicalHostName(); + final HeldCertificate localhostCertificate = new HeldCertificate.Builder() + .addSubjectAlternativeName(localhost) + .build(); + final HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder() + .heldCertificate(localhostCertificate) + .build(); + mockWebServer = new MockWebServer(); + mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("Successful auth!")); + mockServerUrl = mockWebServer.url("/sp/junit"); + + // perform test request + final HttpUriRequest httpGet2 = new HttpGet(mockServerUrl.url().toString()); + final CloseableHttpResponse httpResp2 = client.execute(httpGet2); + Assert.assertEquals("http statusCode", 200, httpResp2.getCode()); + + } + + @Test + public void getCustomClientBasicAuthWithSsl() throws EaafException, ClientProtocolException, + IOException, KeyStoreException { + final HttpClientConfiguration config = new HttpClientConfiguration("jUnit"); + config.setEnablePreEmptiveHttpBasicAuth(false); + config.setAuthMode("password"); + config.setUsername("jUnit"); + config.setPassword("password"); + + final CloseableHttpClient client = httpClientFactory.getHttpClient(config); + Assert.assertNotNull("httpClient", client); + + // set-up mock-up web-server with SSL client authentication + final String localhost = InetAddress.getByName("localhost").getCanonicalHostName(); + final HeldCertificate localhostCertificate = new HeldCertificate.Builder() + .addSubjectAlternativeName(localhost) + .build(); + final HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder() + .heldCertificate(localhostCertificate) + .build(); + mockWebServer = new MockWebServer(); + mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("Successful auth!")); + mockServerUrl = mockWebServer.url("/sp/junit"); + + // perform test request + final HttpUriRequest httpGet2 = new HttpGet(mockServerUrl.url().toString()); + assertThrows(SSLHandshakeException.class, () -> client.execute(httpGet2)); + + } + @Test public void getCustomClientBasicAuthWithPreEmptive() throws EaafException, ClientProtocolException, IOException, InterruptedException { -- cgit v1.2.3