aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-feed-client
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-05-25 17:33:50 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-05-25 17:33:50 +0200
commit6115afc38ac577eea18c63d33ebc9d5b0193dcb3 (patch)
treeb731bb980f9b66cc69206ff9e305fdb592b9ead2 /vespa-feed-client
parent34dfcc026213e0a5a4f7c7d1ec6e56d34438d892 (diff)
Allow configuration of crypto material through PEM files
Diffstat (limited to 'vespa-feed-client')
-rw-r--r--vespa-feed-client/src/main/java/ai/vespa/feed/client/FeedClientBuilder.java28
-rw-r--r--vespa-feed-client/src/main/java/ai/vespa/feed/client/HttpFeedClient.java29
2 files changed, 47 insertions, 10 deletions
diff --git a/vespa-feed-client/src/main/java/ai/vespa/feed/client/FeedClientBuilder.java b/vespa-feed-client/src/main/java/ai/vespa/feed/client/FeedClientBuilder.java
index 95a49abcc25..3cd3f3cb4ca 100644
--- a/vespa-feed-client/src/main/java/ai/vespa/feed/client/FeedClientBuilder.java
+++ b/vespa-feed-client/src/main/java/ai/vespa/feed/client/FeedClientBuilder.java
@@ -3,7 +3,10 @@ package ai.vespa.feed.client;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
+import java.io.IOException;
+import java.io.UncheckedIOException;
import java.net.URI;
+import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
@@ -27,6 +30,9 @@ public class FeedClientBuilder {
int maxConnections = 4;
int maxStreamsPerConnection = 1024;
FeedClient.RetryStrategy retryStrategy = defaultRetryStrategy;
+ Path certificate;
+ Path privateKey;
+ Path caCertificates;
public static FeedClientBuilder create(URI endpoint) { return new FeedClientBuilder(endpoint); }
@@ -63,6 +69,9 @@ public class FeedClientBuilder {
}
public FeedClientBuilder setSslContext(SSLContext context) {
+ if (certificate != null || caCertificates != null || privateKey != null) {
+ throw new IllegalArgumentException("Cannot set both SSLContext and certificate / CA certificates");
+ }
this.sslContext = requireNonNull(context);
return this;
}
@@ -86,8 +95,25 @@ public class FeedClientBuilder {
return this;
}
+ public FeedClientBuilder setCertificate(Path certificatePemFile, Path privateKeyPemFile) {
+ if (sslContext != null) throw new IllegalArgumentException("Cannot set both SSLContext and certificate");
+ this.certificate = certificatePemFile;
+ this.privateKey = privateKeyPemFile;
+ return this;
+ }
+
+ public FeedClientBuilder setCaCertificates(Path caCertificatesFile) {
+ if (sslContext != null) throw new IllegalArgumentException("Cannot set both SSLContext and CA certificate");
+ this.caCertificates = caCertificatesFile;
+ return this;
+ }
+
public FeedClient build() {
- return new HttpFeedClient(this);
+ try {
+ return new HttpFeedClient(this);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
}
diff --git a/vespa-feed-client/src/main/java/ai/vespa/feed/client/HttpFeedClient.java b/vespa-feed-client/src/main/java/ai/vespa/feed/client/HttpFeedClient.java
index 64b99961e61..98edc32a107 100644
--- a/vespa-feed-client/src/main/java/ai/vespa/feed/client/HttpFeedClient.java
+++ b/vespa-feed-client/src/main/java/ai/vespa/feed/client/HttpFeedClient.java
@@ -19,6 +19,7 @@ import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
+import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
@@ -48,7 +49,7 @@ class HttpFeedClient implements FeedClient {
private final CloseableHttpAsyncClient httpClient;
private final AtomicBoolean closed = new AtomicBoolean();
- HttpFeedClient(FeedClientBuilder builder) {
+ HttpFeedClient(FeedClientBuilder builder) throws IOException {
this.endpoint = builder.endpoint;
this.requestHeaders = new HashMap<>(builder.requestHeaders);
@@ -57,7 +58,7 @@ class HttpFeedClient implements FeedClient {
this.httpClient.start();
}
- private static CloseableHttpAsyncClient createHttpClient(FeedClientBuilder builder, HttpRequestStrategy retryStrategy) {
+ private static CloseableHttpAsyncClient createHttpClient(FeedClientBuilder builder, HttpRequestStrategy retryStrategy) throws IOException {
HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create()
.setUserAgent(String.format("vespa-feed-client/%s", Vespa.VERSION))
.setDefaultHeaders(Collections.singletonList(new BasicHeader("Vespa-Client-Version", Vespa.VERSION)))
@@ -86,18 +87,28 @@ class HttpFeedClient implements FeedClient {
.setMaxConnTotal(builder.maxConnections)
.setMaxConnPerRoute(builder.maxConnections)
.setPoolConcurrencyPolicy(PoolConcurrencyPolicy.LAX);
- if (builder.sslContext != null) {
- ClientTlsStrategyBuilder tlsStrategyBuilder = ClientTlsStrategyBuilder.create()
- .setSslContext(builder.sslContext);
- if (builder.hostnameVerifier != null) {
- tlsStrategyBuilder.setHostnameVerifier(builder.hostnameVerifier);
- }
- connectionManagerBuilder.setTlsStrategy(tlsStrategyBuilder.build());
+ ClientTlsStrategyBuilder tlsStrategyBuilder = ClientTlsStrategyBuilder.create()
+ .setSslContext(constructSslContext(builder));
+ if (builder.hostnameVerifier != null) {
+ tlsStrategyBuilder.setHostnameVerifier(builder.hostnameVerifier);
}
+ connectionManagerBuilder.setTlsStrategy(tlsStrategyBuilder.build());
httpClientBuilder.setConnectionManager(connectionManagerBuilder.build());
return httpClientBuilder.build();
}
+ private static SSLContext constructSslContext(FeedClientBuilder builder) throws IOException {
+ if (builder.sslContext != null) return builder.sslContext;
+ SslContextBuilder sslContextBuilder = new SslContextBuilder();
+ if (builder.certificate != null && builder.privateKey != null) {
+ sslContextBuilder.withCertificateAndKey(builder.certificate, builder.privateKey);
+ }
+ if (builder.caCertificates != null) {
+ sslContextBuilder.withCaCertificates(builder.caCertificates);
+ }
+ return sslContextBuilder.build();
+ }
+
@Override
public CompletableFuture<Result> put(DocumentId documentId, String documentJson, OperationParameters params) {
return send("POST", documentId, requireNonNull(documentJson), params);