You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by jb...@apache.org on 2022/04/06 19:11:19 UTC

[geode] branch develop updated: GEODE-9991: Refactor for consistency and add tests. (#7533)

This is an automated email from the ASF dual-hosted git repository.

jbarrett pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 75ea5f7f6f GEODE-9991: Refactor for consistency and add tests. (#7533)
75ea5f7f6f is described below

commit 75ea5f7f6f8f6cbd751463dfaab6342762858c58
Author: Jacob Barrett <jb...@pivotal.io>
AuthorDate: Wed Apr 6 12:11:11 2022 -0700

    GEODE-9991: Refactor for consistency and add tests. (#7533)
    
    * Combine common configuration into method for consistency.
    * Adds tests for new extracted methods.
---
 .../org/apache/geode/internal/net/SSLConfig.java   |  40 +++-
 .../apache/geode/internal/net/SocketCreator.java   | 158 +++++--------
 .../apache/geode/internal/net/SSLConfigTest.java   |  49 ++++
 .../geode/internal/net/SocketCreatorTest.java      | 247 +++++++++++++++++----
 4 files changed, 354 insertions(+), 140 deletions(-)

diff --git a/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java b/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java
index 4d32c6e416..a807d545cf 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfig.java
@@ -192,21 +192,54 @@ public class SSLConfig {
   }
 
   /**
-   * Returns true if ciphers is either null, empty or is set to "any" (ignoring case)
+   * Checks if "any" cipher is specified in {@link #getCiphers()}
+   *
+   * @return {@code true} if ciphers is either {@code null}, empty or is set to "any"
+   *         (ignoring case), otherwise {@code false}.
    */
   public boolean isAnyCiphers() {
+    return isAnyCiphers(ciphers);
+  }
+
+  /**
+   * Checks if "any" cipher is specified in {@code ciphers}.
+   *
+   * @param ciphers Comma or space separated list of cipher names.
+   * @return {@code true} if {@code ciphers} is either {@code null}, empty or is set to "any"
+   *         (ignoring case), otherwise {@code false}.
+   */
+  public static boolean isAnyCiphers(final String ciphers) {
     return StringUtils.isBlank(ciphers) || "any".equalsIgnoreCase(ciphers);
   }
 
   /**
-   * Returns true if protocols is either null, empty or is set to "any" (ignoring case)
+   * Checks if "any" cipher is specified in {@code ciphers}.
+   *
+   * @param ciphers Array of cipher names.
+   * @return {@code true} if {@code ciphers} is either {@code null}, empty or first entry is "any"
+   *         (ignoring case), otherwise {@code false}.
+   */
+  public static boolean isAnyCiphers(final String... ciphers) {
+    return ArrayUtils.isEmpty(ciphers) || "any".equalsIgnoreCase(ciphers[0]);
+  }
+
+  /**
+   * Checks if "any" protocol is specified in {@code protocols}.
+   *
+   * @param protocols Comma or space separated list of protocol names.
+   * @return {@code true} if {@code protocols} is either {@code null}, empty or is set to "any"
+   *         (ignoring case), otherwise {@code false}.
    */
   public static boolean isAnyProtocols(final String protocols) {
     return StringUtils.isBlank(protocols) || "any".equalsIgnoreCase(protocols);
   }
 
   /**
-   * Returns true if protocols is either null, empty or is set to "any" (ignoring case)
+   * Checks if "any" protocol is specified in {@code protocols}.
+   *
+   * @param protocols Array of protocol names.
+   * @return {@code true} if {@code protocols} is either {@code null}, empty or first entry is "any"
+   *         (ignoring case), otherwise {@code false}.
    */
   public static boolean isAnyProtocols(final String... protocols) {
     return ArrayUtils.isEmpty(protocols) || "any".equalsIgnoreCase(protocols[0]);
@@ -394,7 +427,6 @@ public class SSLConfig {
       SSLParameterExtension sslParameterExtension =
           CallbackInstantiator.getObjectOfTypeFromClassName(sslParameterExtensionConfig,
               SSLParameterExtension.class);
-      ids.getConfig().getDistributedSystemId();
 
       sslParameterExtension.init(
           new SSLParameterExtensionContextImpl(ids.getConfig().getDistributedSystemId()));
diff --git a/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java b/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java
index 097cc2afd8..89795b5377 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java
@@ -12,9 +12,10 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.geode.internal.net;
 
+package org.apache.geode.internal.net;
 
+import static org.apache.commons.lang3.ObjectUtils.getIfNull;
 import static org.apache.geode.internal.net.filewatch.FileWatchingX509ExtendedKeyManager.newFileWatchingKeyManager;
 import static org.apache.geode.internal.net.filewatch.FileWatchingX509ExtendedTrustManager.newFileWatchingTrustManager;
 
@@ -76,7 +77,6 @@ import org.apache.geode.logging.internal.log4j.api.LogService;
 import org.apache.geode.net.SSLParameterExtension;
 import org.apache.geode.util.internal.GeodeGlossary;
 
-
 /**
  * SocketCreators are built using a SocketCreatorFactory using Geode distributed-system properties.
  * They know how to properly configure sockets for TLS (SSL) communications and perform
@@ -115,17 +115,16 @@ public class SocketCreator extends TcpSocketCreatorImpl {
    * Only print this SocketCreator's config once
    */
   private boolean configShown = false;
+
   /**
    * Only print hostname validation disabled log once
    */
   private boolean hostnameValidationDisabledLogShown = false;
 
-
   private SSLContext sslContext;
 
   private final SSLConfig sslConfig;
 
-
   private ClientSocketFactory clientSocketFactory;
 
   /**
@@ -136,10 +135,6 @@ public class SocketCreator extends TcpSocketCreatorImpl {
   public static final boolean ENABLE_TCP_KEEP_ALIVE =
       AdvancedSocketCreatorImpl.ENABLE_TCP_KEEP_ALIVE;
 
-  // -------------------------------------------------------------------------
-  // Static instance accessors
-  // -------------------------------------------------------------------------
-
   /**
    * This method has migrated to LocalHostUtil but is kept in place here for
    * backward-compatibility testing.
@@ -152,16 +147,15 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     return LocalHostUtil.getLocalHost();
   }
 
-
   /**
    * returns the host name for the given inet address, using a local cache of names to avoid dns
    * hits and duplicate strings
    */
-  public static String getHostName(InetAddress addr) {
-    String result = hostNames.get(addr);
+  public static String getHostName(InetAddress address) {
+    String result = hostNames.get(address);
     if (result == null) {
-      result = addr.getHostName();
-      hostNames.put(addr, result);
+      result = address.getHostName();
+      hostNames.put(address, result);
     }
     return result;
   }
@@ -173,11 +167,6 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     hostNames.clear();
   }
 
-
-  // -------------------------------------------------------------------------
-  // Constructor
-  // -------------------------------------------------------------------------
-
   /**
    * Constructs new SocketCreator instance.
    */
@@ -194,15 +183,11 @@ public class SocketCreator extends TcpSocketCreatorImpl {
 
   /** returns the hostname or address for this client */
   public static String getClientHostName() throws UnknownHostException {
-    InetAddress hostAddr = LocalHostUtil.getLocalHost();
-    return SocketCreator.use_client_host_name ? hostAddr.getCanonicalHostName()
-        : hostAddr.getHostAddress();
+    InetAddress address = LocalHostUtil.getLocalHost();
+    return SocketCreator.use_client_host_name ? address.getCanonicalHostName()
+        : address.getHostAddress();
   }
 
-  // -------------------------------------------------------------------------
-  // Initializers (change SocketCreator state)
-  // -------------------------------------------------------------------------
-
   protected void initializeCreators() {
     clusterSocketCreator = new SCClusterSocketCreator(this);
     clientSocketCreator = new SCClientSocketCreator(this);
@@ -348,10 +333,6 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     return sslConfig.isEnabled();
   }
 
-  // -------------------------------------------------------------------------
-  // Public methods
-  // -------------------------------------------------------------------------
-
   /**
    * Returns an SSLEngine that can be used to perform TLS handshakes and communication
    */
@@ -375,7 +356,7 @@ public class SocketCreator extends TcpSocketCreatorImpl {
       final int port, final boolean clientSocket) {
     if (sslConfig.doEndpointIdentification()) {
       // set server-names so that endpoint identification algorithms can find what's expected
-      setServerNames(parameters, new HostAndPort(hostName, port));
+      addServerNameIfNotSet(parameters, new HostAndPort(hostName, port));
     }
 
     if (clientSocket) {
@@ -384,16 +365,9 @@ public class SocketCreator extends TcpSocketCreatorImpl {
       parameters.setNeedClientAuth(sslConfig.isRequireAuth());
     }
 
-    final String[] protocols = clientSocket ? sslConfig.getClientProtocolsAsStringArray()
-        : sslConfig.getServerProtocolsAsStringArray();
-    if (!SSLConfig.isAnyProtocols(protocols)) {
-      parameters.setProtocols(protocols);
-    }
+    configureProtocols(clientSocket, parameters);
 
-    final String[] ciphers = sslConfig.getCiphersAsStringArray();
-    if (ciphers != null && !"any".equalsIgnoreCase(ciphers[0])) {
-      parameters.setCipherSuites(ciphers);
-    }
+    configureCipherSuites(parameters);
   }
 
   /**
@@ -404,7 +378,7 @@ public class SocketCreator extends TcpSocketCreatorImpl {
    * @param socketChannel the socket's NIO channel
    * @param engine the sslEngine (see createSSLEngine)
    * @param timeout handshake timeout in milliseconds. No timeout if <= 0
-   * @param peerNetBuffer the buffer to use in reading data fron socketChannel. This should also be
+   * @param peerNetBuffer the buffer to use in reading data from socketChannel. This should also be
    *        used in subsequent I/O operations
    * @return The SSLEngine to be used in processing data for sending/receiving from the channel
    */
@@ -452,13 +426,10 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     return nioSslEngine;
   }
 
-  /**
-   * @return true if the parameters have been modified by this method
-   */
-  private boolean checkAndEnableHostnameValidation(SSLParameters sslParameters) {
+  void checkAndEnableHostnameValidation(final SSLParameters sslParameters) {
     if (sslConfig.doEndpointIdentification()) {
       sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
-      return true;
+      return;
     }
     if (!hostnameValidationDisabledLogShown) {
       logger.info("Your SSL configuration disables hostname validation. "
@@ -466,7 +437,6 @@ public class SocketCreator extends TcpSocketCreatorImpl {
           + "Please refer to the Apache GEODE SSL Documentation for SSL Property: ssl‑endpoint‑identification‑enabled");
       hostnameValidationDisabledLogShown = true;
     }
-    return false;
   }
 
   /**
@@ -514,11 +484,11 @@ public class SocketCreator extends TcpSocketCreatorImpl {
    * client/server/advanced interfaces because it references WAN classes that aren't
    * available to them.
    */
-  public ServerSocket createServerSocket(int nport, int backlog, InetAddress bindAddr,
+  public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddress,
       List<GatewayTransportFilter> transportFilters, int socketBufferSize) throws IOException {
     if (transportFilters.isEmpty()) {
       return ((SCClusterSocketCreator) forCluster())
-          .createServerSocket(nport, backlog, bindAddr, socketBufferSize, useSSL());
+          .createServerSocket(port, backlog, bindAddress, socketBufferSize, useSSL());
     } else {
       printConfig();
       ServerSocket result = new TransportFilterServerSocket(transportFilters);
@@ -528,10 +498,10 @@ public class SocketCreator extends TcpSocketCreatorImpl {
       // java.net.ServerSocket.setReceiverBufferSize javadocs)
       result.setReceiveBufferSize(socketBufferSize);
       try {
-        result.bind(new InetSocketAddress(bindAddr, nport), backlog);
+        result.bind(new InetSocketAddress(bindAddress, port), backlog);
       } catch (BindException e) {
         BindException throwMe = new BindException(
-            String.format("Failed to create server socket on %s[%s]", bindAddr, nport));
+            String.format("Failed to create server socket on %s[%s]", bindAddress, port));
         throwMe.initCause(e);
         throw throwMe;
       }
@@ -539,50 +509,24 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     }
   }
 
-
-  // -------------------------------------------------------------------------
-  // Private implementation methods
-  // -------------------------------------------------------------------------
-
-
   /**
    * When a socket is connected to a server socket, it should be passed to this method for SSL
    * configuration.
    */
-  void configureClientSSLSocket(Socket socket, HostAndPort addr, int timeout) throws IOException {
+  void configureClientSSLSocket(final Socket socket, final HostAndPort address, int timeout)
+      throws IOException {
     if (socket instanceof SSLSocket) {
-      SSLSocket sslSocket = (SSLSocket) socket;
+      final SSLSocket sslSocket = (SSLSocket) socket;
 
       sslSocket.setUseClientMode(true);
       sslSocket.setEnableSessionCreation(true);
 
-      SSLParameters parameters = sslSocket.getSSLParameters();
-      boolean updateSSLParameters =
-          checkAndEnableHostnameValidation(parameters);
-
-      if (setServerNames(parameters, addr)) {
-        updateSSLParameters = true;
-      }
-
-      SSLParameterExtension sslParameterExtension = sslConfig.getSSLParameterExtension();
-      if (sslParameterExtension != null) {
-        parameters =
-            sslParameterExtension.modifySSLClientSocketParameters(parameters);
-        updateSSLParameters = true;
-      }
-
-      if (updateSSLParameters) {
-        sslSocket.setSSLParameters(parameters);
-      }
-
-      String[] protocols = sslConfig.getClientProtocolsAsStringArray();
-      if (!SSLConfig.isAnyProtocols(protocols)) {
-        sslSocket.setEnabledProtocols(protocols);
-      }
-      String[] ciphers = sslConfig.getCiphersAsStringArray();
-      if (ciphers != null && !"any".equalsIgnoreCase(ciphers[0])) {
-        sslSocket.setEnabledCipherSuites(ciphers);
-      }
+      final SSLParameters parameters = sslSocket.getSSLParameters();
+      checkAndEnableHostnameValidation(parameters);
+      addServerNameIfNotSet(parameters, address);
+      configureProtocols(true, parameters);
+      configureCipherSuites(parameters);
+      sslSocket.setSSLParameters(applySSLParameterExtensions(parameters));
 
       try {
         if (timeout > 0) {
@@ -615,25 +559,43 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     }
   }
 
-  /**
-   * returns true if the SSLParameters are altered, false if not
-   */
-  private boolean setServerNames(SSLParameters modifiedParams, HostAndPort addr) {
-    List<SNIServerName> oldNames = modifiedParams.getServerNames();
-    oldNames = oldNames == null ? Collections.emptyList() : oldNames;
-    final List<SNIServerName> serverNames = new ArrayList<>(oldNames);
+  SSLParameters applySSLParameterExtensions(final SSLParameters parameters) {
+    final SSLParameterExtension sslParameterExtension = sslConfig.getSSLParameterExtension();
+    if (sslParameterExtension != null) {
+      return sslParameterExtension.modifySSLClientSocketParameters(parameters);
+    }
+    return parameters;
+  }
+
+  void configureProtocols(final boolean clientSocket, final SSLParameters parameters) {
+    final String[] protocols = clientSocket ? sslConfig.getClientProtocolsAsStringArray()
+        : sslConfig.getServerProtocolsAsStringArray();
+    if (!SSLConfig.isAnyProtocols(protocols)) {
+      parameters.setProtocols(protocols);
+    }
+  }
+
+  void configureCipherSuites(final SSLParameters parameters) {
+    final String[] ciphers = sslConfig.getCiphersAsStringArray();
+    if (!SSLConfig.isAnyCiphers(ciphers)) {
+      parameters.setCipherSuites(ciphers);
+    }
+  }
+
+  static void addServerNameIfNotSet(final SSLParameters parameters,
+      final HostAndPort address) {
+    final List<SNIServerName> serverNames =
+        new ArrayList<>(getIfNull(parameters.getServerNames(), Collections::emptyList));
 
     if (serverNames.stream()
         .mapToInt(SNIServerName::getType)
         .anyMatch(type -> type == StandardConstants.SNI_HOST_NAME)) {
       // we already have a SNI hostname set. Do nothing.
-      return false;
+      return;
     }
 
-    String hostName = addr.getHostName();
-    serverNames.add(new SNIHostName(hostName));
-    modifiedParams.setServerNames(serverNames);
-    return true;
+    serverNames.add(new SNIHostName(address.getHostName()));
+    parameters.setServerNames(serverNames);
   }
 
   /**
@@ -664,7 +626,7 @@ public class SocketCreator extends TcpSocketCreatorImpl {
     if (className != null) {
       Object o;
       try {
-        Class c = ClassPathLoader.getLatest().forName(className);
+        Class<?> c = ClassPathLoader.getLatest().forName(className);
         o = c.newInstance();
       } catch (Exception e) {
         // No cache exists yet, so this can't be logged.
diff --git a/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigTest.java b/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigTest.java
index df125cd548..62bbf8c119 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigTest.java
@@ -16,6 +16,7 @@
 package org.apache.geode.internal.net;
 
 import static org.apache.geode.internal.net.SSLConfig.builder;
+import static org.apache.geode.internal.net.SSLConfig.isAnyCiphers;
 import static org.apache.geode.internal.net.SSLConfig.isAnyProtocols;
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -71,6 +72,54 @@ class SSLConfigTest {
     assertThat(isAnyProtocols("other", "something", "any")).isFalse();
   }
 
+  @Test
+  void isAnyCiphersReturnsTrueForNullString() {
+    assertThat(isAnyCiphers((String) null)).isTrue();
+  }
+
+  @Test
+  void isAnyCiphersReturnsTrueForEmptyString() {
+    assertThat(isAnyCiphers("")).isTrue();
+  }
+
+  @Test
+  void isAnyCiphersReturnsTrueForAnyString() {
+    assertThat(isAnyCiphers("any")).isTrue();
+    assertThat(isAnyCiphers("Any")).isTrue();
+    assertThat(isAnyCiphers("ANY")).isTrue();
+  }
+
+  @Test
+  void isAnyCiphersReturnsFalseForOtherString() {
+    assertThat(isAnyCiphers("other")).isFalse();
+  }
+
+  @Test
+  void testIsAnyCiphersForNullArray() {
+    assertThat(isAnyCiphers((String[]) null)).isTrue();
+  }
+
+  @SuppressWarnings("RedundantArrayCreation")
+  @Test
+  void isAnyCiphersReturnsTrueForEmptyArray() {
+    assertThat(isAnyCiphers(new String[0])).isTrue();
+  }
+
+  @Test
+  void isAnyCiphersReturnsTrueForAnyArray() {
+    assertThat(isAnyCiphers(new String[] {"any"})).isTrue();
+    assertThat(isAnyCiphers(new String[] {"Any"})).isTrue();
+    assertThat(isAnyCiphers(new String[] {"ANY"})).isTrue();
+    assertThat(isAnyCiphers("any", "other")).isTrue();
+  }
+
+  @Test
+  void isAnyCiphersReturnsFalseForOtherArray() {
+    assertThat(isAnyCiphers(new String[] {"other"})).isFalse();
+    assertThat(isAnyCiphers("other", "something")).isFalse();
+    assertThat(isAnyCiphers("other", "something", "any")).isFalse();
+  }
+
   @Test
   void getClientProtocolsDefaultsToAny() {
     final SSLConfig config = builder().build();
diff --git a/geode-core/src/test/java/org/apache/geode/internal/net/SocketCreatorTest.java b/geode-core/src/test/java/org/apache/geode/internal/net/SocketCreatorTest.java
index 888bd2bb4b..1faa7c5aa6 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/net/SocketCreatorTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/net/SocketCreatorTest.java
@@ -14,10 +14,15 @@
  */
 package org.apache.geode.internal.net;
 
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.apache.geode.internal.net.SocketCreator.addServerNameIfNotSet;
 import static org.apache.geode.test.util.ResourceUtils.createTempFileFromResource;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -35,21 +40,24 @@ import javax.net.ssl.SSLSocket;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 
+import org.apache.geode.distributed.internal.tcpserver.HostAndPort;
+import org.apache.geode.net.SSLParameterExtension;
+
 @Tag("membership")
-public class SocketCreatorTest {
+class SocketCreatorTest {
 
   private final SSLContext context = mock(SSLContext.class);
   private final SSLParameters parameters = mock(SSLParameters.class);
   private final SSLEngine engine = mock(SSLEngine.class);
 
-  public SocketCreatorTest() {
+  SocketCreatorTest() {
     when(engine.getSSLParameters()).thenReturn(parameters);
   }
 
 
   @Test
-  public void testCreateSocketCreatorWithKeystoreUnset() {
-    SSLConfig.Builder sslConfigBuilder = new SSLConfig.Builder();
+  void testCreateSocketCreatorWithKeystoreUnset() {
+    SSLConfig.Builder sslConfigBuilder = SSLConfig.builder();
     sslConfigBuilder.setEnabled(true);
     sslConfigBuilder.setKeystore(null);
     sslConfigBuilder.setKeystorePassword("");
@@ -60,7 +68,7 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void testConfigureServerSSLSocketSetsSoTimeout() throws Exception {
+  void testConfigureServerSSLSocketSetsSoTimeout() throws Exception {
     final SocketCreator socketCreator = new SocketCreator(mock(SSLConfig.class));
     final SSLSocket socket = mock(SSLSocket.class);
 
@@ -70,7 +78,7 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void testConfigureServerPlainSocketDoesntSetSoTimeout() throws Exception {
+  void testConfigureServerPlainSocketDoesntSetSoTimeout() throws Exception {
     final SocketCreator socketCreator = new SocketCreator(mock(SSLConfig.class));
     final Socket socket = mock(Socket.class);
     final int timeout = 1938236;
@@ -80,8 +88,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLEngineSetsClientModeTrue() {
-    final SSLConfig config = new SSLConfig.Builder().build();
+  void configureSSLEngineSetsClientModeTrue() {
+    final SSLConfig config = SSLConfig.builder().build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLEngine(engine, "localhost", 12345, true);
@@ -93,8 +101,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLEngineSetsClientModeFalse() {
-    final SSLConfig config = new SSLConfig.Builder().build();
+  void configureSSLEngineSetsClientModeFalse() {
+    final SSLConfig config = SSLConfig.builder().build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLEngine(engine, "localhost", 12345, false);
@@ -107,8 +115,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsProtocolsWhenSetProtocolsAndWhenClientSocket() {
-    final SSLConfig config = new SSLConfig.Builder().setProtocols("protocol1,protocol2").build();
+  void configureSSLParametersSetsProtocolsWhenSetProtocolsAndWhenClientSocket() {
+    final SSLConfig config = SSLConfig.builder().setProtocols("protocol1,protocol2").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -118,8 +126,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsProtocolsWhenSetProtocolsAndServerSocket() {
-    final SSLConfig config = new SSLConfig.Builder().setProtocols("protocol1,protocol2").build();
+  void configureSSLParametersSetsProtocolsWhenSetProtocolsAndServerSocket() {
+    final SSLConfig config = SSLConfig.builder().setProtocols("protocol1,protocol2").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, false);
@@ -130,9 +138,9 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsProtocolsWhenSetClientProtocols() {
+  void configureSSLParametersSetsProtocolsWhenSetClientProtocols() {
     final SSLConfig config =
-        new SSLConfig.Builder().setClientProtocols("protocol1,protocol2").build();
+        SSLConfig.builder().setClientProtocols("protocol1,protocol2").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -142,9 +150,9 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsProtocolsWhenSetServerProtocols() {
+  void configureSSLParametersSetsProtocolsWhenSetServerProtocols() {
     final SSLConfig config =
-        new SSLConfig.Builder().setServerProtocols("protocol1,protocol2").build();
+        SSLConfig.builder().setServerProtocols("protocol1,protocol2").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, false);
@@ -155,8 +163,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersDoesNotSetProtocolsWhenSetProtocolsIsAnyAndClientSocket() {
-    final SSLConfig config = new SSLConfig.Builder().setProtocols("any").build();
+  void configureSSLParametersDoesNotSetProtocolsWhenSetProtocolsIsAnyAndClientSocket() {
+    final SSLConfig config = SSLConfig.builder().setProtocols("any").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -165,8 +173,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersDoesNotSetProtocolsWhenSetProtocolsIsAnyAndServerSocket() {
-    final SSLConfig config = new SSLConfig.Builder().setProtocols("any").build();
+  void configureSSLParametersDoesNotSetProtocolsWhenSetProtocolsIsAnyAndServerSocket() {
+    final SSLConfig config = SSLConfig.builder().setProtocols("any").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -175,8 +183,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersDoesNotSetProtocolsWhenSetClientProtocolsIsAny() {
-    final SSLConfig config = new SSLConfig.Builder().setClientProtocols("any").build();
+  void configureSSLParametersDoesNotSetProtocolsWhenSetClientProtocolsIsAny() {
+    final SSLConfig config = SSLConfig.builder().setClientProtocols("any").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -185,8 +193,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersDoesNotSetProtocolsWhenSetServerProtocolsIsAny() {
-    final SSLConfig config = new SSLConfig.Builder().setProtocols("any").build();
+  void configureSSLParametersDoesNotSetProtocolsWhenSetServerProtocolsIsAny() {
+    final SSLConfig config = SSLConfig.builder().setProtocols("any").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, false);
@@ -196,8 +204,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsCipherSuites() {
-    final SSLConfig config = new SSLConfig.Builder().setCiphers("cipher1,cipher2").build();
+  void configureSSLParametersSetsCipherSuites() {
+    final SSLConfig config = SSLConfig.builder().setCiphers("cipher1,cipher2").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -207,8 +215,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersDoesNotSetCipherSuites() {
-    final SSLConfig config = new SSLConfig.Builder().setCiphers("any").build();
+  void configureSSLParametersDoesNotSetCipherSuites() {
+    final SSLConfig config = SSLConfig.builder().setCiphers("any").build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -217,8 +225,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsNeedClientAuthTrue() {
-    final SSLConfig config = new SSLConfig.Builder().setRequireAuth(true).build();
+  void configureSSLParametersSetsNeedClientAuthTrue() {
+    final SSLConfig config = SSLConfig.builder().setRequireAuth(true).build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, false);
@@ -228,8 +236,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsNeedClientAuthFalse() {
-    final SSLConfig config = new SSLConfig.Builder().setRequireAuth(false).build();
+  void configureSSLParametersSetsNeedClientAuthFalse() {
+    final SSLConfig config = SSLConfig.builder().setRequireAuth(false).build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, false);
@@ -239,8 +247,8 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParametersSetsEndpointIdentificationAlgorithmToHttpsAndServerNames() {
-    final SSLConfig config = new SSLConfig.Builder().setEndpointIdentificationEnabled(true).build();
+  void configureSSLParametersSetsEndpointIdentificationAlgorithmToHttpsAndServerNames() {
+    final SSLConfig config = SSLConfig.builder().setEndpointIdentificationEnabled(true).build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -253,9 +261,9 @@ public class SocketCreatorTest {
   }
 
   @Test
-  public void configureSSLParameterDoesNotSetEndpointIdentificationAlgorithm() {
+  void configureSSLParameterDoesNotSetEndpointIdentificationAlgorithm() {
     final SSLConfig config =
-        new SSLConfig.Builder().setEndpointIdentificationEnabled(false).build();
+        SSLConfig.builder().setEndpointIdentificationEnabled(false).build();
     final SocketCreator socketCreator = new SocketCreator(config, context);
 
     socketCreator.configureSSLParameters(parameters, "localhost", 123, true);
@@ -263,6 +271,169 @@ public class SocketCreatorTest {
     verifyNoMoreInteractions(parameters);
   }
 
+  @Test
+  void checkAndEnableHostnameValidationSetsEndpointIdentificationAlgorithmHttpsWhenEnabled() {
+    final SSLConfig config =
+        SSLConfig.builder().setEndpointIdentificationEnabled(true).build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.checkAndEnableHostnameValidation(parameters);
+
+    verify(parameters).setEndpointIdentificationAlgorithm(eq("HTTPS"));
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void checkAndEnableHostnameValidationDoesNotSetEndpointIdentificationAlgorithmHttpsAndHostnameValidationDisabledLogShownSetsWhenDisabled() {
+    final SSLConfig config = SSLConfig.builder()
+        .setEndpointIdentificationEnabled(false)
+        .build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.checkAndEnableHostnameValidation(parameters);
+
+    assertThat(socketCreator).hasFieldOrPropertyWithValue("hostnameValidationDisabledLogShown",
+        true);
+
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureProtocolsSetsClientProtocolsWhenClientSocketIsTrue() {
+    final SSLConfig config = SSLConfig.builder()
+        .setServerProtocols("server1,server2")
+        .setClientProtocols("client1,client2")
+        .build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureProtocols(true, parameters);
+
+    verify(parameters).setProtocols(eq(new String[] {"client1", "client2"}));
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureProtocolsSetsClientProtocolsWhenClientSocketIsFalse() {
+    final SSLConfig config = SSLConfig.builder()
+        .setServerProtocols("server1,server2")
+        .setClientProtocols("client1,client2")
+        .build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureProtocols(false, parameters);
+
+    verify(parameters).setProtocols(eq(new String[] {"server1", "server2"}));
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureProtocolsDoesNotSetClientProtocolsWhenClientSocketIsTrueAndSslConfigClientProtocolsIsUnset() {
+    final SSLConfig config = SSLConfig.builder().build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureProtocols(true, parameters);
+
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureProtocolsDoesNotSetServerProtocolsWhenClientSocketIsTrueAndSslConfigClientProtocolsIsUnset() {
+    final SSLConfig config = SSLConfig.builder().build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureProtocols(false, parameters);
+
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureCipherSuitesSetsCiphersWhenNotAny() {
+    final SSLConfig config = SSLConfig.builder()
+        .setCiphers("cipher1,cipher2")
+        .build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureCipherSuites(parameters);
+
+    verify(parameters).setCipherSuites(eq(new String[] {"cipher1", "cipher2"}));
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureCipherSuitesDoesNotSetCiphersWhenAny() {
+    final SSLConfig config = SSLConfig.builder()
+        .setCiphers("any")
+        .build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureCipherSuites(parameters);
+
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void configureCipherSuitesDoesNotSetCiphersWhenDefault() {
+    final SSLConfig config = SSLConfig.builder().build();
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.configureCipherSuites(parameters);
+
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void addServerNameIfNotSetAddsServerNameWhenNotSet() {
+    final HostAndPort address = new HostAndPort("host1", 1234);
+
+    when(parameters.getServerNames()).thenReturn(null);
+
+    addServerNameIfNotSet(parameters, address);
+
+    verify(parameters).getServerNames();
+    verify(parameters).setServerNames(eq(singletonList(new SNIHostName(address.getHostName()))));
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void addServerNameIfNotSetAddsServerNameWhenServerNamesIsEmpty() {
+    final HostAndPort address = new HostAndPort("host1", 1234);
+
+    when(parameters.getServerNames()).thenReturn(emptyList());
+
+    addServerNameIfNotSet(parameters, address);
+
+    verify(parameters).getServerNames();
+    verify(parameters).setServerNames(eq(singletonList(new SNIHostName(address.getHostName()))));
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void addServerNameIfNotSetDoesNotAddServerNameWhenServerNamesSet() {
+    final HostAndPort address = new HostAndPort("host1", 1234);
+
+    when(parameters.getServerNames())
+        .thenReturn(singletonList(new SNIHostName(address.getHostName())));
+
+    addServerNameIfNotSet(parameters, address);
+
+    verify(parameters).getServerNames();
+    verifyNoMoreInteractions(parameters);
+  }
+
+  @Test
+  void applySSLParameterExtensionsModifiesSSLClientSocketParametersWhenSSLParameterExtensionSet() {
+    final SSLConfig config = mock(SSLConfig.class);
+    final SSLParameterExtension sslParameterExtension = mock(SSLParameterExtension.class);
+    when(config.getSSLParameterExtension()).thenReturn(sslParameterExtension);
+
+    final SocketCreator socketCreator = new SocketCreator(config, context);
+
+    socketCreator.applySSLParameterExtensions(parameters);
+
+    verify(sslParameterExtension).modifySSLClientSocketParameters(same(parameters));
+    verifyNoMoreInteractions(parameters);
+  }
+
   private String getSingleKeyKeystore() {
     return createTempFileFromResource(getClass(), "/ssl/trusted.keystore").getAbsolutePath();
   }