/*
 * 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.geode.internal;

import static org.apache.geode.distributed.ConfigurationProperties.ASYNC_DISTRIBUTION_TIMEOUT;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_CIPHERS;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_ENABLED;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE_TYPE;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_PROTOCOLS;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_TRUSTSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_TRUSTSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_CIPHERS;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_ENABLED;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_KEYSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_KEYSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_KEYSTORE_TYPE;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_PROTOCOLS;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_TRUSTSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.GATEWAY_SSL_TRUSTSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_CIPHERS;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_ENABLED;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE_TYPE;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_PROTOCOLS;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_TRUSTSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_CIPHERS;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_ENABLED;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_KEYSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_KEYSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_KEYSTORE_TYPE;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_PROTOCOLS;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_TRUSTSTORE;
import static org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_TRUSTSTORE_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENDPOINT_IDENTIFICATION_ENABLED;
import static org.apache.geode.internal.security.SecurableCommunicationChannel.ALL;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.distributed.internal.DistributionConfigImpl;
import org.apache.geode.internal.net.SSLConfig;
import org.apache.geode.internal.net.SSLConfigurationFactory;
import org.apache.geode.test.junit.categories.SecurityTest;

/**
 * Test that DistributionConfigImpl handles SSL options correctly.
 */
@Category({SecurityTest.class})
public class SSLConfigJUnitTest {

  private static final Properties SSL_PROPS_MAP = new Properties();
  private static final Properties CLUSTER_SSL_PROPS_MAP = new Properties();
  private static final Properties CLUSTER_SSL_PROPS_SUBSET_MAP = new Properties();
  private static final Properties JMX_SSL_PROPS_MAP = new Properties();
  private static final Properties JMX_SSL_PROPS_SUBSET_MAP = new Properties();
  private static final Properties SERVER_SSL_PROPS_MAP = new Properties();
  private static final Properties SERVER_PROPS_SUBSET_MAP = new Properties();
  private static final Properties GATEWAY_SSL_PROPS_MAP = new Properties();
  private static final Properties GATEWAY_PROPS_SUBSET_MAP = new Properties();

  @BeforeClass
  public static void initializeSSLMaps() {

    SSL_PROPS_MAP.put("javax.net.ssl.keyStoreType", "jks");
    SSL_PROPS_MAP.put("javax.net.ssl.keyStore", "/export/gemfire-configs/gemfire.keystore");
    SSL_PROPS_MAP.put("javax.net.ssl.keyStorePassword", "gemfire-key-password");
    SSL_PROPS_MAP.put("javax.net.ssl.trustStore", "/export/gemfire-configs/gemfire.truststore");
    SSL_PROPS_MAP.put("javax.net.ssl.trustStorePassword", "gemfire-trust-password");

    // SSL Properties for GemFire in-cluster connections
    CLUSTER_SSL_PROPS_MAP.put(CLUSTER_SSL_KEYSTORE_TYPE, "jks");
    CLUSTER_SSL_PROPS_MAP.put(CLUSTER_SSL_KEYSTORE, "/export/gemfire-configs/gemfire.keystore");
    CLUSTER_SSL_PROPS_MAP.put(CLUSTER_SSL_KEYSTORE_PASSWORD, "gemfire-key-password");
    CLUSTER_SSL_PROPS_MAP.put(CLUSTER_SSL_TRUSTSTORE, "/export/gemfire-configs/gemfire.truststore");
    CLUSTER_SSL_PROPS_MAP.put(CLUSTER_SSL_TRUSTSTORE_PASSWORD, "gemfire-trust-password");

    // Partially over-ridden SSL Properties for cluster
    CLUSTER_SSL_PROPS_SUBSET_MAP.put(CLUSTER_SSL_KEYSTORE,
        "/export/gemfire-configs/gemfire.keystore");
    CLUSTER_SSL_PROPS_SUBSET_MAP.put(CLUSTER_SSL_TRUSTSTORE,
        "/export/gemfire-configs/gemfire.truststore");

    // SSL Properties for GemFire JMX Manager connections
    JMX_SSL_PROPS_MAP.put(JMX_MANAGER_SSL_KEYSTORE_TYPE, "jks");
    JMX_SSL_PROPS_MAP.put(JMX_MANAGER_SSL_KEYSTORE, "/export/gemfire-configs/manager.keystore");
    JMX_SSL_PROPS_MAP.put(JMX_MANAGER_SSL_KEYSTORE_PASSWORD, "manager-key-password");
    JMX_SSL_PROPS_MAP.put(JMX_MANAGER_SSL_TRUSTSTORE, "/export/gemfire-configs/manager.truststore");
    JMX_SSL_PROPS_MAP.put(JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD, "manager-trust-password");

    // SSL Properties for GemFire CacheServer connections
    SERVER_SSL_PROPS_MAP.put(SERVER_SSL_KEYSTORE_TYPE, "jks");
    SERVER_SSL_PROPS_MAP.put(SERVER_SSL_KEYSTORE, "/export/gemfire-configs/cacheserver.keystore");
    SERVER_SSL_PROPS_MAP.put(SERVER_SSL_KEYSTORE_PASSWORD, "cacheserver-key-password");
    SERVER_SSL_PROPS_MAP.put(SERVER_SSL_TRUSTSTORE,
        "/export/gemfire-configs/cacheserver.truststore");
    SERVER_SSL_PROPS_MAP.put(SERVER_SSL_TRUSTSTORE_PASSWORD, "cacheserver-trust-password");

    // SSL Properties for GemFire gateway connections
    GATEWAY_SSL_PROPS_MAP.put(GATEWAY_SSL_KEYSTORE_TYPE, "jks");
    GATEWAY_SSL_PROPS_MAP.put(GATEWAY_SSL_KEYSTORE, "/export/gemfire-configs/gateway.keystore");
    GATEWAY_SSL_PROPS_MAP.put(GATEWAY_SSL_KEYSTORE_PASSWORD, "gateway-key-password");
    GATEWAY_SSL_PROPS_MAP.put(GATEWAY_SSL_TRUSTSTORE, "/export/gemfire-configs/gateway.truststore");
    GATEWAY_SSL_PROPS_MAP.put(GATEWAY_SSL_TRUSTSTORE_PASSWORD, "gateway-trust-password");

    // Partially over-ridden SSL Properties for GemFire JMX Manager connections
    JMX_SSL_PROPS_SUBSET_MAP.put(JMX_MANAGER_SSL_KEYSTORE,
        "/export/gemfire-configs/manager.keystore");
    JMX_SSL_PROPS_SUBSET_MAP.put(JMX_MANAGER_SSL_TRUSTSTORE,
        "/export/gemfire-configs/manager.truststore");

    // Partially over-ridden SSL Properties for GemFire JMX Manager connections
    SERVER_PROPS_SUBSET_MAP.put(SERVER_SSL_KEYSTORE,
        "/export/gemfire-configs/cacheserver.keystore");
    SERVER_PROPS_SUBSET_MAP.put(SERVER_SSL_TRUSTSTORE,
        "/export/gemfire-configs/cacheserver.truststore");

    // Partially over-ridden SSL Properties for GemFire JMX Manager connections
    GATEWAY_PROPS_SUBSET_MAP.put(GATEWAY_SSL_KEYSTORE, "/export/gemfire-configs/gateway.keystore");
    GATEWAY_PROPS_SUBSET_MAP.put(GATEWAY_SSL_TRUSTSTORE,
        "/export/gemfire-configs/gateway.truststore");

  }

  @After
  public void tearDownTest() {}

  @Test
  public void slowReceiverShouldThrowExceptionWhenEnabledClusterTLS() throws Exception {
    Properties props = new Properties();
    props.setProperty(SSL_ENABLED_COMPONENTS, "cluster");
    props.setProperty(ASYNC_DISTRIBUTION_TIMEOUT, "1");

    Throwable thrown = catchThrowable(() -> new DistributionConfigImpl(props));
    assertThat(thrown).isInstanceOf(IllegalArgumentException.class).hasMessageContaining(
        "async-distribution-timeout greater than 0 is not allowed with cluster TLS/SSL.");
  }

  @Test
  public void slowReceiverShouldThrowExceptionWhenEnabledAllTLS() throws Exception {
    Properties props = new Properties();
    props.setProperty(SSL_ENABLED_COMPONENTS, "all");
    props.setProperty(ASYNC_DISTRIBUTION_TIMEOUT, "1");

    Throwable thrown = catchThrowable(() -> new DistributionConfigImpl(props));
    assertThat(thrown).isInstanceOf(IllegalArgumentException.class).hasMessageContaining(
        "async-distribution-timeout greater than 0 is not allowed with cluster TLS/SSL.");
  }

  @Test
  public void slowReceiverShouldNotThrowExceptionWhenEnabledLocatorTLS() throws Exception {
    Properties props = new Properties();
    props.setProperty(SSL_ENABLED_COMPONENTS, "locator");
    props.setProperty(ASYNC_DISTRIBUTION_TIMEOUT, "1");

    new DistributionConfigImpl(props);
  }

  @Test
  public void slowReceiverShouldThrowExceptionWhenLegacyClusterTLS() throws Exception {
    Properties props = new Properties();
    props.setProperty(CLUSTER_SSL_ENABLED, "true");
    props.setProperty(ASYNC_DISTRIBUTION_TIMEOUT, "1");

    Throwable thrown = catchThrowable(() -> new DistributionConfigImpl(props));
    assertThat(thrown).isInstanceOf(IllegalArgumentException.class).hasMessageContaining(
        "async-distribution-timeout greater than 0 is not allowed with cluster TLS/SSL.");
  }

  @Test
  public void testMCastPortWithClusterSSL() throws Exception {
    Properties props = new Properties();
    // default mcast-port is not 0.
    props.setProperty(CLUSTER_SSL_ENABLED, "true");

    try {
      new DistributionConfigImpl(props);
    } catch (IllegalArgumentException e) {
      if (!e.toString().matches(".*Could not set \"cluster-ssl-enabled.*")) {
        throw new Exception("did not get expected exception, got this instead...", e);
      }
    }

    props.setProperty(MCAST_PORT, "0");
    new DistributionConfigImpl(props);
  }

  @Test
  public void testConfigCopyWithSSL() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    DistributionConfigImpl config = new DistributionConfigImpl(new Properties());
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    Properties props = new Properties();
    sslciphers = "RSA_WITH_GARBAGE";
    props.setProperty(CLUSTER_SSL_CIPHERS, sslciphers);

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    sslprotocols = "SSLv7";
    props.setProperty(CLUSTER_SSL_PROTOCOLS, sslprotocols);

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    requireAuth = false;
    props.setProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    sslenabled = true;
    props.setProperty(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    props.setProperty(MCAST_PORT, "0");

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    config = new DistributionConfigImpl(config);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);
  }

  @Test
  public void testConfigCopyWithClusterSSL() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    DistributionConfigImpl config = new DistributionConfigImpl(new Properties());
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    Properties props = new Properties();
    sslciphers = "RSA_WITH_GARBAGE";
    props.setProperty(CLUSTER_SSL_CIPHERS, sslciphers);

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    sslprotocols = "SSLv7";
    props.setProperty(CLUSTER_SSL_PROTOCOLS, sslprotocols);

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    requireAuth = false;
    props.setProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    sslenabled = true;
    props.setProperty(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    props.setProperty(MCAST_PORT, "0");

    config = new DistributionConfigImpl(props);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    config = new DistributionConfigImpl(config);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);
  }

  @Test
  public void testManagerDefaultConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean jmxManagerSsl = false;
    boolean jmxManagerSslenabled = false;
    String jmxManagerSslprotocols = "any";
    String jmxManagerSslciphers = "any";
    boolean jmxManagerSslRequireAuth = true;

    DistributionConfigImpl config = new DistributionConfigImpl(new Properties());
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getJmxManagerSSLEnabled(), jmxManagerSsl);
    isEqual(config.getJmxManagerSSLEnabled(), jmxManagerSslenabled);
    isEqual(config.getJmxManagerSSLProtocols(), jmxManagerSslprotocols);
    isEqual(config.getJmxManagerSSLCiphers(), jmxManagerSslciphers);
    isEqual(config.getJmxManagerSSLRequireAuthentication(), jmxManagerSslRequireAuth);
  }

  @Test
  public void testCacheServerDefaultConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean cacheServerSslenabled = false;
    String cacheServerSslprotocols = "any";
    String cacheServerSslciphers = "any";
    boolean cacheServerSslRequireAuth = true;

    DistributionConfigImpl config = new DistributionConfigImpl(new Properties());
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getServerSSLEnabled(), cacheServerSslenabled);
    isEqual(config.getServerSSLProtocols(), cacheServerSslprotocols);
    isEqual(config.getServerSSLCiphers(), cacheServerSslciphers);
    isEqual(config.getServerSSLRequireAuthentication(), cacheServerSslRequireAuth);
  }

  @Test
  public void testGatewayDefaultConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean gatewaySslenabled = false;
    String gatewaySslprotocols = "any";
    String gatewaySslciphers = "any";
    boolean gatewaySslRequireAuth = true;

    DistributionConfigImpl config = new DistributionConfigImpl(new Properties());
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getGatewaySSLEnabled(), gatewaySslenabled);
    isEqual(config.getGatewaySSLProtocols(), gatewaySslprotocols);
    isEqual(config.getGatewaySSLCiphers(), gatewaySslciphers);
    isEqual(config.getGatewaySSLRequireAuthentication(), gatewaySslRequireAuth);
  }

  @Test
  public void testManagerConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean jmxManagerSslenabled = true;
    String jmxManagerSslprotocols = "SSLv7";
    String jmxManagerSslciphers = "RSA_WITH_GARBAGE";
    boolean jmxManagerSslRequireAuth = true;

    Properties gemFireProps = new Properties();
    gemFireProps.put(JMX_MANAGER_SSL_ENABLED, String.valueOf(jmxManagerSslenabled));
    gemFireProps.put(JMX_MANAGER_SSL_PROTOCOLS, jmxManagerSslprotocols);
    gemFireProps.put(JMX_MANAGER_SSL_CIPHERS, jmxManagerSslciphers);
    gemFireProps.put(JMX_MANAGER_SSL_REQUIRE_AUTHENTICATION,
        String.valueOf(jmxManagerSslRequireAuth));
    try {
      DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    } catch (IllegalArgumentException e) {
      if (!e.toString().contains(
          "GemFire properties 'jmx-manager-ssl' and 'jmx-manager-ssl-enabled' can not be used at the same time")) {
        throw new Exception("did not get expected exception, got this instead...", e);
      }
    }

    gemFireProps = new Properties();
    gemFireProps.put(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    gemFireProps.put(CLUSTER_SSL_PROTOCOLS, sslprotocols);
    gemFireProps.put(CLUSTER_SSL_CIPHERS, sslciphers);
    gemFireProps.put(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    gemFireProps.put(JMX_MANAGER_SSL_ENABLED, String.valueOf(jmxManagerSslenabled));
    gemFireProps.put(JMX_MANAGER_SSL_PROTOCOLS, jmxManagerSslprotocols);
    gemFireProps.put(JMX_MANAGER_SSL_CIPHERS, jmxManagerSslciphers);
    gemFireProps.put(JMX_MANAGER_SSL_REQUIRE_AUTHENTICATION,
        String.valueOf(jmxManagerSslRequireAuth));

    DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getJmxManagerSSLEnabled(), jmxManagerSslenabled);
    isEqual(config.getJmxManagerSSLProtocols(), jmxManagerSslprotocols);
    isEqual(config.getJmxManagerSSLCiphers(), jmxManagerSslciphers);
    isEqual(config.getJmxManagerSSLRequireAuthentication(), jmxManagerSslRequireAuth);
  }

  @Test
  public void testCacheServerConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean cacheServerSslenabled = true;
    String cacheServerSslprotocols = "SSLv7";
    String cacheServerSslciphers = "RSA_WITH_GARBAGE";
    boolean cacheServerSslRequireAuth = true;

    Properties gemFireProps = new Properties();
    gemFireProps.put(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    gemFireProps.put(CLUSTER_SSL_PROTOCOLS, sslprotocols);
    gemFireProps.put(CLUSTER_SSL_CIPHERS, sslciphers);
    gemFireProps.put(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    gemFireProps.put(SERVER_SSL_ENABLED, String.valueOf(cacheServerSslenabled));
    gemFireProps.put(SERVER_SSL_PROTOCOLS, cacheServerSslprotocols);
    gemFireProps.put(SERVER_SSL_CIPHERS, cacheServerSslciphers);
    gemFireProps.put(SERVER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(cacheServerSslRequireAuth));

    DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getServerSSLEnabled(), cacheServerSslenabled);
    isEqual(config.getServerSSLProtocols(), cacheServerSslprotocols);
    isEqual(config.getServerSSLCiphers(), cacheServerSslciphers);
    isEqual(config.getServerSSLRequireAuthentication(), cacheServerSslRequireAuth);
  }

  @Test
  public void testGatewayConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean gatewaySslenabled = true;
    String gatewaySslprotocols = "SSLv7";
    String gatewaySslciphers = "RSA_WITH_GARBAGE";
    boolean gatewaySslRequireAuth = true;

    Properties gemFireProps = new Properties();
    gemFireProps.put(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    gemFireProps.put(CLUSTER_SSL_PROTOCOLS, sslprotocols);
    gemFireProps.put(CLUSTER_SSL_CIPHERS, sslciphers);
    gemFireProps.put(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    gemFireProps.put(GATEWAY_SSL_ENABLED, String.valueOf(gatewaySslenabled));
    gemFireProps.put(GATEWAY_SSL_PROTOCOLS, gatewaySslprotocols);
    gemFireProps.put(GATEWAY_SSL_CIPHERS, gatewaySslciphers);
    gemFireProps.put(GATEWAY_SSL_REQUIRE_AUTHENTICATION, String.valueOf(gatewaySslRequireAuth));

    DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getGatewaySSLEnabled(), gatewaySslenabled);
    isEqual(config.getGatewaySSLProtocols(), gatewaySslprotocols);
    isEqual(config.getGatewaySSLCiphers(), gatewaySslciphers);
    isEqual(config.getGatewaySSLRequireAuthentication(), gatewaySslRequireAuth);
  }

  @Test
  public void testCustomizedManagerSslConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean jmxManagerSslenabled = true;
    String jmxManagerSslprotocols = "SSLv7";
    String jmxManagerSslciphers = "RSA_WITH_GARBAGE";
    boolean jmxManagerSslRequireAuth = true;

    Properties gemFireProps = new Properties();
    gemFireProps.put(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    gemFireProps.put(CLUSTER_SSL_PROTOCOLS, sslprotocols);
    gemFireProps.put(CLUSTER_SSL_CIPHERS, sslciphers);
    gemFireProps.put(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    gemFireProps.put(JMX_MANAGER_SSL_ENABLED, String.valueOf(jmxManagerSslenabled));
    gemFireProps.put(JMX_MANAGER_SSL_PROTOCOLS, jmxManagerSslprotocols);
    gemFireProps.put(JMX_MANAGER_SSL_CIPHERS, jmxManagerSslciphers);
    gemFireProps.put(JMX_MANAGER_SSL_REQUIRE_AUTHENTICATION,
        String.valueOf(jmxManagerSslRequireAuth));

    gemFireProps.putAll(getGfSecurityPropertiesJMX(false /* partialJmxSslConfigOverride */));

    DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getJmxManagerSSLEnabled(), jmxManagerSslenabled);
    isEqual(config.getJmxManagerSSLProtocols(), jmxManagerSslprotocols);
    isEqual(config.getJmxManagerSSLCiphers(), jmxManagerSslciphers);
    isEqual(config.getJmxManagerSSLRequireAuthentication(), jmxManagerSslRequireAuth);

    isEqual(JMX_SSL_PROPS_MAP.get(JMX_MANAGER_SSL_KEYSTORE), config.getJmxManagerSSLKeyStore());
    isEqual(JMX_SSL_PROPS_MAP.get(JMX_MANAGER_SSL_KEYSTORE_TYPE),
        config.getJmxManagerSSLKeyStoreType());
    isEqual(JMX_SSL_PROPS_MAP.get(JMX_MANAGER_SSL_KEYSTORE_PASSWORD),
        config.getJmxManagerSSLKeyStorePassword());
    isEqual(JMX_SSL_PROPS_MAP.get(JMX_MANAGER_SSL_TRUSTSTORE), config.getJmxManagerSSLTrustStore());
    isEqual(JMX_SSL_PROPS_MAP.get(JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD),
        config.getJmxManagerSSLTrustStorePassword());
  }

  @Test
  public void testCustomizedCacheServerSslConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean cacheServerSslenabled = true;
    String cacheServerSslprotocols = "SSLv7";
    String cacheServerSslciphers = "RSA_WITH_GARBAGE";
    boolean cacheServerSslRequireAuth = true;

    Properties gemFireProps = new Properties();
    gemFireProps.put(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    gemFireProps.put(CLUSTER_SSL_PROTOCOLS, sslprotocols);
    gemFireProps.put(CLUSTER_SSL_CIPHERS, sslciphers);
    gemFireProps.put(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    gemFireProps.put(SERVER_SSL_ENABLED, String.valueOf(cacheServerSslenabled));
    gemFireProps.put(SERVER_SSL_PROTOCOLS, cacheServerSslprotocols);
    gemFireProps.put(SERVER_SSL_CIPHERS, cacheServerSslciphers);
    gemFireProps.put(SERVER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(cacheServerSslRequireAuth));

    gemFireProps.putAll(getGfSecurityPropertiesForCS(false));

    DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getServerSSLEnabled(), cacheServerSslenabled);
    isEqual(config.getServerSSLProtocols(), cacheServerSslprotocols);
    isEqual(config.getServerSSLCiphers(), cacheServerSslciphers);
    isEqual(config.getServerSSLRequireAuthentication(), cacheServerSslRequireAuth);

    isEqual(SERVER_SSL_PROPS_MAP.get(SERVER_SSL_KEYSTORE), config.getServerSSLKeyStore());
    isEqual(SERVER_SSL_PROPS_MAP.get(SERVER_SSL_KEYSTORE_TYPE), config.getServerSSLKeyStoreType());
    isEqual(SERVER_SSL_PROPS_MAP.get(SERVER_SSL_KEYSTORE_PASSWORD),
        config.getServerSSLKeyStorePassword());
    isEqual(SERVER_SSL_PROPS_MAP.get(SERVER_SSL_TRUSTSTORE), config.getServerSSLTrustStore());
    isEqual(SERVER_SSL_PROPS_MAP.get(SERVER_SSL_TRUSTSTORE_PASSWORD),
        config.getServerSSLTrustStorePassword());
  }

  @Test
  public void testCustomizedGatewaySslConfig() throws Exception {
    boolean sslenabled = false;
    String sslprotocols = "any";
    String sslciphers = "any";
    boolean requireAuth = true;

    boolean gatewaySslenabled = true;
    String gatewaySslprotocols = "SSLv7";
    String gatewaySslciphers = "RSA_WITH_GARBAGE";
    boolean gatewaySslRequireAuth = true;

    Properties gemFireProps = new Properties();
    gemFireProps.put(CLUSTER_SSL_ENABLED, String.valueOf(sslenabled));
    gemFireProps.put(CLUSTER_SSL_PROTOCOLS, sslprotocols);
    gemFireProps.put(CLUSTER_SSL_CIPHERS, sslciphers);
    gemFireProps.put(CLUSTER_SSL_REQUIRE_AUTHENTICATION, String.valueOf(requireAuth));

    gemFireProps.put(GATEWAY_SSL_ENABLED, String.valueOf(gatewaySslenabled));
    gemFireProps.put(GATEWAY_SSL_PROTOCOLS, gatewaySslprotocols);
    gemFireProps.put(GATEWAY_SSL_CIPHERS, gatewaySslciphers);
    gemFireProps.put(GATEWAY_SSL_REQUIRE_AUTHENTICATION, String.valueOf(gatewaySslRequireAuth));

    gemFireProps.putAll(getGfSecurityPropertiesForGateway(false));

    DistributionConfigImpl config = new DistributionConfigImpl(gemFireProps);
    isEqual(config.getClusterSSLEnabled(), sslenabled);
    isEqual(config.getClusterSSLProtocols(), sslprotocols);
    isEqual(config.getClusterSSLCiphers(), sslciphers);
    isEqual(config.getClusterSSLRequireAuthentication(), requireAuth);

    isEqual(config.getGatewaySSLEnabled(), gatewaySslenabled);
    isEqual(config.getGatewaySSLProtocols(), gatewaySslprotocols);
    isEqual(config.getGatewaySSLCiphers(), gatewaySslciphers);
    isEqual(config.getGatewaySSLRequireAuthentication(), gatewaySslRequireAuth);

    isEqual(GATEWAY_SSL_PROPS_MAP.get(GATEWAY_SSL_KEYSTORE), config.getGatewaySSLKeyStore());
    isEqual(GATEWAY_SSL_PROPS_MAP.get(GATEWAY_SSL_KEYSTORE_TYPE),
        config.getGatewaySSLKeyStoreType());
    isEqual(GATEWAY_SSL_PROPS_MAP.get(GATEWAY_SSL_KEYSTORE_PASSWORD),
        config.getGatewaySSLKeyStorePassword());
    isEqual(GATEWAY_SSL_PROPS_MAP.get(GATEWAY_SSL_TRUSTSTORE), config.getGatewaySSLTrustStore());
    isEqual(GATEWAY_SSL_PROPS_MAP.get(GATEWAY_SSL_TRUSTSTORE_PASSWORD),
        config.getGatewaySSLTrustStorePassword());
  }

  @Test
  public void testPartialCustomizedManagerSslConfig() throws Exception {
