summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas <>2023-02-06 15:04:35 +0100
committerThomas <>2023-02-06 15:04:35 +0100
commita0320b9505073357bbd085e5ee4a4894ecd1e9f3 (patch)
tree55429e6ce293be9f719498c568b5007c18985d53
parentb1c89dad26ec39270de561657f1200980ec301da (diff)
downloadEAAF-Components-a0320b9505073357bbd085e5ee4a4894ecd1e9f3.tar.gz
EAAF-Components-a0320b9505073357bbd085e5ee4a4894ecd1e9f3.tar.bz2
EAAF-Components-a0320b9505073357bbd085e5ee4a4894ecd1e9f3.zip
feat(http): add request interceptor to pre-emptive HTTP Basic authentication
-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.java8
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/interceptor/PreemptiveAuthInterceptor.java55
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java33
4 files changed, 99 insertions, 0 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 40d22205..5e873fe8 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
@@ -46,6 +46,9 @@ public class HttpClientConfiguration {
boolean disableHostnameValidation = false;
@Setter
+ boolean enablePreEmptiveHttpBasicAuth = true;
+
+ @Setter
boolean disableTlsHostCertificateValidation = false;
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 784dbe0e..ac5905ac 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
@@ -49,6 +49,7 @@ 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.KeyStoreType;
import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.http.interceptor.PreemptiveAuthInterceptor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -305,6 +306,13 @@ public class HttpClientFactory implements IHttpClientFactory {
log.info("Basic http authentication was injected with username: {}",
httpClientConfig.getUsername());
+ if (httpClientConfig.isEnablePreEmptiveHttpBasicAuth()) {
+ log.info("Inject pre-emptive HTTP Basic-Auth interceptor for client: {}",
+ httpClientConfig.getFriendlyName());
+ builder.addInterceptorFirst(new PreemptiveAuthInterceptor());
+
+ }
+
} else {
log.trace("Injection of Http Basic authentication was skipped");
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/interceptor/PreemptiveAuthInterceptor.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/interceptor/PreemptiveAuthInterceptor.java
new file mode 100644
index 00000000..5edc8cac
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/interceptor/PreemptiveAuthInterceptor.java
@@ -0,0 +1,55 @@
+package at.gv.egiz.eaaf.core.impl.http.interceptor;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpCoreContext;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Intercepter for Apache HTTP client to pre-emptive Basic authentication.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
+
+ @Override
+ public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
+ final AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
+
+ // If no auth scheme available yet, try to initialize it
+ // preemptively
+ if (authState.getAuthScheme() == null) {
+ final CredentialsProvider credentialsProvider =
+ (CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER);
+ final HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
+
+ final Credentials credentials = credentialsProvider.getCredentials(
+ new AuthScope(targetHost.getHostName(), targetHost.getPort()));
+ if (credentials == null) {
+ log.warn("Find HTTP credential-provider but not credential matches. "
+ + "Use it as it is and looking what happend");
+
+ } else {
+ log.trace("Updating HTTP basic-auth state to pre-emptive credentials ... ");
+ authState.update(new BasicScheme(), credentials);
+
+ }
+ }
+
+ }
+
+}
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 62de99c0..7f3982be 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,5 +1,7 @@
package at.gv.egiz.eaaf.core.test.http;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
@@ -179,6 +181,7 @@ public class HttpClientFactoryTest {
public void getCustomClientBasicAuth() throws EaafException, ClientProtocolException,
IOException, InterruptedException {
final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
+ config.setEnablePreEmptiveHttpBasicAuth(false);
config.setAuthMode("password");
config.setUsername("jUnit");
config.setPassword("password");
@@ -206,10 +209,40 @@ public class HttpClientFactoryTest {
final RecordedRequest httpReq2 = mockWebServer.takeRequest();
Assert.assertNull("wrong BasicAuthHeader", httpReq1.getHeader("Authorization"));
Assert.assertNotNull("missing BasicAuthHeader", httpReq2.getHeader("Authorization"));
+ assertEquals("Basic alVuaXQ6cGFzc3dvcmQ=", httpReq2.getHeader("Authorization"), "wrong authHeader");
}
@Test
+ public void getCustomClientBasicAuthWithPreEmptive() throws EaafException, ClientProtocolException,
+ IOException, InterruptedException {
+ final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
+ config.setAuthMode("password");
+ config.setUsername("jUnit");
+ config.setPassword("password");
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("httpClient", client);
+
+ //setup test webserver that requestes http Basic authentication
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("Successful auth!"));
+
+ //request webservice
+ final HttpUriRequest httpGet2 = new HttpGet(mockServerUrl.url().toString());
+ final CloseableHttpResponse httpResp2 = client.execute(httpGet2);
+ Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
+
+ //check request contains basic authentication after authentication was requested
+ final RecordedRequest httpReq1 = mockWebServer.takeRequest();
+ Assert.assertNotNull("missing BasicAuthHeader", httpReq1.getHeader("Authorization"));
+ assertEquals("Basic alVuaXQ6cGFzc3dvcmQ=", httpReq1.getHeader("Authorization"), "wrong authHeader");
+
+ }
+
+ @Test
public void getCustomClientBasicAuthNoUsername() {
final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
config.setAuthMode("password");