diff --git a/src/main/java/com/arangodb/ArangoDB.java b/src/main/java/com/arangodb/ArangoDB.java index e60e9383d..260d939d9 100644 --- a/src/main/java/com/arangodb/ArangoDB.java +++ b/src/main/java/com/arangodb/ArangoDB.java @@ -46,6 +46,7 @@ import com.arangodb.velocystream.Request; import com.arangodb.velocystream.Response; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.io.InputStream; import java.lang.annotation.Annotation; @@ -175,6 +176,17 @@ public Builder sslContext(final SSLContext sslContext) { return this; } + /** + * Sets the {@link javax.net.ssl.HostnameVerifier} to be used when using ssl with http protocol. + * + * @param hostnameVerifier HostnameVerifier to be used + * @return {@link ArangoDB.Builder} + */ + public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) { + setHostnameVerifier(hostnameVerifier); + return this; + } + /** * Sets the chunk size when {@link Protocol#VST} is used. * @@ -571,8 +583,8 @@ public synchronized ArangoDB build() { final ConnectionFactory connectionFactory = (protocol == null || Protocol.VST == protocol) ? new VstConnectionFactorySync(host, timeout, connectionTtl, useSsl, sslContext) - : new HttpConnectionFactory(timeout, user, password, useSsl, sslContext, custom, protocol, - connectionTtl, httpCookieSpec); + : new HttpConnectionFactory(timeout, user, password, useSsl, sslContext, hostnameVerifier, custom, + protocol, connectionTtl, httpCookieSpec); final Collection hostList = createHostList(max, connectionFactory); final HostResolver hostResolver = createHostResolver(hostList, max, connectionFactory); diff --git a/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java b/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java index 75e3bdfab..a8fdd01d3 100644 --- a/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java +++ b/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java @@ -34,6 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.InputStream; @@ -74,6 +75,7 @@ public abstract class InternalArangoDBBuilder { protected Boolean useSsl; protected String httpCookieSpec; protected SSLContext sslContext; + protected HostnameVerifier hostnameVerifier; protected Integer chunksize; protected Integer maxConnections; protected Long connectionTtl; @@ -160,6 +162,10 @@ protected void setSslContext(final SSLContext sslContext) { this.sslContext = sslContext; } + protected void setHostnameVerifier(final HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + } + protected void setChunksize(final Integer chunksize) { this.chunksize = chunksize; } diff --git a/src/main/java/com/arangodb/internal/http/HttpConnection.java b/src/main/java/com/arangodb/internal/http/HttpConnection.java index 398827c62..5c6069d38 100644 --- a/src/main/java/com/arangodb/internal/http/HttpConnection.java +++ b/src/main/java/com/arangodb/internal/http/HttpConnection.java @@ -58,6 +58,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.io.IOException; import java.util.ArrayList; @@ -87,6 +88,7 @@ public static class Builder { private HostDescription host; private Long ttl; private SSLContext sslContext; + private HostnameVerifier hostnameVerifier; private Integer timeout; public Builder user(final String user) { @@ -134,13 +136,18 @@ public Builder sslContext(final SSLContext sslContext) { return this; } + public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + return this; + } + public Builder timeout(final Integer timeout) { this.timeout = timeout; return this; } public HttpConnection build() { - return new HttpConnection(host, timeout, user, password, useSsl, sslContext, util, contentType, ttl, httpCookieSpec); + return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util, contentType, ttl, httpCookieSpec); } } @@ -154,7 +161,7 @@ public HttpConnection build() { private final HostDescription host; private HttpConnection(final HostDescription host, final Integer timeout, final String user, final String password, - final Boolean useSsl, final SSLContext sslContext, final ArangoSerialization util, final Protocol contentType, + final Boolean useSsl, final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol contentType, final Long ttl, final String httpCookieSpec) { super(); this.host = host; @@ -166,11 +173,10 @@ private HttpConnection(final HostDescription host, final Integer timeout, final final RegistryBuilder registryBuilder = RegistryBuilder .create(); if (Boolean.TRUE == useSsl) { - if (sslContext != null) { - registryBuilder.register("https", new SSLConnectionSocketFactory(sslContext)); - } else { - registryBuilder.register("https", new SSLConnectionSocketFactory(SSLContexts.createSystemDefault())); - } + registryBuilder.register("https", new SSLConnectionSocketFactory( + sslContext != null ? sslContext : SSLContexts.createSystemDefault(), + hostnameVerifier != null ? hostnameVerifier : SSLConnectionSocketFactory.getDefaultHostnameVerifier() + )); } else { registryBuilder.register("http", new PlainConnectionSocketFactory()); } diff --git a/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java b/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java index efd42ce23..bab2b8233 100644 --- a/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java +++ b/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java @@ -26,6 +26,7 @@ import com.arangodb.internal.net.HostDescription; import com.arangodb.util.ArangoSerialization; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; /** @@ -36,11 +37,12 @@ public class HttpConnectionFactory implements ConnectionFactory { private final HttpConnection.Builder builder; public HttpConnectionFactory(final Integer timeout, final String user, final String password, final Boolean useSsl, - final SSLContext sslContext, final ArangoSerialization util, final Protocol protocol, + final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol protocol, final Long connectionTtl, String httpCookieSpec) { super(); builder = new HttpConnection.Builder().timeout(timeout).user(user).password(password).useSsl(useSsl) - .sslContext(sslContext).serializationUtil(util).contentType(protocol).ttl(connectionTtl).httpCookieSpec(httpCookieSpec); + .sslContext(sslContext).hostnameVerifier(hostnameVerifier).serializationUtil(util).contentType(protocol) + .ttl(connectionTtl).httpCookieSpec(httpCookieSpec); } diff --git a/src/test/java/com/arangodb/example/ssl/SslExample.java b/src/test/java/com/arangodb/example/ssl/SslExample.java index f1501aad1..7512f30ff 100644 --- a/src/test/java/com/arangodb/example/ssl/SslExample.java +++ b/src/test/java/com/arangodb/example/ssl/SslExample.java @@ -23,6 +23,7 @@ import com.arangodb.ArangoDB; import com.arangodb.Protocol; import com.arangodb.entity.ArangoDBVersion; +import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.junit.Ignore; import org.junit.Test; @@ -55,6 +56,35 @@ public class SslExample { @Test @Ignore public void connect() throws Exception { + final ArangoDB arangoDB = new ArangoDB.Builder() + .host("localhost", 8529) + .password("test") + .useSsl(true) + .sslContext(createSslContext()) + .useProtocol(Protocol.HTTP_JSON) + .build(); + final ArangoDBVersion version = arangoDB.getVersion(); + assertThat(version, is(notNullValue())); + System.out.println(version.getVersion()); + } + + @Test + @Ignore + public void noopHostnameVerifier() throws Exception { + final ArangoDB arangoDB = new ArangoDB.Builder() + .host("127.0.0.1", 8529) + .password("test") + .useSsl(true) + .sslContext(createSslContext()) + .hostnameVerifier(NoopHostnameVerifier.INSTANCE) + .useProtocol(Protocol.HTTP_JSON) + .build(); + final ArangoDBVersion version = arangoDB.getVersion(); + assertThat(version, is(notNullValue())); + System.out.println(version.getVersion()); + } + + private SSLContext createSslContext() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(this.getClass().getResourceAsStream(SSL_TRUSTSTORE), SSL_TRUSTSTORE_PASSWORD.toCharArray()); @@ -67,17 +97,7 @@ public void connect() throws Exception { final SSLContext sc = SSLContext.getInstance("TLS"); sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - final ArangoDB arangoDB = new ArangoDB.Builder() - .host("127.0.0.1", 8529) - .password("test") - .useSsl(true) - .sslContext(sc) - .useProtocol(Protocol.HTTP_JSON) - .build(); - final ArangoDBVersion version = arangoDB.getVersion(); - assertThat(version, is(notNullValue())); - System.out.println(version.getVersion()); + return sc; } }