calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From els...@apache.org
Subject calcite-avatica git commit: [CALCITE-1904] Allow SSL hostname verification to be turned off
Date Thu, 27 Jul 2017 16:26:05 GMT
Repository: calcite-avatica
Updated Branches:
  refs/heads/master 4d0f397a7 -> c3f4611d4


[CALCITE-1904] Allow SSL hostname verification to be turned off

Closes #12


Project: http://git-wip-us.apache.org/repos/asf/calcite-avatica/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite-avatica/commit/c3f4611d
Tree: http://git-wip-us.apache.org/repos/asf/calcite-avatica/tree/c3f4611d
Diff: http://git-wip-us.apache.org/repos/asf/calcite-avatica/diff/c3f4611d

Branch: refs/heads/master
Commit: c3f4611d4e94f50ed2130801c7054e3d109bde4b
Parents: 4d0f397
Author: Josh Elser <elserj@apache.org>
Authored: Thu Jul 27 12:19:05 2017 -0400
Committer: Josh Elser <elserj@apache.org>
Committed: Thu Jul 27 12:19:05 2017 -0400

----------------------------------------------------------------------
 .../avatica/BuiltInConnectionProperty.java      |  6 ++-
 .../calcite/avatica/ConnectionConfig.java       |  3 ++
 .../calcite/avatica/ConnectionConfigImpl.java   |  6 +++
 .../remote/AvaticaCommonsHttpClientImpl.java    | 39 +++++++++++++++-
 .../remote/AvaticaHttpClientFactoryImpl.java    |  9 ++++
 .../HostnameVerificationConfigurable.java       | 47 ++++++++++++++++++++
 .../AvaticaCommonsHttpClientImplTest.java       | 28 ++++++++++++
 7 files changed, 135 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java
b/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java
index d68bae8..1da7025 100644
--- a/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java
+++ b/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.avatica;
 
 import org.apache.calcite.avatica.remote.AvaticaHttpClientFactoryImpl;
+import org.apache.calcite.avatica.remote.HostnameVerificationConfigurable.HostnameVerification;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -73,7 +74,10 @@ public enum BuiltInConnectionProperty implements ConnectionProperty {
   TRUSTSTORE("truststore", Type.STRING, null, false),
 
   /** Password for the truststore */
-  TRUSTSTORE_PASSWORD("truststore_password", Type.STRING, null, false);
+  TRUSTSTORE_PASSWORD("truststore_password", Type.STRING, null, false),
+
+  HOSTNAME_VERIFICATION("hostname_verification", Type.ENUM, HostnameVerification.STRICT,
+      HostnameVerification.class, false);
 
   private final String camelName;
   private final Type type;

http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/main/java/org/apache/calcite/avatica/ConnectionConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/avatica/ConnectionConfig.java b/core/src/main/java/org/apache/calcite/avatica/ConnectionConfig.java
index e8ff0be..cd18ec5 100644
--- a/core/src/main/java/org/apache/calcite/avatica/ConnectionConfig.java
+++ b/core/src/main/java/org/apache/calcite/avatica/ConnectionConfig.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.avatica;
 
 import org.apache.calcite.avatica.remote.AvaticaHttpClientFactory;
+import org.apache.calcite.avatica.remote.HostnameVerificationConfigurable.HostnameVerification;
 import org.apache.calcite.avatica.remote.Service;
 
 import java.io.File;
@@ -53,6 +54,8 @@ public interface ConnectionConfig {
   File truststore();
   /** @see BuiltInConnectionProperty#TRUSTSTORE_PASSWORD */
   String truststorePassword();
+  /** @see BuiltInConnectionProperty#HOSTNAME_VERIFICATION */
+  HostnameVerification hostnameVerification();
 }
 
 // End ConnectionConfig.java

http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java b/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java
index a003b82..63fbd8d 100644
--- a/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java
+++ b/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.avatica;
 
 import org.apache.calcite.avatica.remote.AvaticaHttpClientFactory;
+import org.apache.calcite.avatica.remote.HostnameVerificationConfigurable.HostnameVerification;
 import org.apache.calcite.avatica.remote.Service;
 
 import java.io.File;
@@ -105,6 +106,11 @@ public class ConnectionConfigImpl implements ConnectionConfig {
     return BuiltInConnectionProperty.TRUSTSTORE_PASSWORD.wrap(properties).getString();
   }
 
+  public HostnameVerification hostnameVerification() {
+    return BuiltInConnectionProperty.HOSTNAME_VERIFICATION.wrap(properties)
+        .getEnum(HostnameVerification.class);
+  }
+
   /** Converts a {@link Properties} object containing (name, value)
    * pairs into a map whose keys are
    * {@link org.apache.calcite.avatica.InternalProperty} objects.

http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java
b/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java
index 33872d0..5576847 100644
--- a/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java
+++ b/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java
@@ -31,6 +31,7 @@ import org.apache.http.config.Lookup;
 import org.apache.http.config.RegistryBuilder;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.entity.ContentType;
@@ -55,6 +56,7 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Objects;
 
+import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
 
 /**
@@ -62,7 +64,7 @@ import javax.net.ssl.SSLContext;
  * sent and received across the wire.
  */
 public class AvaticaCommonsHttpClientImpl implements AvaticaHttpClient,
-    UsernamePasswordAuthenticateable, TrustStoreConfigurable {
+    UsernamePasswordAuthenticateable, TrustStoreConfigurable, HostnameVerificationConfigurable
{
   private static final Logger LOG = LoggerFactory.getLogger(AvaticaCommonsHttpClientImpl.class);
 
   // Some basic exposed configurations
@@ -84,6 +86,7 @@ public class AvaticaCommonsHttpClientImpl implements AvaticaHttpClient,
 
   protected File truststore = null;
   protected String truststorePassword = null;
+  protected HostnameVerification hostnameVerification = null;
 
   public AvaticaCommonsHttpClientImpl(URL url) {
     this.host = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
@@ -97,7 +100,10 @@ public class AvaticaCommonsHttpClientImpl implements AvaticaHttpClient,
       try {
         SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(
             truststore, truststorePassword.toCharArray()).build();
-        sslFactory = new SSLConnectionSocketFactory(sslcontext);
+
+        final HostnameVerifier verifier = getHostnameVerifier(hostnameVerification);
+
+        sslFactory = new SSLConnectionSocketFactory(sslcontext, verifier);
       } catch (Exception e) {
         throw new RuntimeException(e);
       }
@@ -128,6 +134,30 @@ public class AvaticaCommonsHttpClientImpl implements AvaticaHttpClient,
     this.client = HttpClients.custom().setConnectionManager(pool).build();
   }
 
+  /**
+   * Creates the {@code HostnameVerifier} given the provided {@code verification}.
+   *
+   * @param verification The intended hostname verification action.
+   * @return A verifier for the request verification.
+   * @throws IllegalArgumentException if the provided verification cannot be handled.
+   */
+  HostnameVerifier getHostnameVerifier(HostnameVerification verification) {
+    // Normally, the configuration logic would give us a default of STRICT if it was not
+    // provided by the user. It's easy for us to do a double-check.
+    if (verification == null) {
+      verification = HostnameVerification.STRICT;
+    }
+    switch (verification) {
+    case STRICT:
+      return SSLConnectionSocketFactory.getDefaultHostnameVerifier();
+    case NONE:
+      return NoopHostnameVerifier.INSTANCE;
+    default:
+      throw new IllegalArgumentException("Unhandled HostnameVerification: "
+          + hostnameVerification);
+    }
+  }
+
   public byte[] send(byte[] request) {
     while (true) {
       HttpClientContext context = HttpClientContext.create();
@@ -216,6 +246,11 @@ public class AvaticaCommonsHttpClientImpl implements AvaticaHttpClient,
     this.truststorePassword = Objects.requireNonNull(password);
     initializeClient();
   }
+
+  @Override public void setHostnameVerification(HostnameVerification verification) {
+    this.hostnameVerification = Objects.requireNonNull(verification);
+    initializeClient();
+  }
 }
 
 // End AvaticaCommonsHttpClientImpl.java

http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
b/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
index 8778c3d..f352ac1 100644
--- a/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
@@ -80,6 +80,15 @@ public class AvaticaHttpClientFactoryImpl implements AvaticaHttpClientFactory
{
       LOG.debug("{} is not capable of SSL/TLS communication", client.getClass().getName());
     }
 
+    // Set the SSL hostname verification if the client supports it
+    if (client instanceof HostnameVerificationConfigurable) {
+      ((HostnameVerificationConfigurable) client)
+          .setHostnameVerification(config.hostnameVerification());
+    } else {
+      LOG.debug("{} is not capable of configurable SSL/TLS hostname verification",
+          client.getClass().getName());
+    }
+
     if (client instanceof UsernamePasswordAuthenticateable) {
       // Shortcircuit quickly if authentication wasn't provided (implies NONE)
       final String authString = config.authentication();

http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/main/java/org/apache/calcite/avatica/remote/HostnameVerificationConfigurable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/avatica/remote/HostnameVerificationConfigurable.java
b/core/src/main/java/org/apache/calcite/avatica/remote/HostnameVerificationConfigurable.java
new file mode 100644
index 0000000..4f6d111
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/avatica/remote/HostnameVerificationConfigurable.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica.remote;
+
+/**
+ * An interface to decorate an {@link AvaticaHttpClient} that can support configuration on
+ * SSL hostname verification.
+ */
+public interface HostnameVerificationConfigurable {
+  /**
+   * Describes the support hostname verification methods of {@link AvaticaHttpClient}.
+   */
+  public enum HostnameVerification {
+    /**
+     * The common name (CN) on the certificate must match the server's hostname.
+     */
+    STRICT,
+    /**
+     * No verification is performed.
+     */
+    NONE,
+  }
+
+  /**
+   * Instructs the {@link AvaticaHttpClient} how to perform hostname verification for SSL
+   * connections.
+   *
+   * @param verification The mode of hostname verification
+   */
+  void setHostnameVerification(HostnameVerification verification);
+}
+
+// End HostnameVerificationConfigurable.java

http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/c3f4611d/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImplTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImplTest.java
b/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImplTest.java
index 990ecd2..9918143 100644
--- a/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImplTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImplTest.java
@@ -16,11 +16,15 @@
  */
 package org.apache.calcite.avatica.remote;
 
+import org.apache.calcite.avatica.remote.HostnameVerificationConfigurable.HostnameVerification;
+
 import org.apache.http.NoHttpResponseException;
 import org.apache.http.StatusLine;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.entity.StringEntity;
 
 import org.junit.Test;
@@ -28,10 +32,14 @@ import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import java.net.HttpURLConnection;
+import javax.net.ssl.HostnameVerifier;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.nullable;
 import static org.mockito.Mockito.when;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
@@ -110,6 +118,26 @@ public class AvaticaCommonsHttpClientImplTest {
     byte[] responseBytes = client.send(requestBytes);
     assertEquals("success", new String(responseBytes, UTF_8));
   }
+
+  @Test public void testHostnameVerification() throws Exception {
+    AvaticaCommonsHttpClientImpl client = mock(AvaticaCommonsHttpClientImpl.class);
+    // Call the real method
+    when(client.getHostnameVerifier(nullable(HostnameVerification.class)))
+        .thenCallRealMethod();
+
+    // No verification should give the default (strict) verifier
+    HostnameVerifier actualVerifier = client.getHostnameVerifier(null);
+    assertNotNull(actualVerifier);
+    assertTrue(actualVerifier instanceof DefaultHostnameVerifier);
+
+    actualVerifier = client.getHostnameVerifier(HostnameVerification.STRICT);
+    assertNotNull(actualVerifier);
+    assertTrue(actualVerifier instanceof DefaultHostnameVerifier);
+
+    actualVerifier = client.getHostnameVerifier(HostnameVerification.NONE);
+    assertNotNull(actualVerifier);
+    assertTrue(actualVerifier instanceof NoopHostnameVerifier);
+  }
 }
 
 // End AvaticaCommonsHttpClientImplTest.java


Mime
View raw message