From 78fb9f998f39face9c05602ca094dfdffa5b0551 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:19:16 +0900 Subject: [PATCH 01/14] Add ability to talk to HTTPS based kafka-connect instances --- .../connect/apiclient/Configuration.java | 54 +++++++- .../apiclient/rest/HttpClientRestClient.java | 21 +++- .../apiclient/rest/HttpsContextBuilder.java | 117 ++++++++++++++++++ .../apiclient/rest/NoopTrustManager.java | 39 ++++++ .../apiclient/KafkaConnectClientTest.java | 16 ++- 5 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java create mode 100644 src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java index 74a300b..7431989 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java @@ -17,6 +17,10 @@ package org.sourcelab.kafka.connect.apiclient; +import java.io.File; +import java.net.URL; +import java.util.Objects; + /** * Configure your Kafka Connect API client. * @@ -26,6 +30,11 @@ public final class Configuration { // Defines the URL/Hostname of Kafka-Connect private final String apiHost; + // Optional SSL options + private boolean ignoreInvalidSslCertificates = false; + private File trustStoreFile = null; + private String trustStorePassword = null; + // Optional Proxy Configuration private String proxyHost = null; private int proxyPort = 0; @@ -45,10 +54,11 @@ public Configuration(final String kafkaConnectHost) { } // Normalize into "http://" - if (!kafkaConnectHost.startsWith("http://")) { - this.apiHost = "http://" + kafkaConnectHost; - } else { + if (kafkaConnectHost.startsWith("http://") || kafkaConnectHost.startsWith("https://")) { this.apiHost = kafkaConnectHost; + } else { + // Assume http protocol + this.apiHost = "http://" + kafkaConnectHost; } } @@ -80,6 +90,32 @@ public Configuration useProxyAuthentication(final String proxyUsername, final St return this; } + /** + * Skip all validation of SSL Certificates. This is insecure and highly discouraged! + * + * @return Configuration instance. + */ + public Configuration useInsecureSslCertificates() { + this.ignoreInvalidSslCertificates = true; + return this; + } + + /** + * You can supply a path to a JKS trust store to be used to validate SSL certificates with. + * + * Alternatively you can can explicitly add your certificate to the JVM's truststore using a command like: + * keytool -importcert -keystore truststore.jks -file servercert.pem + * + * @param trustStorePath file path to truststore. + * @param password (optional) Password for truststore. + * @return Configuration instance. + */ + public Configuration useTrustStore(final File trustStorePath, final String password) { + this.trustStoreFile = Objects.requireNonNull(trustStorePath); + this.trustStorePassword = password; + return this; + } + public String getProxyHost() { return proxyHost; } @@ -104,6 +140,18 @@ public String getApiHost() { return apiHost; } + public boolean getIgnoreInvalidSslCertificates() { + return ignoreInvalidSslCertificates; + } + + public File getTrustStoreFile() { + return trustStoreFile; + } + + public String getTrustStorePassword() { + return trustStorePassword; + } + @Override public String toString() { final StringBuilder stringBuilder = new StringBuilder("Configuration{") diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java index 7159dcd..0821437 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java @@ -31,6 +31,7 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCredentialsProvider; @@ -47,11 +48,19 @@ import org.sourcelab.kafka.connect.apiclient.rest.exceptions.ResultParsingException; import org.sourcelab.kafka.connect.apiclient.rest.handlers.RestResponseHandler; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.net.SocketException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -91,15 +100,15 @@ public void init(final Configuration configuration) { // Save reference to configuration this.configuration = configuration; - // Create default SSLContext - final SSLContext sslcontext = SSLContexts.createDefault(); + // Create https context builder utility. + final HttpsContextBuilder httpsContextBuilder = new HttpsContextBuilder(configuration); - // Allow TLSv1 protocol only + // Allow TLSv1.2, TLSv1.1, TLSv1 protocols final LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( - sslcontext, - new String[] { "TLSv1" }, + httpsContextBuilder.getSslContext(), + new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }, null, - SSLConnectionSocketFactory.getDefaultHostnameVerifier() + httpsContextBuilder.getHostnameVerifier() ); // Setup client builder diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java new file mode 100644 index 0000000..a414ef5 --- /dev/null +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java @@ -0,0 +1,117 @@ +/** + * Copyright 2018 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.sourcelab.kafka.connect.apiclient.rest; + +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.ssl.SSLContexts; +import org.sourcelab.kafka.connect.apiclient.Configuration; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.util.Objects; + +/** + * Utility for properly configuring the SSL Context based on client configuration settings. + */ +class HttpsContextBuilder { + /** + * Client configuration. + */ + private final Configuration configuration; + + /** + * Constructor. + * @param configuration client configuration instance. + */ + HttpsContextBuilder(final Configuration configuration) { + this.configuration = Objects.requireNonNull(configuration); + } + + /** + * Get HostnameVerifier instance based on client configuration. + * @return HostnameVerifier instance. + */ + HostnameVerifier getHostnameVerifier() { + // If we're configured to ignore invalid certificates + if (configuration.getIgnoreInvalidSslCertificates()) { + // Use the Noop verifier. + return NoopHostnameVerifier.INSTANCE; + } + // Otherwise use the default verifier. + return SSLConnectionSocketFactory.getDefaultHostnameVerifier(); + } + + /** + * Get properly configured SSLContext instance based on client configuration. + * @return SSLContext instance. + */ + SSLContext getSslContext() { + // Create default SSLContext + final SSLContext sslcontext = SSLContexts.createDefault(); + + try { + // If client configuration is set to ignore invalid certificates + if (configuration.getIgnoreInvalidSslCertificates()) { + // Initialize ssl context with a TrustManager instance that just accepts everything blindly. + // HIGHLY INSECURE / NOT RECOMMENDED! + sslcontext.init(new KeyManager[0], new TrustManager[]{new NoopTrustManager()}, new SecureRandom()); + + // If client configuration has a trust store defined. + } else if (configuration.getTrustStoreFile() != null) { + + final TrustManagerFactory trustManagerFactory = TrustManagerFactory + .getInstance(TrustManagerFactory.getDefaultAlgorithm()); + + + // New JKS Keystore. + final KeyStore keyStore = KeyStore.getInstance("JKS"); + + // Attempt to read the trust store from disk. + try (final FileInputStream trustStoreFileInput = new FileInputStream(configuration.getTrustStoreFile())) { + + // If no trust store password is set. + if (configuration.getTrustStorePassword() == null) { + keyStore.load(trustStoreFileInput, null); + } else { + keyStore.load(trustStoreFileInput, configuration.getTrustStorePassword().toCharArray()); + } + trustManagerFactory.init(keyStore); + } + + // Initialize ssl context with our custom loaded trust store. + sslcontext.init(new KeyManager[0], trustManagerFactory.getTrustManagers(), new SecureRandom()); + } + } catch (final KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) { + throw new RuntimeException(e.getMessage(), e); + } + + return sslcontext; + } +} diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java new file mode 100644 index 0000000..a53ab2c --- /dev/null +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java @@ -0,0 +1,39 @@ +/** + * Copyright 2018 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.sourcelab.kafka.connect.apiclient.rest; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; + +/** + * Implementation of TrustManager that blindly trusts all certificates with no validation or verification. + */ +class NoopTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(final X509Certificate[] x509Certificates, final String s) { + } + + @Override + public void checkServerTrusted(final X509Certificate[] x509Certificates, final String s) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } +} diff --git a/src/test/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClientTest.java b/src/test/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClientTest.java index ccec911..1504991 100644 --- a/src/test/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClientTest.java +++ b/src/test/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClientTest.java @@ -26,6 +26,7 @@ import org.sourcelab.kafka.connect.apiclient.request.dto.ConnectorPluginConfigDefinition; import org.sourcelab.kafka.connect.apiclient.request.dto.NewConnectorDefinition; +import java.io.File; import java.util.HashMap; import java.util.Map; @@ -47,10 +48,21 @@ public void setup() { // Pull apiHost from environment String apiHost = System.getenv("KAFKA_CONNECT_HOST"); if (apiHost == null || apiHost.isEmpty()) { - apiHost = "localhost:8083"; + apiHost = "http://localhost:8083"; } + + final Configuration configuration = new Configuration(apiHost); + + // Pull trust store configuration from environment + final String sslTrustStoreFile = System.getenv("KAFKA_CONNECT_TRUSTSTORE"); + if (sslTrustStoreFile != null && !sslTrustStoreFile.isEmpty()) { + configuration.useTrustStore( + new File(sslTrustStoreFile), System.getenv("KAFKA_CONNECT_TRUSTSTORE_PASSWORD") + ); + } + // Build api client - this.kafkaConnectClient = new KafkaConnectClient(new Configuration(apiHost)); + this.kafkaConnectClient = new KafkaConnectClient(configuration); } /** From a042a77de13ee7e44c1cafd817a767954bc09993 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:20:36 +0900 Subject: [PATCH 02/14] Bump release version --- CHANGELOG.md | 5 ++++- pom.xml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b263114..b1078f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## 1.0.4 (UNRELEASED) +## 1.1.0 (UNRELEASED) + +### New Features +- Added ability to communicate with Kafka-Connect REST endpoints using SSL. More can be found in README. ### Internal Dependency Updates - Updated Guava from 24.0-JRE to 25.0-JRE for [CVE-2018-10237](https://github.com/google/guava/wiki/CVE-2018-10237). diff --git a/pom.xml b/pom.xml index 0779d9d..7a498fb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.sourcelab kafka-connect-client - 1.0.4-SNAPSHOT + 1.1.0-SNAPSHOT jar From f99702b1436f49a860d201868e33b3ddbd6a535b Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:38:32 +0900 Subject: [PATCH 03/14] minor cleanup --- .../connect/apiclient/Configuration.java | 1 - .../apiclient/rest/HttpClientRestClient.java | 11 ---- .../apiclient/rest/NoopTrustManager.java | 4 +- .../rest/HttpsContextBuilderTest.java | 65 +++++++++++++++++++ 4 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java index 7431989..6e61a3f 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java @@ -18,7 +18,6 @@ package org.sourcelab.kafka.connect.apiclient; import java.io.File; -import java.net.URL; import java.util.Objects; /** diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java index 0821437..05b4a85 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java @@ -31,14 +31,12 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicHeader; -import org.apache.http.ssl.SSLContexts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sourcelab.kafka.connect.apiclient.Configuration; @@ -48,19 +46,10 @@ import org.sourcelab.kafka.connect.apiclient.rest.exceptions.ResultParsingException; import org.sourcelab.kafka.connect.apiclient.rest.handlers.RestResponseHandler; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.net.SocketException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.security.KeyManagementException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java index a53ab2c..f014b9c 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java @@ -25,11 +25,11 @@ */ class NoopTrustManager implements X509TrustManager { @Override - public void checkClientTrusted(final X509Certificate[] x509Certificates, final String s) { + public void checkClientTrusted(final X509Certificate[] x509Certificates, final String input) { } @Override - public void checkServerTrusted(final X509Certificate[] x509Certificates, final String s) { + public void checkServerTrusted(final X509Certificate[] x509Certificates, final String input) { } @Override diff --git a/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java b/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java new file mode 100644 index 0000000..94b3bd1 --- /dev/null +++ b/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java @@ -0,0 +1,65 @@ +/** + * Copyright 2018 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.sourcelab.kafka.connect.apiclient.rest; + +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.junit.Test; +import org.sourcelab.kafka.connect.apiclient.Configuration; + +import javax.net.ssl.HostnameVerifier; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class HttpsContextBuilderTest { + + /** + * Constructor should require non-null arguments. + */ + @Test(expected = NullPointerException.class) + public void testConstructorNullArguments() { + new HttpsContextBuilder(null); + } + + /** + * When configured to validate SSL certificates, should not get NoopHostnameVerifier back. + */ + @Test + public void getHostnameVerifier_validateSslCertificates() { + final HttpsContextBuilder builder = new HttpsContextBuilder(new Configuration("http://localhost")); + + final HostnameVerifier verifier = builder.getHostnameVerifier(); + assertNotNull(verifier); + assertFalse("Should not be an instance of NoopHostnameVerifier", verifier instanceof NoopHostnameVerifier); + } + + /** + * When configured to skip validating SSL certificates, should get NoopHostnameVerifier back. + */ + @Test + public void getHostnameVerifier_acceptInvalidSslCertificates() { + final HttpsContextBuilder builder = new HttpsContextBuilder( + new Configuration("http://localhost").useInsecureSslCertificates() + ); + + final HostnameVerifier verifier = builder.getHostnameVerifier(); + assertNotNull(verifier); + assertTrue("Should be an instance of NoopHostnameVerifier", verifier instanceof NoopHostnameVerifier); + } +} From 7d4246f23e474e94e569b0a36eed33d98af4a216 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:44:59 +0900 Subject: [PATCH 04/14] Update README --- README.md | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23bd4d5..1e5410d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ This client library is released on Maven Central. Add a new dependency to your ``` -Example Code: + +##### Example Code: ```java /* * Create a new configuration object. @@ -27,7 +28,7 @@ Example Code: * This configuration also allows you to define some optional details on your connection, * such as using an outbound proxy (authenticated or not). */ -final Configuration configuration = new Configuration("hostname.for.kafka-connect.service.com:8083"); +final Configuration configuration = new Configuration("http://hostname.for.kafka-connect.service.com:8083"); /* * Create an instance of KafkaConnectClient, passing your configuration. @@ -55,6 +56,38 @@ final ConnectorDefinition connectorDefition = client.addConnector(NewConnectorDe Public methods available on KafkaConnectClient can be [found here](src/main/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClient.java#L62) + +##### Communicating with HTTPS enabled Kafka-Connect REST server: +```java +/* + * Create a new configuration object. + * + * This configuration also allows you to define some optional details on your connection, + * such as using an outbound proxy (authenticated or not). + */ +final Configuration configuration = new Configuration("https://hostname.for.kafka-connect.service.com:8083"); + +/* + * If you have a JKS formatted TrustStore file to validate your Kafka-Connect host's certificate with, + * you can provide it to the configuration. + */ +configuration.useTrustStore( + new File("/path/to/truststore.jks"), "TrustStorePasswordHere (Optional)" +); + +/* + * Optionally, you can disable all verifications of Kafka-Connect's SSL certificates. + * Doing this is HIGHLY discouraged and defeats most of the purpose of using SSL in the first place. + */ +//configuration.useInsecureSslCertificates(); + +/* + * Create an instance of KafkaConnectClient, passing your configuration. + */ +final KafkaConnectClient client = new KafkaConnectClient(configuration); + +``` + ## Changelog The format is based on [Keep a Changelog](http://keepachangelog.com/) From 46494f6d1cb593bc6abefa388e2a53b6e243d608 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:45:07 +0900 Subject: [PATCH 05/14] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e5410d..a88558e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This client library is released on Maven Central. Add a new dependency to your org.sourcelab kafka-connect-client - 1.0.3 + 1.1.0 ``` From 567cc8635a0262d96b3a90c133972fde4d5c161e Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:46:19 +0900 Subject: [PATCH 06/14] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a88558e..b5e4a47 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This client library is released on Maven Central. Add a new dependency to your ``` -##### Example Code: +#### Example Code: ```java /* * Create a new configuration object. @@ -57,7 +57,7 @@ final ConnectorDefinition connectorDefition = client.addConnector(NewConnectorDe Public methods available on KafkaConnectClient can be [found here](src/main/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClient.java#L62) -##### Communicating with HTTPS enabled Kafka-Connect REST server: +#### Communicating with HTTPS enabled Kafka-Connect REST server: ```java /* * Create a new configuration object. From d32db8e7678c960f2ea7371268b008e6ea2d72d3 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:48:13 +0900 Subject: [PATCH 07/14] Update README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b5e4a47..400793d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ This client library is released on Maven Central. Add a new dependency to your * Create a new configuration object. * * This configuration also allows you to define some optional details on your connection, - * such as using an outbound proxy (authenticated or not). + * such as using an outbound proxy (authenticated or not), SSL client settings, etc.. */ final Configuration configuration = new Configuration("http://hostname.for.kafka-connect.service.com:8083"); @@ -52,6 +52,10 @@ final ConnectorDefinition connectorDefition = client.addConnector(NewConnectorDe .withConfig("topics", "test-topic") .build() )); + +/* + * See KafkaConnectClient for other available options. + */ ``` Public methods available on KafkaConnectClient can be [found here](src/main/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClient.java#L62) @@ -61,9 +65,6 @@ Public methods available on KafkaConnectClient can be [found here](src/main/java ```java /* * Create a new configuration object. - * - * This configuration also allows you to define some optional details on your connection, - * such as using an outbound proxy (authenticated or not). */ final Configuration configuration = new Configuration("https://hostname.for.kafka-connect.service.com:8083"); From 87aab5f4dcaba54f67698c081fd3bdce91d6f9a4 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:54:00 +0900 Subject: [PATCH 08/14] Update README --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 400793d..77f44e6 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ final ConnectorDefinition connectorDefition = client.addConnector(NewConnectorDe )); /* - * See KafkaConnectClient for other available options. + * See KafkaConnectClient for other available operations. */ ``` @@ -69,16 +69,20 @@ Public methods available on KafkaConnectClient can be [found here](src/main/java final Configuration configuration = new Configuration("https://hostname.for.kafka-connect.service.com:8083"); /* - * If you have a JKS formatted TrustStore file to validate your Kafka-Connect host's certificate with, - * you can provide it to the configuration. + * If you're JVM's TrustStore has already been updated to accept the certificate installed on your Kafka-Connect + * instance, then no further configuration is required. Typically this is done using the 'key-tool' command. + * + * Alternatively, you can configure the path to JKS formatted TrustStore file to validate the host's certificate + * with. */ configuration.useTrustStore( - new File("/path/to/truststore.jks"), "TrustStorePasswordHere (Optional)" + new File("/path/to/truststore.jks"), "TrustStorePasswordHere or NULL" ); /* - * Optionally, you can disable all verifications of Kafka-Connect's SSL certificates. - * Doing this is HIGHLY discouraged and defeats most of the purpose of using SSL in the first place. + * Optionally instead of providing a TrustStore, you can disable all verifications of Kafka-Connect's SSL certificates. + * + * Doing this is HIGHLY DISCOURAGED! */ //configuration.useInsecureSslCertificates(); From 0108797178501f8b881faf2d88ec597535dd9d01 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 14:55:07 +0900 Subject: [PATCH 09/14] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77f44e6..0641329 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Public methods available on KafkaConnectClient can be [found here](src/main/java final Configuration configuration = new Configuration("https://hostname.for.kafka-connect.service.com:8083"); /* - * If you're JVM's TrustStore has already been updated to accept the certificate installed on your Kafka-Connect + * If your JVM's TrustStore has already been updated to accept the certificate installed on your Kafka-Connect * instance, then no further configuration is required. Typically this is done using the 'key-tool' command. * * Alternatively, you can configure the path to JKS formatted TrustStore file to validate the host's certificate From ce51fc430e6cc8bb1f964b9328601937de6306cf Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 15:00:00 +0900 Subject: [PATCH 10/14] Update Header --- .../kafka/connect/apiclient/rest/HttpsContextBuilder.java | 2 +- .../kafka/connect/apiclient/rest/NoopTrustManager.java | 2 +- .../kafka/connect/apiclient/rest/HttpsContextBuilderTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java index a414ef5..56cc7b3 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java @@ -1,5 +1,5 @@ /** - * Copyright 2018 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client + * Copyright 2018, 2019 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java index f014b9c..cb3e49d 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/NoopTrustManager.java @@ -1,5 +1,5 @@ /** - * Copyright 2018 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client + * Copyright 2018, 2019 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the diff --git a/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java b/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java index 94b3bd1..aeeef50 100644 --- a/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java +++ b/src/test/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilderTest.java @@ -1,5 +1,5 @@ /** - * Copyright 2018 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client + * Copyright 2018, 2019 SourceLab.org https://github.com/SourceLabOrg/kafka-connect-client * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the From 1d28a72713495b68c7105e8da50f28a9ca82866c Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 15:26:54 +0900 Subject: [PATCH 11/14] Update HttpClientRestClient --- .../connect/apiclient/Configuration.java | 27 +++++- .../apiclient/rest/HttpClientRestClient.java | 85 +++++++------------ .../apiclient/rest/HttpsContextBuilder.java | 27 ++++++ 3 files changed, 84 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java index 5d43183..4419712 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java @@ -29,6 +29,9 @@ public final class Configuration { // Defines the URL/Hostname of Kafka-Connect private final String apiHost; + // Optional Connection settings + private int requestTimeoutInSeconds = 300; + // Optional SSL options private boolean ignoreInvalidSslCertificates = false; private File trustStoreFile = null; @@ -115,6 +118,16 @@ public Configuration useTrustStore(final File trustStorePath, final String passw return this; } + /** + * Set the request timeout value, in seconds. + * @param requestTimeoutInSeconds How long before a request times out, in seconds. + * @return Configuration instance. + */ + public Configuration useRequestTimeoutInSeconds(final int requestTimeoutInSeconds) { + this.requestTimeoutInSeconds = requestTimeoutInSeconds; + return this; + } + public String getProxyHost() { return proxyHost; } @@ -151,10 +164,15 @@ public String getTrustStorePassword() { return trustStorePassword; } + public int getRequestTimeoutInSeconds() { + return requestTimeoutInSeconds; + } + @Override public String toString() { final StringBuilder stringBuilder = new StringBuilder("Configuration{") - .append("apiHost='").append(apiHost).append('\''); + .append("apiHost='").append(apiHost).append('\'') + .append(", requestTimeout='").append(requestTimeoutInSeconds).append('\''); if (proxyHost != null) { stringBuilder .append(", proxy='").append(proxyScheme).append("://"); @@ -166,6 +184,13 @@ public String toString() { stringBuilder.append(proxyHost).append(":").append(proxyPort).append('\''); } + stringBuilder.append(", ignoreInvalidSslCertificates='").append(ignoreInvalidSslCertificates).append('\''); + if (trustStoreFile != null) { + stringBuilder.append(", sslTrustStoreFile='").append(trustStoreFile).append('\''); + if (trustStorePassword != null) { + stringBuilder.append(", sslTrustStorePassword='******'"); + } + } stringBuilder.append('}'); return stringBuilder.toString(); diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java index a4bbe98..09cc506 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java @@ -17,6 +17,7 @@ package org.sourcelab.kafka.connect.apiclient.rest; +import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.NameValuePair; import org.apache.http.auth.AuthScope; @@ -30,8 +31,6 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.utils.URIBuilder; -import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; @@ -51,6 +50,8 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -62,6 +63,15 @@ public class HttpClientRestClient implements RestClient { private static final Logger logger = LoggerFactory.getLogger(HttpClientRestClient.class); + /** + * Default headers included with every request. + */ + private static final Collection
DEFAULT_HEADERS = Collections.unmodifiableCollection(Arrays.asList( + new BasicHeader("Accept", "application/json"), + new BasicHeader("Content-Type", "application/json") + )); + + /** * Save a copy of the configuration. */ @@ -72,7 +82,6 @@ public class HttpClientRestClient implements RestClient { */ private CloseableHttpClient httpClient; - /** * Constructor. */ @@ -92,20 +101,14 @@ public void init(final Configuration configuration) { // Create https context builder utility. final HttpsContextBuilder httpsContextBuilder = new HttpsContextBuilder(configuration); - // Allow TLSv1.2, TLSv1.1, TLSv1 protocols - final LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( - httpsContextBuilder.getSslContext(), - new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }, - null, - httpsContextBuilder.getHostnameVerifier() - ); - // Setup client builder final HttpClientBuilder clientBuilder = HttpClientBuilder.create(); clientBuilder - // 3 min timeout? - .setConnectionTimeToLive(300, TimeUnit.SECONDS) - .setSSLSocketFactory(sslSocketFactory); + // Define timeout + .setConnectionTimeToLive(configuration.getRequestTimeoutInSeconds(), TimeUnit.SECONDS) + + // Define SSL Socket Factory instance. + .setSSLSocketFactory(httpsContextBuilder.createSslSocketFactory()); // Define our RequestConfigBuilder final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); @@ -192,7 +195,7 @@ public RestResponse submitRequest(final Request request) throws RestException { * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitGetRequest(final String url, final Map getParams, final ResponseHandler responseHandler) throws IOException { + private T submitGetRequest(final String url, final Map getParams, final ResponseHandler responseHandler) { try { // Construct URI including our request parameters. final URIBuilder uriBuilder = new URIBuilder(url) @@ -206,11 +209,8 @@ private T submitGetRequest(final String url, final Map getPa // Build Get Request final HttpGet get = new HttpGet(uriBuilder.build()); - // Add Accept header. - get.addHeader(new BasicHeader("Accept", "application/json")); - - // Conditionally add content-type header? - get.addHeader(new BasicHeader("Content-Type", "application/json")); + // Add default headers. + DEFAULT_HEADERS.forEach(get::addHeader); logger.debug("Executing request {}", get.getRequestLine()); @@ -233,18 +233,12 @@ private T submitGetRequest(final String url, final Map getPa * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitPostRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) throws IOException { + private T submitPostRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) { try { final HttpPost post = new HttpPost(url); - // Add Accept header. - post.addHeader(new BasicHeader("Accept", "application/json")); - - // Conditionally add content-type header? - post.addHeader(new BasicHeader("Content-Type", "application/json")); - - // Define required auth params - final List params = new ArrayList<>(); + // Add default headers. + DEFAULT_HEADERS.forEach(post::addHeader); // Convert to Json final String jsonPayloadStr = JacksonFactory.newInstance().writeValueAsString(requestBody); @@ -272,19 +266,12 @@ private T submitPostRequest(final String url, final Object requestBody, fina * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitPutRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) throws IOException { + private T submitPutRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) { try { - // Construct URI including our request parameters. - final URIBuilder uriBuilder = new URIBuilder(url) - .setCharset(StandardCharsets.UTF_8); - final HttpPut put = new HttpPut(url); - // Add Accept header. - put.addHeader(new BasicHeader("Accept", "application/json")); - - // Conditionally add content-type header? - put.addHeader(new BasicHeader("Content-Type", "application/json")); + // Add default headers. + DEFAULT_HEADERS.forEach(put::addHeader); // Convert to Json and submit as payload. final String jsonPayloadStr = JacksonFactory.newInstance().writeValueAsString(requestBody); @@ -294,7 +281,7 @@ private T submitPutRequest(final String url, final Object requestBody, final // Execute and return return httpClient.execute(put, responseHandler); - } catch (final ClientProtocolException | SocketException | URISyntaxException connectionException) { + } catch (final ClientProtocolException | SocketException connectionException) { // Typically this is a connection issue. throw new ConnectionException(connectionException.getMessage(), connectionException); } catch (final IOException ioException) { @@ -311,22 +298,12 @@ private T submitPutRequest(final String url, final Object requestBody, final * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitDeleteRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) throws IOException { + private T submitDeleteRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) { try { - // Construct URI including our request parameters. - final URIBuilder uriBuilder = new URIBuilder(url) - .setCharset(StandardCharsets.UTF_8); - final HttpDelete delete = new HttpDelete(url); - // Add Accept header. - delete.addHeader(new BasicHeader("Accept", "application/json")); - - // Conditionally add content-type header? - delete.addHeader(new BasicHeader("Content-Type", "application/json")); - - // Define required auth params - final List params = new ArrayList<>(); + // Add default headers. + DEFAULT_HEADERS.forEach(delete::addHeader); // Convert to Json final String jsonPayloadStr = JacksonFactory.newInstance().writeValueAsString(requestBody); @@ -335,7 +312,7 @@ private T submitDeleteRequest(final String url, final Object requestBody, fi // Execute and return return httpClient.execute(delete, responseHandler); - } catch (final ClientProtocolException | SocketException | URISyntaxException connectionException) { + } catch (final ClientProtocolException | SocketException connectionException) { // Typically this is a connection issue. throw new ConnectionException(connectionException.getMessage(), connectionException); } catch (final IOException ioException) { diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java index 56cc7b3..89c057d 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java @@ -17,6 +17,7 @@ package org.sourcelab.kafka.connect.apiclient.rest; +import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.ssl.SSLContexts; @@ -41,6 +42,11 @@ * Utility for properly configuring the SSL Context based on client configuration settings. */ class HttpsContextBuilder { + /** + * Accept TLS1.2, 1.1, and 1.0 protocols. + */ + private static final String[] sslProtocols = new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }; + /** * Client configuration. */ @@ -114,4 +120,25 @@ SSLContext getSslContext() { return sslcontext; } + + /** + * Get allowed SSL Protocols. + * @return allowed SslProtocols. + */ + private String[] getSslProtocols() { + return sslProtocols; + } + + /** + * Properly configured SslSocketFactory based on client configuration. + * @return SslSocketFactory instance. + */ + LayeredConnectionSocketFactory createSslSocketFactory() { + return new SSLConnectionSocketFactory( + getSslContext(), + getSslProtocols(), + null, + getHostnameVerifier() + ); + } } From 8f648d57165acd8eb5283de9c09f9884191cd041 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 15:29:34 +0900 Subject: [PATCH 12/14] Add back throws statement --- .../connect/apiclient/rest/HttpClientRestClient.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java index 09cc506..0a40b9d 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java @@ -195,7 +195,7 @@ public RestResponse submitRequest(final Request request) throws RestException { * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitGetRequest(final String url, final Map getParams, final ResponseHandler responseHandler) { + private T submitGetRequest(final String url, final Map getParams, final ResponseHandler responseHandler) throws IOException { try { // Construct URI including our request parameters. final URIBuilder uriBuilder = new URIBuilder(url) @@ -233,7 +233,7 @@ private T submitGetRequest(final String url, final Map getPa * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitPostRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) { + private T submitPostRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) throws IOException { try { final HttpPost post = new HttpPost(url); @@ -266,7 +266,7 @@ private T submitPostRequest(final String url, final Object requestBody, fina * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitPutRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) { + private T submitPutRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) throws IOException { try { final HttpPut put = new HttpPut(url); @@ -298,7 +298,7 @@ private T submitPutRequest(final String url, final Object requestBody, final * @param The type that ResponseHandler returns. * @return Parsed response. */ - private T submitDeleteRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) { + private T submitDeleteRequest(final String url, final Object requestBody, final ResponseHandler responseHandler) throws IOException { try { final HttpDelete delete = new HttpDelete(url); From d74a2b7d74e35be0d6b985645e78c018baacd46d Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Tue, 29 Jan 2019 15:30:04 +0900 Subject: [PATCH 13/14] cleanup --- .../kafka/connect/apiclient/rest/HttpClientRestClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java index 0a40b9d..ccf09d3 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java @@ -71,7 +71,6 @@ public class HttpClientRestClient implements RestClient { new BasicHeader("Content-Type", "application/json") )); - /** * Save a copy of the configuration. */ From fa24d262bfc659431b2de1e5ec40e1540b584ace Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Wed, 30 Jan 2019 09:50:48 +0900 Subject: [PATCH 14/14] Add warning log --- .../connect/apiclient/rest/HttpsContextBuilder.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java index 89c057d..6af7564 100644 --- a/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java +++ b/src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java @@ -21,6 +21,8 @@ import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.ssl.SSLContexts; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sourcelab.kafka.connect.apiclient.Configuration; import javax.net.ssl.HostnameVerifier; @@ -42,6 +44,8 @@ * Utility for properly configuring the SSL Context based on client configuration settings. */ class HttpsContextBuilder { + private static final Logger logger = LoggerFactory.getLogger(HttpsContextBuilder.class); + /** * Accept TLS1.2, 1.1, and 1.0 protocols. */ @@ -134,6 +138,11 @@ private String[] getSslProtocols() { * @return SslSocketFactory instance. */ LayeredConnectionSocketFactory createSslSocketFactory() { + // Emit an warning letting everyone know we're using an insecure configuration. + if (configuration.getIgnoreInvalidSslCertificates()) { + logger.warn("Using insecure configuration, skipping server-side certificate validation checks."); + } + return new SSLConnectionSocketFactory( getSslContext(), getSslProtocols(),