diff options
author | Bjørn Christian Seime <bjorn.christian@seime.no> | 2020-11-25 13:56:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-25 13:56:14 +0100 |
commit | 7f6172f425200fa41c9dbc08a5c183225e2e663c (patch) | |
tree | 9326faebdc0e54618e1040e88b565f7a905928a6 /http-utils | |
parent | 67cb7157535233e86b5c57db534ffbffeac4d20a (diff) |
Revert "Revert "Bjorncs/config convergence checker preps""
Diffstat (limited to 'http-utils')
-rw-r--r-- | http-utils/pom.xml | 5 | ||||
-rw-r--r-- | http-utils/src/main/java/ai/vespa/util/http/VespaAsyncHttpClientBuilder.java | 95 |
2 files changed, 100 insertions, 0 deletions
diff --git a/http-utils/pom.xml b/http-utils/pom.xml index 6d2e009cf8c..aa261574285 100644 --- a/http-utils/pom.xml +++ b/http-utils/pom.xml @@ -38,6 +38,11 @@ <artifactId>httpcore</artifactId> <scope>compile</scope> </dependency> + <dependency> + <groupId>org.apache.httpcomponents.client5</groupId> + <artifactId>httpclient5</artifactId> + <scope>compile</scope> + </dependency> <!-- test scope --> <dependency> diff --git a/http-utils/src/main/java/ai/vespa/util/http/VespaAsyncHttpClientBuilder.java b/http-utils/src/main/java/ai/vespa/util/http/VespaAsyncHttpClientBuilder.java new file mode 100644 index 00000000000..51e83bd870a --- /dev/null +++ b/http-utils/src/main/java/ai/vespa/util/http/VespaAsyncHttpClientBuilder.java @@ -0,0 +1,95 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.util.http; + +import com.yahoo.security.tls.MixedMode; +import com.yahoo.security.tls.TlsContext; +import com.yahoo.security.tls.TransportSecurityUtils; +import org.apache.hc.client5.http.HttpRoute; +import org.apache.hc.client5.http.impl.DefaultSchemePortResolver; +import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner; +import org.apache.hc.client5.http.nio.AsyncClientConnectionManager; +import org.apache.hc.client5.http.routing.HttpRoutePlanner; +import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http.protocol.HttpContext; + +import javax.net.ssl.SSLParameters; + +/** + * Async http client builder for internal Vespa communications over http/https. + * Configures Vespa mTLS and handles TLS mixed mode automatically. + * Client should only be used for requests to Vespa services. + * + * Caveats: + * - custom connection manager must be configured through {@link #create(AsyncConnectionManagerFactory)}. + * + * @author bjorncs + */ +public class VespaAsyncHttpClientBuilder { + + public interface AsyncConnectionManagerFactory { + AsyncClientConnectionManager create(TlsStrategy tlsStrategy); + } + + public static HttpAsyncClientBuilder create() { + return create( + tlsStrategy -> PoolingAsyncClientConnectionManagerBuilder.create() + .setTlsStrategy(tlsStrategy) + .build()); + } + + public static HttpAsyncClientBuilder create(AsyncConnectionManagerFactory factory) { + HttpAsyncClientBuilder clientBuilder = HttpAsyncClientBuilder.create(); + TlsContext vespaTlsContext = TransportSecurityUtils.createTlsContext().orElse(null); + TlsStrategy tlsStrategy; + if (vespaTlsContext != null) { + SSLParameters vespaTlsParameters = vespaTlsContext.parameters(); + tlsStrategy = ClientTlsStrategyBuilder.create() + .setHostnameVerifier(new NoopHostnameVerifier()) + .setSslContext(vespaTlsContext.context()) + .setTlsVersions(vespaTlsParameters.getProtocols()) + .setCiphers(vespaTlsParameters.getCipherSuites()) + .build(); + if (TransportSecurityUtils.getInsecureMixedMode() != MixedMode.PLAINTEXT_CLIENT_MIXED_SERVER) { + clientBuilder.setRoutePlanner(new HttpToHttpsRoutePlanner()); + } + } else { + tlsStrategy = ClientTlsStrategyBuilder.create().build(); + } + clientBuilder.disableConnectionState(); // Share connections between subsequent requests + clientBuilder.disableCookieManagement(); + clientBuilder.disableAuthCaching(); + clientBuilder.disableRedirectHandling(); + clientBuilder.setConnectionManager(factory.create(tlsStrategy)); + return clientBuilder; + } + + private static class HttpToHttpsRoutePlanner implements HttpRoutePlanner { + + private final DefaultRoutePlanner defaultPlanner = new DefaultRoutePlanner(new DefaultSchemePortResolver()); + + @Override + public HttpRoute determineRoute(HttpHost target, HttpContext context) throws HttpException { + HttpRoute originalRoute = defaultPlanner.determineRoute(target, context); + HttpHost originalHost = originalRoute.getTargetHost(); + String originalScheme = originalHost.getSchemeName(); + String rewrittenScheme = originalScheme.equalsIgnoreCase("http") ? "https" : originalScheme; + boolean rewrittenSecure = target.getSchemeName().equalsIgnoreCase("https"); + HttpHost rewrittenHost = new HttpHost( + rewrittenScheme, originalHost.getAddress(), originalHost.getHostName(), originalHost.getPort()); + return new HttpRoute( + rewrittenHost, + originalRoute.getLocalAddress(), + originalRoute.getProxyHost(), + rewrittenSecure, + originalRoute.getTunnelType(), + originalRoute.getLayerType()); + } + } + +} |