Skip to content

Commit f64b161

Browse files
authored
Merge pull request #14 from SourceLabOrg/sp/sslClient
Add support for communicating with SSL enabled Kafka-Connect REST instances.
2 parents 996a1ab + fa24d26 commit f64b161

File tree

9 files changed

+401
-29
lines changed

9 files changed

+401
-29
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
The format is based on [Keep a Changelog](http://keepachangelog.com/)
33
and this project adheres to [Semantic Versioning](http://semver.org/).
44

5-
## 1.0.4 (UNRELEASED)
5+
## 1.1.0 (UNRELEASED)
6+
7+
### New Features
8+
- Added ability to communicate with Kafka-Connect REST endpoints using SSL. More can be found in README.
69

710
### Internal Dependency Updates
811
- Updated Guava from 24.0-JRE to 25.0-JRE for [CVE-2018-10237](https://github.com/google/guava/wiki/CVE-2018-10237).

README.md

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@ This client library is released on Maven Central. Add a new dependency to your
1515
<dependency>
1616
<groupId>org.sourcelab</groupId>
1717
<artifactId>kafka-connect-client</artifactId>
18-
<version>1.0.3</version>
18+
<version>1.1.0</version>
1919
</dependency>
2020
```
2121

22-
Example Code:
22+
23+
#### Example Code:
2324
```java
2425
/*
2526
* Create a new configuration object.
2627
*
2728
* This configuration also allows you to define some optional details on your connection,
28-
* such as using an outbound proxy (authenticated or not).
29+
* such as using an outbound proxy (authenticated or not), SSL client settings, etc..
2930
*/
30-
final Configuration configuration = new Configuration("hostname.for.kafka-connect.service.com:8083");
31+
final Configuration configuration = new Configuration("http://hostname.for.kafka-connect.service.com:8083");
3132

3233
/*
3334
* Create an instance of KafkaConnectClient, passing your configuration.
@@ -51,10 +52,47 @@ final ConnectorDefinition connectorDefition = client.addConnector(NewConnectorDe
5152
.withConfig("topics", "test-topic")
5253
.build()
5354
));
55+
56+
/*
57+
* See KafkaConnectClient for other available operations.
58+
*/
5459
```
5560

5661
Public methods available on KafkaConnectClient can be [found here](src/main/java/org/sourcelab/kafka/connect/apiclient/KafkaConnectClient.java#L62)
5762

63+
64+
#### Communicating with HTTPS enabled Kafka-Connect REST server:
65+
```java
66+
/*
67+
* Create a new configuration object.
68+
*/
69+
final Configuration configuration = new Configuration("https://hostname.for.kafka-connect.service.com:8083");
70+
71+
/*
72+
* If your JVM's TrustStore has already been updated to accept the certificate installed on your Kafka-Connect
73+
* instance, then no further configuration is required. Typically this is done using the 'key-tool' command.
74+
*
75+
* Alternatively, you can configure the path to JKS formatted TrustStore file to validate the host's certificate
76+
* with.
77+
*/
78+
configuration.useTrustStore(
79+
new File("/path/to/truststore.jks"), "TrustStorePasswordHere or NULL"
80+
);
81+
82+
/*
83+
* Optionally instead of providing a TrustStore, you can disable all verifications of Kafka-Connect's SSL certificates.
84+
*
85+
* Doing this is HIGHLY DISCOURAGED!
86+
*/
87+
//configuration.useInsecureSslCertificates();
88+
89+
/*
90+
* Create an instance of KafkaConnectClient, passing your configuration.
91+
*/
92+
final KafkaConnectClient client = new KafkaConnectClient(configuration);
93+
94+
```
95+
5896
## Changelog
5997

6098
The format is based on [Keep a Changelog](http://keepachangelog.com/)

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.sourcelab</groupId>
88
<artifactId>kafka-connect-client</artifactId>
9-
<version>1.0.4-SNAPSHOT</version>
9+
<version>1.1.0-SNAPSHOT</version>
1010
<packaging>jar</packaging>
1111

1212
<!-- Require Maven 3.3.9 -->

src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
package org.sourcelab.kafka.connect.apiclient;
1919

20+
import java.io.File;
21+
import java.util.Objects;
22+
2023
/**
2124
* Configure your Kafka Connect API client.
2225
*
@@ -26,6 +29,14 @@ public final class Configuration {
2629
// Defines the URL/Hostname of Kafka-Connect
2730
private final String apiHost;
2831

32+
// Optional Connection settings
33+
private int requestTimeoutInSeconds = 300;
34+
35+
// Optional SSL options
36+
private boolean ignoreInvalidSslCertificates = false;
37+
private File trustStoreFile = null;
38+
private String trustStorePassword = null;
39+
2940
// Optional Proxy Configuration
3041
private String proxyHost = null;
3142
private int proxyPort = 0;
@@ -45,10 +56,11 @@ public Configuration(final String kafkaConnectHost) {
4556
}
4657

4758
// Normalize into "http://<hostname>"
48-
if (!kafkaConnectHost.startsWith("http://")) {
49-
this.apiHost = "http://" + kafkaConnectHost;
50-
} else {
59+
if (kafkaConnectHost.startsWith("http://") || kafkaConnectHost.startsWith("https://")) {
5160
this.apiHost = kafkaConnectHost;
61+
} else {
62+
// Assume http protocol
63+
this.apiHost = "http://" + kafkaConnectHost;
5264
}
5365
}
5466

@@ -80,6 +92,42 @@ public Configuration useProxyAuthentication(final String proxyUsername, final St
8092
return this;
8193
}
8294

95+
/**
96+
* Skip all validation of SSL Certificates. This is insecure and highly discouraged!
97+
*
98+
* @return Configuration instance.
99+
*/
100+
public Configuration useInsecureSslCertificates() {
101+
this.ignoreInvalidSslCertificates = true;
102+
return this;
103+
}
104+
105+
/**
106+
* You can supply a path to a JKS trust store to be used to validate SSL certificates with.
107+
*
108+
* Alternatively you can can explicitly add your certificate to the JVM's truststore using a command like:
109+
* keytool -importcert -keystore truststore.jks -file servercert.pem
110+
*
111+
* @param trustStorePath file path to truststore.
112+
* @param password (optional) Password for truststore.
113+
* @return Configuration instance.
114+
*/
115+
public Configuration useTrustStore(final File trustStorePath, final String password) {
116+
this.trustStoreFile = Objects.requireNonNull(trustStorePath);
117+
this.trustStorePassword = password;
118+
return this;
119+
}
120+
121+
/**
122+
* Set the request timeout value, in seconds.
123+
* @param requestTimeoutInSeconds How long before a request times out, in seconds.
124+
* @return Configuration instance.
125+
*/
126+
public Configuration useRequestTimeoutInSeconds(final int requestTimeoutInSeconds) {
127+
this.requestTimeoutInSeconds = requestTimeoutInSeconds;
128+
return this;
129+
}
130+
83131
public String getProxyHost() {
84132
return proxyHost;
85133
}
@@ -104,10 +152,27 @@ public String getApiHost() {
104152
return apiHost;
105153
}
106154

155+
public boolean getIgnoreInvalidSslCertificates() {
156+
return ignoreInvalidSslCertificates;
157+
}
158+
159+
public File getTrustStoreFile() {
160+
return trustStoreFile;
161+
}
162+
163+
public String getTrustStorePassword() {
164+
return trustStorePassword;
165+
}
166+
167+
public int getRequestTimeoutInSeconds() {
168+
return requestTimeoutInSeconds;
169+
}
170+
107171
@Override
108172
public String toString() {
109173
final StringBuilder stringBuilder = new StringBuilder("Configuration{")
110-
.append("apiHost='").append(apiHost).append('\'');
174+
.append("apiHost='").append(apiHost).append('\'')
175+
.append(", requestTimeout='").append(requestTimeoutInSeconds).append('\'');
111176
if (proxyHost != null) {
112177
stringBuilder
113178
.append(", proxy='").append(proxyScheme).append("://");
@@ -119,6 +184,13 @@ public String toString() {
119184

120185
stringBuilder.append(proxyHost).append(":").append(proxyPort).append('\'');
121186
}
187+
stringBuilder.append(", ignoreInvalidSslCertificates='").append(ignoreInvalidSslCertificates).append('\'');
188+
if (trustStoreFile != null) {
189+
stringBuilder.append(", sslTrustStoreFile='").append(trustStoreFile).append('\'');
190+
if (trustStorePassword != null) {
191+
stringBuilder.append(", sslTrustStorePassword='******'");
192+
}
193+
}
122194
stringBuilder.append('}');
123195

124196
return stringBuilder.toString();

src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,11 @@
3030
import org.apache.http.client.methods.HttpPost;
3131
import org.apache.http.client.methods.HttpPut;
3232
import org.apache.http.client.utils.URIBuilder;
33-
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
34-
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
3533
import org.apache.http.entity.StringEntity;
3634
import org.apache.http.impl.client.BasicCredentialsProvider;
3735
import org.apache.http.impl.client.CloseableHttpClient;
3836
import org.apache.http.impl.client.HttpClientBuilder;
3937
import org.apache.http.message.BasicHeader;
40-
import org.apache.http.ssl.SSLContexts;
4138
import org.slf4j.Logger;
4239
import org.slf4j.LoggerFactory;
4340
import org.sourcelab.kafka.connect.apiclient.Configuration;
@@ -47,7 +44,6 @@
4744
import org.sourcelab.kafka.connect.apiclient.rest.exceptions.ResultParsingException;
4845
import org.sourcelab.kafka.connect.apiclient.rest.handlers.RestResponseHandler;
4946

50-
import javax.net.ssl.SSLContext;
5147
import java.io.IOException;
5248
import java.net.SocketException;
5349
import java.net.URISyntaxException;
@@ -98,23 +94,17 @@ public void init(final Configuration configuration) {
9894
// Save reference to configuration
9995
this.configuration = configuration;
10096

101-
// Create default SSLContext
102-
final SSLContext sslcontext = SSLContexts.createDefault();
103-
104-
// Allow TLSv1 protocol only
105-
final LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
106-
sslcontext,
107-
new String[] { "TLSv1" },
108-
null,
109-
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
110-
);
97+
// Create https context builder utility.
98+
final HttpsContextBuilder httpsContextBuilder = new HttpsContextBuilder(configuration);
11199

112100
// Setup client builder
113101
final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
114102
clientBuilder
115-
// 3 min timeout?
116-
.setConnectionTimeToLive(300, TimeUnit.SECONDS)
117-
.setSSLSocketFactory(sslSocketFactory);
103+
// Define timeout
104+
.setConnectionTimeToLive(configuration.getRequestTimeoutInSeconds(), TimeUnit.SECONDS)
105+
106+
// Define SSL Socket Factory instance.
107+
.setSSLSocketFactory(httpsContextBuilder.createSslSocketFactory());
118108

119109
// Define our RequestConfigBuilder
120110
final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();

0 commit comments

Comments
 (0)