summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas <>2024-04-03 09:26:23 +0200
committerThomas <>2024-04-03 09:26:23 +0200
commit487011328411309e0be774d5e9371346a788d9ba (patch)
treed0bd7710f882426f1ee8e91535503af46fa16b9d
parent9ecefc83ada33a3f803431a21122f6389b9c0989 (diff)
downloadEAAF-Components-487011328411309e0be774d5e9371346a788d9ba.tar.gz
EAAF-Components-487011328411309e0be774d5e9371346a788d9ba.tar.bz2
EAAF-Components-487011328411309e0be774d5e9371346a788d9ba.zip
feat(http): support HTTP-Proxy connections on client level
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java3
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java48
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ConfigurationUtils.java23
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java74
-rw-r--r--eaaf_core_utils/src/test/resources/data/config1.properties3
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