From 63030dd9c5349195006cc553a6bdaa3e92948288 Mon Sep 17 00:00:00 2001 From: Dmytro Vitiuk Date: Mon, 10 Jan 2022 21:36:32 +0200 Subject: [PATCH] Fix basic auth. --- docs/HTTP-action.md | 3 +++ docs/HTTP-batchsource.md | 3 +++ docs/HTTP-streamingsource.md | 3 +++ .../plugin/http/action/HttpActionConfig.java | 11 +++++++++ .../http/common/BaseHttpSourceConfig.java | 11 +++++++++ .../plugin/http/common/http/HttpClient.java | 23 ++++++++++++++++--- .../http/common/http/HttpConstants.java | 1 + .../plugin/http/common/http/IHttpConfig.java | 2 ++ .../plugin/http/etl/HttpSourceETLTest.java | 1 + widgets/HTTP-action.json | 16 +++++++++++++ widgets/HTTP-batchsource.json | 16 +++++++++++++ widgets/HTTP-streamingsource.json | 16 +++++++++++++ 12 files changed, 103 insertions(+), 3 deletions(-) diff --git a/docs/HTTP-action.md b/docs/HTTP-action.md index 3073d02c..c80283b5 100644 --- a/docs/HTTP-action.md +++ b/docs/HTTP-action.md @@ -21,6 +21,9 @@ The url must start with a protocol (e.g. http://). ### Basic Authentication +**Preemptive basic authentication:** If true, basic authentication will be performed in preemptive mode, +without additional negotiation request. + **Username:** Username for basic authentication. **Password:** Password for basic authentication. diff --git a/docs/HTTP-batchsource.md b/docs/HTTP-batchsource.md index 1e227869..4c350731 100644 --- a/docs/HTTP-batchsource.md +++ b/docs/HTTP-batchsource.md @@ -205,6 +205,9 @@ can be omitted as long as the field is present in schema. ### Basic Authentication +**Preemptive basic authentication:** If true, basic authentication will be performed in preemptive mode, +without additional negotiation request. + **Username:** Username for basic authentication. **Password:** Password for basic authentication. diff --git a/docs/HTTP-streamingsource.md b/docs/HTTP-streamingsource.md index eafe35f6..08b33a83 100644 --- a/docs/HTTP-streamingsource.md +++ b/docs/HTTP-streamingsource.md @@ -209,6 +209,9 @@ can be omitted as long as the field is present in schema. ### Basic Authentication +**Preemptive basic authentication:** If true, basic authentication will be performed in preemptive mode, +without additional negotiation request. + **Username:** Username for basic authentication. **Password:** Password for basic authentication. diff --git a/src/main/java/io/cdap/plugin/http/action/HttpActionConfig.java b/src/main/java/io/cdap/plugin/http/action/HttpActionConfig.java index 101b8c98..0bcb9e1d 100644 --- a/src/main/java/io/cdap/plugin/http/action/HttpActionConfig.java +++ b/src/main/java/io/cdap/plugin/http/action/HttpActionConfig.java @@ -66,6 +66,12 @@ public class HttpActionConfig extends PluginConfig implements IHttpConfig { @Macro protected String requestBody; + @Name(HttpConstants.PROPERTY_PREEMPTIVE_BASIC_AUTH) + @Description("If true, basic authentication will be performed in preemptive mode, " + + "without additional negotiation request.") + @Macro + protected String preemptiveBasicAuth; + @Nullable @Name(HttpConstants.PROPERTY_USERNAME) @Description("Username for basic authentication.") @@ -255,6 +261,11 @@ public String getRequestBody() { return requestBody; } + @Override + public Boolean getPreemptiveBasicAuth() { + return Boolean.parseBoolean(preemptiveBasicAuth); + } + @Override @Nullable public String getUsername() { diff --git a/src/main/java/io/cdap/plugin/http/common/BaseHttpSourceConfig.java b/src/main/java/io/cdap/plugin/http/common/BaseHttpSourceConfig.java index 6933ce98..19261d7a 100644 --- a/src/main/java/io/cdap/plugin/http/common/BaseHttpSourceConfig.java +++ b/src/main/java/io/cdap/plugin/http/common/BaseHttpSourceConfig.java @@ -119,6 +119,12 @@ public abstract class BaseHttpSourceConfig extends ReferencePluginConfig impleme @Macro protected String csvSkipFirstRow; + @Name(HttpConstants.PROPERTY_PREEMPTIVE_BASIC_AUTH) + @Description("If true, basic authentication will be performed in preemptive mode, " + + "without additional negotiation request.") + @Macro + protected String preemptiveBasicAuth; + @Nullable @Name(HttpConstants.PROPERTY_USERNAME) @Description("Username for basic authentication.") @@ -403,6 +409,11 @@ public Boolean getCsvSkipFirstRow() { return Boolean.parseBoolean(csvSkipFirstRow); } + @Override + public Boolean getPreemptiveBasicAuth() { + return Boolean.parseBoolean(preemptiveBasicAuth); + } + @Nullable public String getUsername() { return username; diff --git a/src/main/java/io/cdap/plugin/http/common/http/HttpClient.java b/src/main/java/io/cdap/plugin/http/common/http/HttpClient.java index aa6b151d..761f79f5 100644 --- a/src/main/java/io/cdap/plugin/http/common/http/HttpClient.java +++ b/src/main/java/io/cdap/plugin/http/common/http/HttpClient.java @@ -22,11 +22,15 @@ import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; @@ -36,6 +40,7 @@ import java.io.Closeable; import java.io.IOException; import java.net.URI; +import java.net.URL; import java.util.ArrayList; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -48,6 +53,7 @@ public class HttpClient implements Closeable { private final IHttpConfig config; private final StringEntity requestBody; private CloseableHttpClient httpClient; + private HttpClientContext localContext; public HttpClient(IHttpConfig config) { this.config = config; @@ -81,7 +87,7 @@ public CloseableHttpResponse executeHTTP(String uri) throws IOException { request.setEntity(requestBody); } - return httpClient.execute(request); + return localContext == null ? httpClient.execute(request) : httpClient.execute(request, localContext); } @Override @@ -106,11 +112,22 @@ private CloseableHttpClient createHttpClient() throws IOException { // basic auth CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + localContext = HttpClientContext.create(); + if (!Strings.isNullOrEmpty(config.getUsername()) && !Strings.isNullOrEmpty(config.getPassword())) { + URL targetURL = new URL(config.getUrl()); + HttpHost targetHost = new HttpHost(targetURL.getHost(), targetURL.getPort(), targetURL.getProtocol()); + credentialsProvider.setCredentials( - new AuthScope(HttpHost.create(config.getUrl())), - new UsernamePasswordCredentials(config.getUsername(), config.getPassword()) + new AuthScope(targetHost), + new UsernamePasswordCredentials(config.getUsername(), config.getPassword()) ); + if (config.getPreemptiveBasicAuth()) { + AuthCache authCache = new BasicAuthCache(); + authCache.put(targetHost, new BasicScheme()); + + localContext.setAuthCache(authCache); + } } // proxy and proxy auth diff --git a/src/main/java/io/cdap/plugin/http/common/http/HttpConstants.java b/src/main/java/io/cdap/plugin/http/common/http/HttpConstants.java index 0e10acb5..47ab3a98 100644 --- a/src/main/java/io/cdap/plugin/http/common/http/HttpConstants.java +++ b/src/main/java/io/cdap/plugin/http/common/http/HttpConstants.java @@ -31,6 +31,7 @@ private HttpConstants() { public static final String PROPERTY_HEADERS = "headers"; public static final String PROPERTY_REQUEST_BODY = "requestBody"; public static final String PROPERTY_USERNAME = "username"; + public static final String PROPERTY_PREEMPTIVE_BASIC_AUTH = "preemptiveBasicAuth"; public static final String PROPERTY_PASSWORD = "password"; public static final String PROPERTY_PROXY_URL = "proxyUrl"; public static final String PROPERTY_PROXY_USERNAME = "proxyUsername"; diff --git a/src/main/java/io/cdap/plugin/http/common/http/IHttpConfig.java b/src/main/java/io/cdap/plugin/http/common/http/IHttpConfig.java index 09d93759..5f1437f2 100644 --- a/src/main/java/io/cdap/plugin/http/common/http/IHttpConfig.java +++ b/src/main/java/io/cdap/plugin/http/common/http/IHttpConfig.java @@ -37,6 +37,8 @@ public interface IHttpConfig { @Nullable String getRequestBody(); + Boolean getPreemptiveBasicAuth(); + @Nullable String getUsername(); diff --git a/src/test/java/io/cdap/plugin/http/etl/HttpSourceETLTest.java b/src/test/java/io/cdap/plugin/http/etl/HttpSourceETLTest.java index 5f525754..24b9cd5d 100644 --- a/src/test/java/io/cdap/plugin/http/etl/HttpSourceETLTest.java +++ b/src/test/java/io/cdap/plugin/http/etl/HttpSourceETLTest.java @@ -487,6 +487,7 @@ protected Map getProperties(Map sourceProperties return new ImmutableMap.Builder() .put("referenceName", testName.getMethodName()) .put(HttpConstants.PROPERTY_HTTP_METHOD, "GET") + .put(HttpConstants.PROPERTY_PREEMPTIVE_BASIC_AUTH, "false") .put(HttpConstants.PROPERTY_OAUTH2_ENABLED, "false") .put(HttpConstants.PROPERTY_HTTP_ERROR_HANDLING, "2..:Success,.*:Fail") .put(HttpConstants.PROPERTY_ERROR_HANDLING, "stopOnError") diff --git a/widgets/HTTP-action.json b/widgets/HTTP-action.json index 4f2ab93c..7c40e4a4 100644 --- a/widgets/HTTP-action.json +++ b/widgets/HTTP-action.json @@ -98,6 +98,22 @@ { "label": "Basic Authentication", "properties": [ + { + "widget-type": "toggle", + "label": "Preemptive basic authentication", + "name": "preemptiveBasicAuth", + "widget-attributes": { + "default": "false", + "on": { + "label": "True", + "value": "true" + }, + "off": { + "label": "False", + "value": "false" + } + } + }, { "widget-type": "textbox", "label": "Username", diff --git a/widgets/HTTP-batchsource.json b/widgets/HTTP-batchsource.json index 373101ec..5eee35e8 100644 --- a/widgets/HTTP-batchsource.json +++ b/widgets/HTTP-batchsource.json @@ -156,6 +156,22 @@ { "label": "Basic Authentication", "properties": [ + { + "widget-type": "toggle", + "label": "Preemptive basic authentication", + "name": "preemptiveBasicAuth", + "widget-attributes": { + "default": "false", + "on": { + "label": "True", + "value": "true" + }, + "off": { + "label": "False", + "value": "false" + } + } + }, { "widget-type": "textbox", "label": "Username", diff --git a/widgets/HTTP-streamingsource.json b/widgets/HTTP-streamingsource.json index 798a6fed..ff5f7e80 100644 --- a/widgets/HTTP-streamingsource.json +++ b/widgets/HTTP-streamingsource.json @@ -161,6 +161,22 @@ { "label": "Basic Authentication", "properties": [ + { + "widget-type": "toggle", + "label": "Preemptive basic authentication", + "name": "preemptiveBasicAuth", + "widget-attributes": { + "default": "false", + "on": { + "label": "True", + "value": "true" + }, + "off": { + "label": "False", + "value": "false" + } + } + }, { "widget-type": "textbox", "label": "Username",