diff options
author | Thomas <> | 2024-04-03 09:26:23 +0200 |
---|---|---|
committer | Thomas <> | 2024-04-03 09:26:23 +0200 |
commit | 487011328411309e0be774d5e9371346a788d9ba (patch) | |
tree | d0bd7710f882426f1ee8e91535503af46fa16b9d | |
parent | 9ecefc83ada33a3f803431a21122f6389b9c0989 (diff) | |
download | EAAF-Components-487011328411309e0be774d5e9371346a788d9ba.tar.gz EAAF-Components-487011328411309e0be774d5e9371346a788d9ba.tar.bz2 EAAF-Components-487011328411309e0be774d5e9371346a788d9ba.zip |
feat(http): support HTTP-Proxy connections on client level
5 files changed, 149 insertions, 2 deletions
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java index 4d808f2b..2081bd24 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java @@ -49,6 +49,9 @@ public class HttpClientConfiguration { boolean enablePreEmptiveHttpBasicAuth = true; @Setter + boolean enableHttpProxyMode = false; + + @Setter boolean disableTlsHostCertificateValidation = false; @Setter 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 04dd36cb..62e781b9 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 @@ -22,6 +22,7 @@ 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.BasicHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.client5.http.protocol.RedirectStrategy; import org.apache.hc.client5.http.socket.ConnectionSocketFactory; @@ -30,8 +31,10 @@ import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.config.Registry; import org.apache.hc.core5.http.config.RegistryBuilder; import org.apache.hc.core5.http.io.SocketConfig; @@ -81,6 +84,20 @@ public class HttpClientFactory implements IHttpClientFactory { public static final String PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL = "client.http.ssl.hostnameverifier.trustall"; + public static final String PROP_CONFIG_CLIENT_HTTP_PROXY_HOST_SSL = + "client.http.connection.proxy.host.ssl"; + public static final String PROP_CONFIG_CLIENT_HTTP_PROXY_HOST = + "client.http.connection.proxy.host"; + public static final String PROP_CONFIG_CLIENT_HTTP_PROXY_PORT = + "client.http.connection.proxy.port"; + public static final String PROP_CONFIG_CLIENT_HTTP_PROXY_AUTH_USERNAME = + "client.http.connection.proxy.auth.username"; + public static final String PROP_CONFIG_CLIENT_HTTP_PROXY_AUTH_PASSWORD = + "client.http.connection.proxy.auth.password"; + + public static final String PROP_CONFIG_CLIENT_HTTP_PROXY_ENABLED = + "client.http.connection.proxy.enabled"; + public static final String PROP_CONFIG_CLIENT_MODE = "client.authmode"; public static final String PROP_CONFIG_CLIENT_AUTH_HTTP_USERNAME = "client.auth.http.username"; public static final String PROP_CONFIG_CLIENT_AUTH_HTTP_PASSORD = "client.auth.http.password"; @@ -149,6 +166,9 @@ public class HttpClientFactory implements IHttpClientFactory { builder.setDefaultRequestConfig(buildDefaultRequestConfig(config)); injectInternalRetryHandler(builder, config); + // inject HTTP Proxy + injectHttpProxyConnections(builder, config); + // inject basic authentication infos injectBasicAuthenticationIfRequired(builder, config); @@ -212,6 +232,9 @@ public class HttpClientFactory implements IHttpClientFactory { defaultHttpClientBuilder.setDefaultRequestConfig(buildDefaultRequestConfig(defaultHttpClientConfig)); injectInternalRetryHandler(defaultHttpClientBuilder, defaultHttpClientConfig); + // inject HTTP Proxy + injectHttpProxyConnections(defaultHttpClientBuilder, defaultHttpClientConfig); + // inject http basic authentication injectBasicAuthenticationIfRequired(defaultHttpClientBuilder, defaultHttpClientConfig); @@ -230,6 +253,28 @@ public class HttpClientFactory implements IHttpClientFactory { } + private void injectHttpProxyConnections(HttpClientBuilder httpClientBuilder, + HttpClientConfiguration httpClientConfig) throws EaafConfigurationException { + if (httpClientConfig.isEnableHttpProxyMode()) { + log.debug("Injecting HTTP Proxy-Connections ... "); + URIScheme proxySchema = basicConfig.getBasicConfigurationBoolean( + PROP_CONFIG_CLIENT_HTTP_PROXY_HOST_SSL, false) + ? URIScheme.HTTPS + : URIScheme.HTTP; + HttpHost proxy = new HttpHost( + proxySchema.getId(), + ConfigurationUtils.parseString(basicConfig, PROP_CONFIG_CLIENT_HTTP_PROXY_HOST), + ConfigurationUtils.parseInteger(basicConfig, PROP_CONFIG_CLIENT_HTTP_PROXY_PORT)); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); + httpClientBuilder.setRoutePlanner(routePlanner); + log.info("Set HTTP Proxy-Connection: {} for client: {}", proxy, httpClientConfig.getFriendlyName()); + + } else { + log.trace("Injection of HTTP Proxy-Connection was skipped"); + + } + } + private HttpClientConfiguration buildDefaultHttpClientConfiguration() throws EaafConfigurationException { final HttpClientConfiguration config = new HttpClientConfiguration("Default"); @@ -265,6 +310,9 @@ public class HttpClientFactory implements IHttpClientFactory { PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT, DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT))); + config.setEnableHttpProxyMode(basicConfig.getBasicConfigurationBoolean( + PROP_CONFIG_CLIENT_HTTP_PROXY_ENABLED, false)); + // validate configuration object config.validate(); diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ConfigurationUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ConfigurationUtils.java index 81de9762..ae39ba49 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ConfigurationUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ConfigurationUtils.java @@ -1,5 +1,7 @@ package at.gv.egiz.eaaf.core.impl.utils; +import org.apache.commons.lang3.StringUtils; + import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import lombok.extern.slf4j.Slf4j; @@ -15,6 +17,26 @@ public class ConfigurationUtils { /** + * Read String value from configuration. + * + * @param basicConfig Configuration object + * @param propertyKey Configuration key + * @return Configuration value + * @throws EaafConfigurationException If configuration value does not exist + */ + public static String parseString(IConfiguration basicConfig, String propertyKey) + throws EaafConfigurationException { + String value = basicConfig.getBasicConfiguration(propertyKey); + if (StringUtils.isEmpty(value)) { + log.error("Can not find String value from configuration: {}", propertyKey); + throw new EaafConfigurationException("internal.configuration.00", new Object[] { propertyKey }); + + } + + return value; + } + + /** * Parse Integer value from configuration. * * @param basicConfig Configuration object @@ -81,4 +103,5 @@ public class ConfigurationUtils { private ConfigurationUtils() { } + } 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 7f0240ef..243205c9 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 @@ -20,6 +20,7 @@ import java.security.cert.X509Certificate; import org.apache.commons.lang3.RandomStringUtils; import org.apache.hc.client5.http.ClientProtocolException; +import org.apache.hc.client5.http.HttpHostConnectException; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.classic.methods.HttpUriRequest; @@ -42,6 +43,7 @@ import org.springframework.test.annotation.DirtiesContext.MethodMode; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; @@ -52,8 +54,10 @@ import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration; import at.gv.egiz.eaaf.core.impl.http.HttpUtils; import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory; import at.gv.egiz.eaaf.core.impl.utils.StreamUtils; +import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; +import lombok.SneakyThrows; import okhttp3.HttpUrl; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -67,8 +71,14 @@ import okhttp3.tls.HeldCertificate; @DirtiesContext(classMode = ClassMode.BEFORE_CLASS) public class HttpClientFactoryTest { - @Autowired private EaafKeyStoreFactory keyStoreFactory; - @Autowired private IHttpClientFactory httpClientFactory; + @Autowired + EaafKeyStoreFactory keyStoreFactory; + + @Autowired + IHttpClientFactory httpClientFactory; + + @Autowired + DummyAuthConfigMap basicConfig; private MockWebServer mockWebServer = null; private HttpUrl mockServerUrl; @@ -100,6 +110,8 @@ public class HttpClientFactoryTest { */ @Before public void setup() { + basicConfig.putConfigValue("client.http.connection.proxy.host", "localhost"); + basicConfig.putConfigValue("client.http.connection.proxy.port", "8080"); } @@ -170,6 +182,64 @@ public class HttpClientFactoryTest { } @Test + @SneakyThrows + public void clientWithHttpProxyModeWrongPort() throws EaafException { + basicConfig.putConfigValue("client.http.connection.proxy.port", "8081"); + + final HttpClientConfiguration config = new HttpClientConfiguration("jUnit-withProxy"); + config.setEnableHttpProxyMode(true); + + final CloseableHttpClient client = httpClientFactory.getHttpClient(config); + Assert.assertNotNull("httpClient", client); + + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/junit"); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("GetData")); + + final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); + assertThrows(HttpHostConnectException.class, () -> client.execute(httpGet1)); + + } + + @Test + @SneakyThrows + public void clientWithHttpProxyMode() throws EaafException { + final HttpClientConfiguration config = new HttpClientConfiguration("jUnit-withProxy"); + config.setEnableHttpProxyMode(true); + + final CloseableHttpClient client = httpClientFactory.getHttpClient(config); + Assert.assertNotNull("httpClient", client); + + MockWebServer mockProxy = new MockWebServer(); + mockProxy.start(8080); + mockProxy.enqueue(new MockResponse().setResponseCode(200) + .setBody("GetData")); + + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/junit"); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("GetData")); + + final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString()); + final CloseableHttpResponse httpResp1 = client.execute(httpGet1); + Assert.assertEquals("http statusCode", 200, httpResp1.getCode()); + + mockProxy.close(); + + } + + @Test + public void clientWithHttpProxyModeMissingHost() throws EaafException { + basicConfig.removeConfigValue("client.http.connection.proxy.host"); + + final HttpClientConfiguration config = new HttpClientConfiguration("jUnit-withProxy"); + config.setEnableHttpProxyMode(true); + assertThrows(EaafConfigurationException.class, () -> httpClientFactory.getHttpClient(config)); + + } + + @Test public void getCustomClientUnknownAuthMethod() throws EaafException { final HttpClientConfiguration config = new HttpClientConfiguration("jUnit"); config.setAuthMode(RandomStringUtils.randomAlphabetic(5)); diff --git a/eaaf_core_utils/src/test/resources/data/config1.properties b/eaaf_core_utils/src/test/resources/data/config1.properties index 1bcc1fb3..ec5e45a7 100644 --- a/eaaf_core_utils/src/test/resources/data/config1.properties +++ b/eaaf_core_utils/src/test/resources/data/config1.properties @@ -9,6 +9,9 @@ client.http.connection.timeout.socket=2 client.http.connection.timeout.connection=2 client.http.connection.timeout.request=2 +client.http.connection.proxy.host=localhost +client.http.connection.proxy.port=8080 + core.pendingrequestid.maxlifetime=180 core.pendingrequestid.digist.type=passphrase core.pendingrequestid.digist.secret=pendingReqIdSecret |