You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by bb...@apache.org on 2020/06/19 13:43:56 UTC

[geode-native] branch develop updated: GEODE-8128: Add SNI tests using new test framework (#616)

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 72459fd  GEODE-8128: Add SNI tests using new test framework (#616)
72459fd is described below

commit 72459fdf95be96f46457672abe82a8abbfdc3c0d
Author: Michael Martell <mm...@pivotal.io>
AuthorDate: Fri Jun 19 06:43:46 2020 -0700

    GEODE-8128: Add SNI tests using new test framework (#616)
    
    * Update cluster to support propertiesFile, etc.
    * Add new SNI test and config folder
    * Make sni scripts executable
    * Brought services up as daemons and stop them
    * Add parsing of proxy port and a couple test cases.
    * Inlined forever script and added gfsh script to start the cluster
    * Disable the SNI test that requires a real gateway
    
    Co-authored-by: Ernest Burghardt <eb...@pivotal.io>
    Co-authored-by: Blake Bender <bb...@pivotal.io>
---
 cppcache/integration/framework/Cluster.cpp         |  22 ++-
 cppcache/integration/framework/Cluster.h           |  16 ++
 cppcache/integration/framework/Gfsh.cpp            |  38 ++++-
 cppcache/integration/framework/Gfsh.h              |  14 +-
 cppcache/integration/test/CMakeLists.txt           |   3 +
 cppcache/integration/test/SNITest.cpp              | 166 +++++++++++++++++++++
 cppcache/integration/test/SslOneWayTest.cpp        |  16 +-
 cppcache/integration/test/SslTwoWayTest.cpp        |  16 +-
 .../test/sni-test-config/docker-compose.yml        |  43 ++++++
 .../geode-config/gemfire.properties                |  19 +++
 .../geode-config/gfsecurity.properties             |  27 ++++
 .../geode-config/locator-maeve-keystore.jks        | Bin 0 -> 2048 bytes
 .../geode-config/server-clementine-keystore.jks    | Bin 0 -> 2059 bytes
 .../geode-config/server-dolores-keystore.jks       | Bin 0 -> 2050 bytes
 .../sni-test-config/geode-config/truststore.jks    | Bin 0 -> 8095 bytes
 .../integration/test/sni-test-config/haproxy.cfg   |  44 ++++++
 .../test/sni-test-config/scripts/forever           |  20 +++
 .../sni-test-config/scripts/geode-starter-2.gfsh   |  23 +++
 .../sni-test-config/scripts/geode-starter.gfsh     |  22 +++
 19 files changed, 456 insertions(+), 33 deletions(-)

diff --git a/cppcache/integration/framework/Cluster.cpp b/cppcache/integration/framework/Cluster.cpp
index 78c621f..91ff454 100644
--- a/cppcache/integration/framework/Cluster.cpp
+++ b/cppcache/integration/framework/Cluster.cpp
@@ -89,7 +89,7 @@ void Locator::start() {
   if (cluster_.useSsl()) {
     locator.withConnect(false)
         .withSslEnabledComponents("all")
-        .withSslRquireAuthentication(cluster_.requireSslAuthentication())
+        .withSslRequireAuthentication(cluster_.requireSslAuthentication())
         .withSslKeystore(cluster_.keystore())
         .withSslTruststore(cluster_.truststore())
         .withSslKeystorePassword(cluster_.keystorePassword())
@@ -455,6 +455,26 @@ void Cluster::useSsl(const bool requireSslAuthentication,
 
 bool Cluster::useSsl() { return useSsl_; }
 
+void Cluster::usePropertiesFile(const std::string propertiesFile) {
+  usePropertiesFile_ = true;
+  propertiesFile_ = propertiesFile;
+}
+
+void Cluster::useSecurityPropertiesFile(const std::string securityPropertiesFile) {
+  useSecurityPropertiesFile_ = true;
+  securityPropertiesFile_ = securityPropertiesFile;
+}
+
+void Cluster::useHostNameForClients(
+    const std::string hostName) {
+  usePropertiesFile_ = true;
+  hostName_ = hostName;
+}
+
+bool Cluster::usePropertiesFile() { return usePropertiesFile_; }
+bool Cluster::useSecurityPropertiesFile() { return useSecurityPropertiesFile_; }
+bool Cluster::useHostNameForClients() { return useHostNameForClients_; }
+
 bool Cluster::requireSslAuthentication() { return requireSslAuthentication_; }
 
 std::string Cluster::keystore() { return keystore_; }
diff --git a/cppcache/integration/framework/Cluster.h b/cppcache/integration/framework/Cluster.h
index ee5ca70..bf17eb9 100644
--- a/cppcache/integration/framework/Cluster.h
+++ b/cppcache/integration/framework/Cluster.h
@@ -171,7 +171,15 @@ class Cluster {
               const std::string truststorePassword);
 
   bool useSsl();
+
+  void usePropertiesFile(const std::string propertiesFile);
+  void useSecurityPropertiesFile(const std::string securityPropertiesFile);
+  void useHostNameForClients(const std::string hostNameForClients);
+  bool usePropertiesFile();
+  bool useSecurityPropertiesFile();
+  bool useHostNameForClients();
   bool requireSslAuthentication();
+
   std::string keystore();
   std::string truststore();
   std::string keystorePassword();
@@ -214,11 +222,19 @@ class Cluster {
 
   bool useSsl_ = false;
   bool requireSslAuthentication_ = false;
+  bool usePropertiesFile_ = false;
+  bool useSecurityPropertiesFile_ = false;
+  bool useHostNameForClients_ = false;
+
   std::string keystore_;
   std::string keystorePassword_;
   std::string truststore_;
   std::string truststorePassword_;
 
+  std::string propertiesFile_;
+  std::string securityPropertiesFile_;
+  std::string hostName_;
+
   bool useIPv6_ = false;
 
   GfshExecute gfsh_;
diff --git a/cppcache/integration/framework/Gfsh.cpp b/cppcache/integration/framework/Gfsh.cpp
index a29e616..0373dce 100644
--- a/cppcache/integration/framework/Gfsh.cpp
+++ b/cppcache/integration/framework/Gfsh.cpp
@@ -156,13 +156,31 @@ Gfsh::Start::Locator &Gfsh::Start::Locator::withJmxManagerStart(
   return *this;
 }
 
-Gfsh::Start::Locator &Gfsh::Start::Locator::withSslRquireAuthentication(
+Gfsh::Start::Locator &Gfsh::Start::Locator::withSslRequireAuthentication(
     const bool require) {
   command_ += " --J=-Dgemfire.ssl-require-authentication=" +
               std::string(require ? "true" : "false");
   return *this;
 }
 
+Gfsh::Start::Locator &Gfsh::Start::Locator::withPropertiesFile(
+    const std::string file) {
+  command_ += " --properties-file=" + file;
+  return *this;
+}
+
+Gfsh::Start::Locator &Gfsh::Start::Locator::withSecurityPropertiesFile(
+    const std::string file) {
+  command_ += " --security-properties-file=" + file;
+  return *this;
+}
+
+Gfsh::Start::Locator &Gfsh::Start::Locator::withHostNameForClients(
+    const std::string hostName) {
+  command_ += " --hostname-for-clients=" + hostName;
+  return *this;
+}
+
 Gfsh::Start::Server::Server(Gfsh &gfsh) : Command(gfsh, "start server") {}
 
 Gfsh::Start::Server &Gfsh::Start::Server::withName(const std::string &name) {
@@ -288,6 +306,24 @@ Gfsh::Start::Server &Gfsh::Start::Server::withSslRquireAuthentication(
   return *this;
 }
 
+Gfsh::Start::Server &Gfsh::Start::Server::withPropertiesFile(
+    const std::string file) {
+  command_ += " --properties-file=" + file;
+  return *this;
+}
+
+Gfsh::Start::Server &Gfsh::Start::Server::withSecurityPropertiesFile(
+    const std::string file) {
+  command_ += " --security-properties-file=" + file;
+  return *this;
+}
+
+Gfsh::Start::Server &Gfsh::Start::Server::withHostNameForClients(
+    const std::string hostName) {
+  command_ += " --hostname-for-clients=" + hostName;
+  return *this;
+}
+
 Gfsh::Stop::Stop(Gfsh &gfsh) : gfsh_(gfsh) {}
 
 Gfsh::Stop::Server Gfsh::Stop::server() { return Server{gfsh_}; }
diff --git a/cppcache/integration/framework/Gfsh.h b/cppcache/integration/framework/Gfsh.h
index b775493..4907137 100644
--- a/cppcache/integration/framework/Gfsh.h
+++ b/cppcache/integration/framework/Gfsh.h
@@ -125,7 +125,13 @@ class Gfsh {
 
       Locator &withJmxManagerStart(const bool startJmxManager);
 
-      Locator &withSslRquireAuthentication(const bool require);
+      Locator &withSslRequireAuthentication(const bool require);
+
+      Locator &withPropertiesFile(const std::string file);
+
+      Locator &withSecurityPropertiesFile(const std::string file);
+
+      Locator &withHostNameForClients(const std::string hostName);
     };
 
     class Server : public Command<void> {
@@ -169,6 +175,12 @@ class Gfsh {
       Server &withSslTruststorePassword(const std::string &truststorePassword);
 
       Server &withSslRquireAuthentication(const bool require);
+
+      Server &withPropertiesFile(const std::string file);
+
+      Server &withSecurityPropertiesFile(const std::string file);
+
+      Server &withHostNameForClients(const std::string hostName);
     };
 
    private:
diff --git a/cppcache/integration/test/CMakeLists.txt b/cppcache/integration/test/CMakeLists.txt
index a7554fd..e7be053 100644
--- a/cppcache/integration/test/CMakeLists.txt
+++ b/cppcache/integration/test/CMakeLists.txt
@@ -39,6 +39,7 @@ add_executable(cpp-integration-test
   SimpleAuthInitialize.hpp
   SimpleCqListener.cpp
   SimpleCqListener.hpp
+  SNITest.cpp
   SslOneWayTest.cpp
   SslTwoWayTest.cpp
   StructTest.cpp
@@ -92,6 +93,8 @@ configure_file(
   ${CMAKE_CURRENT_SOURCE_DIR}/func_cacheserver2_pool.xml
   ${CMAKE_CURRENT_BINARY_DIR}/func_cacheserver2_pool.xml COPYONLY)
 
+ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/sni-test-config DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 
+
 set_target_properties(cpp-integration-test PROPERTIES
   CXX_VISIBILITY_PRESET hidden
   VISIBILITY_INLINES_HIDDEN ON
diff --git a/cppcache/integration/test/SNITest.cpp b/cppcache/integration/test/SNITest.cpp
new file mode 100644
index 0000000..490abe3
--- /dev/null
+++ b/cppcache/integration/test/SNITest.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <geode/Cache.hpp>
+#include <geode/CacheFactory.hpp>
+#include <geode/RegionFactory.hpp>
+#include <geode/RegionShortcut.hpp>
+
+#include "framework/Cluster.h"
+
+namespace ssltest {
+
+using apache::geode::client::AuthenticationRequiredException;
+using apache::geode::client::CacheableString;
+using apache::geode::client::CacheFactory;
+using apache::geode::client::Exception;
+using apache::geode::client::RegionShortcut;
+
+class SNITest : public ::testing::Test {
+ protected:
+  SNITest() {
+    certificatePassword = std::string("apachegeode");
+    currentWorkingDirectory = boost::filesystem::current_path();
+  }
+
+  ~SNITest() override = default;
+
+  void SetUp() override {
+#if defined(_WIN32)
+    std::string sniDir(currentWorkingDirectory.string());
+    sniDir += "/../sni-test-config";
+    SetCurrentDirectory(sniDir.c_str());
+#else
+    chdir("./sni-test-config");
+#endif
+
+    std::system("docker-compose up -d");
+
+    std::system(
+        "docker exec -t geode gfsh run "
+        "--file=/geode/scripts/geode-starter.gfsh");
+  }
+
+  void TearDown() override { std::system("docker-compose stop"); }
+
+  std::string makeItSo(const char* command) {
+    std::string commandOutput;
+#if defined(_WIN32)
+    std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(command, "r"),
+                                                   _pclose);
+#else
+    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command, "r"), pclose);
+#endif
+    std::array<char, 128> charBuff;
+    if (!pipe) {
+      throw std::runtime_error("Failed on the POPEN");
+    }
+    while (fgets(charBuff.data(), charBuff.size(), pipe.get()) != nullptr) {
+      commandOutput += charBuff.data();
+    }
+    return commandOutput;
+  }
+
+  int parseProxyPort(std::string proxyString) {
+    // 15443/tcp -> 0.0.0.0:32787
+    std::size_t colonPosition = proxyString.find(":");
+    std::string portNumberString = proxyString.substr((colonPosition + 1));
+    return stoi(portNumberString);
+  }
+
+  std::string certificatePassword;
+  boost::filesystem::path currentWorkingDirectory;
+};
+
+TEST_F(SNITest, DISABLED_connectViaProxyTest) {
+  const auto clientTruststore =
+      (currentWorkingDirectory /
+       boost::filesystem::path("sni-test-config/geode-config/truststore.jks"));
+
+  auto cache = CacheFactory()
+                   .set("log-level", "DEBUG")
+                   .set("ssl-enabled", "true")
+                   .set("ssl-truststore", clientTruststore.string())
+                   .create();
+
+  auto portString = makeItSo("docker port haproxy");
+  auto portNumber = parseProxyPort(portString);
+
+  cache.getPoolManager()
+      .createFactory()
+      .addLocator("localhost", portNumber)
+      .create("pool");
+
+  auto region = cache.createRegionFactory(RegionShortcut::PROXY)
+                    .setPoolName("pool")
+                    .create("region");
+
+  region->put("1", "one");
+
+  cache.close();
+}
+
+TEST_F(SNITest, connectionFailsTest) {
+  const auto clientTruststore =
+      (currentWorkingDirectory /
+       boost::filesystem::path("sni-test-config/geode-config/truststore.jks"));
+
+  auto cache = CacheFactory()
+                   .set("log-level", "DEBUG")
+                   .set("ssl-enabled", "true")
+                   .set("ssl-truststore", clientTruststore.string())
+                   .create();
+
+  cache.getPoolManager()
+      .createFactory()
+      .addLocator("localhost", 10334)
+      .create("pool");
+
+  auto region = cache.createRegionFactory(RegionShortcut::PROXY)
+                    .setPoolName("pool")
+                    .create("region");
+  EXPECT_THROW(region->put("1", "one"),
+               apache::geode::client::NotConnectedException);
+
+  cache.close();
+}
+
+TEST_F(SNITest, doNothingTest) {
+  const auto clientTruststore =
+      (currentWorkingDirectory /
+       boost::filesystem::path("sni-test-config/geode-config/truststore.jks"));
+
+  auto cache = CacheFactory()
+                   .set("log-level", "DEBUG")
+                   .set("ssl-enabled", "true")
+                   .set("ssl-truststore", clientTruststore.string())
+                   .create();
+
+  cache.getPoolManager()
+      .createFactory()
+      .addLocator("localhost", 10334)
+      .create("pool");
+
+  cache.close();
+}
+
+}  // namespace ssltest
diff --git a/cppcache/integration/test/SslOneWayTest.cpp b/cppcache/integration/test/SslOneWayTest.cpp
index 177e228..d7c10f1 100644
--- a/cppcache/integration/test/SslOneWayTest.cpp
+++ b/cppcache/integration/test/SslOneWayTest.cpp
@@ -36,11 +36,7 @@ using apache::geode::client::RegionShortcut;
 
 class SslOneWayTest : public ::testing::Test {
  protected:
-  // You can remove any or all of the following functions if their bodies would
-  // be empty.
-
   SslOneWayTest() {
-    // You can do set-up work for each test here.
     certificatePassword = std::string("apachegeode");
     serverSslKeysDir = boost::filesystem::path(
         getFrameworkString(FrameworkVariable::TestServerSslKeysDir));
@@ -49,13 +45,8 @@ class SslOneWayTest : public ::testing::Test {
   }
 
   ~SslOneWayTest() override = default;
-  // You can do clean-up work that doesn't throw exceptions here.
 
-  // If the constructor and destructor are not enough for setting up
-  // and cleaning up each test, you can define the following methods:
   void SetUp() override {
-    // Code here will be called immediately after the constructor (right
-    // before each test).
     const auto clusterKeystore =
         (serverSslKeysDir /
          boost::filesystem::path("server_keystore_chained.p12"));
@@ -76,13 +67,8 @@ class SslOneWayTest : public ::testing::Test {
         .execute();
   }
 
-  void TearDown() override {
-    // Code here will be called immediately after each test (right
-    // before the destructor).
-  }
+  void TearDown() override {}
 
-  // Class members declared here can be used by all tests in the test suite
-  // for Ssl.
   Cluster cluster = Cluster{LocatorCount{1}, ServerCount{1}};
   std::string certificatePassword;
   boost::filesystem::path serverSslKeysDir;
diff --git a/cppcache/integration/test/SslTwoWayTest.cpp b/cppcache/integration/test/SslTwoWayTest.cpp
index 01edc50..4cb1b41 100644
--- a/cppcache/integration/test/SslTwoWayTest.cpp
+++ b/cppcache/integration/test/SslTwoWayTest.cpp
@@ -36,11 +36,7 @@ using apache::geode::client::RegionShortcut;
 
 class SslTwoWayTest : public ::testing::Test {
  protected:
-  // You can remove any or all of the following functions if their bodies would
-  // be empty.
-
   SslTwoWayTest() {
-    // You can do set-up work for each test here.
     certificatePassword = std::string("apachegeode");
     serverSslKeysDir = boost::filesystem::path(
         getFrameworkString(FrameworkVariable::TestServerSslKeysDir));
@@ -49,13 +45,8 @@ class SslTwoWayTest : public ::testing::Test {
   }
 
   ~SslTwoWayTest() override = default;
-  // You can do clean-up work that doesn't throw exceptions here.
 
-  // If the constructor and destructor are not enough for setting up
-  // and cleaning up each test, you can define the following methods:
   void SetUp() override {
-    // Code here will be called immediately after the constructor (right
-    // before each test).
     const auto clusterKeystore =
         (serverSslKeysDir /
          boost::filesystem::path("server_keystore_chained.p12"));
@@ -76,13 +67,8 @@ class SslTwoWayTest : public ::testing::Test {
         .execute();
   }
 
-  void TearDown() override {
-    // Code here will be called immediately after each test (right
-    // before the destructor).
-  }
+  void TearDown() override {}
 
-  // Class members declared here can be used by all tests in the test suite
-  // for Ssl.
   Cluster cluster = Cluster{LocatorCount{1}, ServerCount{1}};
   std::string certificatePassword;
   boost::filesystem::path serverSslKeysDir;
diff --git a/cppcache/integration/test/sni-test-config/docker-compose.yml b/cppcache/integration/test/sni-test-config/docker-compose.yml
new file mode 100644
index 0000000..b0a6100
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/docker-compose.yml
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+version: '3'
+services:
+  geode:
+    container_name: 'geode'
+    image: 'apachegeode/geode'
+    expose:
+      - '10334'
+      - '40404'
+    entrypoint: 'sh'
+    command: ["-c", "while true; do sleep 600; done"]
+    networks:
+      geode-sni-test:
+    volumes:
+      - ./geode-config:/geode/config:ro
+      - ./scripts:/geode/scripts
+  haproxy:
+    container_name: 'haproxy'
+    image: 'haproxy:2.1'
+    ports:
+      - "15443"
+    networks:
+      geode-sni-test:
+    volumes:
+      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
+networks:
+  geode-sni-test:
+
diff --git a/cppcache/integration/test/sni-test-config/geode-config/gemfire.properties b/cppcache/integration/test/sni-test-config/geode-config/gemfire.properties
new file mode 100644
index 0000000..1f13fb0
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/geode-config/gemfire.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+statistic-sampling-enabled=true
+statistic-archive-file=statArchive.gfs
diff --git a/cppcache/integration/test/sni-test-config/geode-config/gfsecurity.properties b/cppcache/integration/test/sni-test-config/geode-config/gfsecurity.properties
new file mode 100644
index 0000000..813d260
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/geode-config/gfsecurity.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+security-log-level=info
+security-peer-verifymember-timeout=1000
+ssl-keystore-password=geode
+ssl-truststore=/geode/config/truststore.jks
+ssl-truststore-password=geode
+ssl-require-authentication=false
+ssl-web-require-authentication=false
+ssl-enabled-components=all
+ssl-endpoint-identification-enabled=false
+
diff --git a/cppcache/integration/test/sni-test-config/geode-config/locator-maeve-keystore.jks b/cppcache/integration/test/sni-test-config/geode-config/locator-maeve-keystore.jks
new file mode 100644
index 0000000..a29cf0f
Binary files /dev/null and b/cppcache/integration/test/sni-test-config/geode-config/locator-maeve-keystore.jks differ
diff --git a/cppcache/integration/test/sni-test-config/geode-config/server-clementine-keystore.jks b/cppcache/integration/test/sni-test-config/geode-config/server-clementine-keystore.jks
new file mode 100644
index 0000000..380de6c
Binary files /dev/null and b/cppcache/integration/test/sni-test-config/geode-config/server-clementine-keystore.jks differ
diff --git a/cppcache/integration/test/sni-test-config/geode-config/server-dolores-keystore.jks b/cppcache/integration/test/sni-test-config/geode-config/server-dolores-keystore.jks
new file mode 100644
index 0000000..cb2c4c5
Binary files /dev/null and b/cppcache/integration/test/sni-test-config/geode-config/server-dolores-keystore.jks differ
diff --git a/cppcache/integration/test/sni-test-config/geode-config/truststore.jks b/cppcache/integration/test/sni-test-config/geode-config/truststore.jks
new file mode 100644
index 0000000..ffcdaf3
Binary files /dev/null and b/cppcache/integration/test/sni-test-config/geode-config/truststore.jks differ
diff --git a/cppcache/integration/test/sni-test-config/haproxy.cfg b/cppcache/integration/test/sni-test-config/haproxy.cfg
new file mode 100644
index 0000000..c451ef6
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/haproxy.cfg
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+defaults
+  timeout client 1000
+  timeout connect 1000
+  timeout server 1000
+
+frontend sniproxy
+  bind *:15443
+  mode tcp
+  tcp-request inspect-delay 5s
+  tcp-request content accept if { req_ssl_hello_type 1 }
+  use_backend locators-maeve if { req.ssl_sni -i locator-maeve }
+  use_backend servers-dolores if { req.ssl_sni -i server-dolores }
+  use_backend servers-clementine if { req.ssl_sni -i server-clementine }
+  default_backend locators-maeve
+  log stdout format raw  local0  debug
+
+backend locators-maeve
+  mode tcp
+  server locator1 geode:10334
+
+backend servers-dolores
+  mode tcp
+  server server1 geode:40404
+
+backend servers-clementine
+  mode tcp
+  server server1 geode:40405
diff --git a/cppcache/integration/test/sni-test-config/scripts/forever b/cppcache/integration/test/sni-test-config/scripts/forever
new file mode 100755
index 0000000..4fecfa8
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/scripts/forever
@@ -0,0 +1,20 @@
+#!/usr/bin/env sh
+
+#
+# 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.
+#
+
+while true; do sleep 600; done
diff --git a/cppcache/integration/test/sni-test-config/scripts/geode-starter-2.gfsh b/cppcache/integration/test/sni-test-config/scripts/geode-starter-2.gfsh
new file mode 100755
index 0000000..38600aa
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/scripts/geode-starter-2.gfsh
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+start locator --name=locator-maeve --hostname-for-clients=locator-maeve --properties-file=/geode/config/gemfire.properties --security-properties-file=/geode/config/gfsecurity.properties --J=-Dgemfire.ssl-keystore=/geode/config/locator-maeve-keystore.jks
+start server --name=server-dolores --group=group-dolores --hostname-for-clients=server-dolores --locators=localhost[10334] --properties-file=/geode/config/gemfire.properties --security-properties-file=/geode/config/gfsecurity.properties --J=-Dgemfire.ssl-keystore=/geode/config/server-dolores-keystore.jks
+start server --name=server-clementine --group=group-clementine --hostname-for-clients=server-clementine --server-port=40405 --locators=localhost[10334] --properties-file=/geode/config/gemfire.properties --security-properties-file=/geode/config/gfsecurity.properties --J=-Dgemfire.ssl-keystore=/geode/config/server-clementine-keystore.jks
+connect --locator=localhost[10334] --use-ssl=true --security-properties-file=/geode/config/gfsecurity.properties
+create region --name=region-dolores --group=group-dolores --type=REPLICATE
+create region --name=region-clementine --group=group-clementine --type=REPLICATE
diff --git a/cppcache/integration/test/sni-test-config/scripts/geode-starter.gfsh b/cppcache/integration/test/sni-test-config/scripts/geode-starter.gfsh
new file mode 100755
index 0000000..9ceecad
--- /dev/null
+++ b/cppcache/integration/test/sni-test-config/scripts/geode-starter.gfsh
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+start locator --name=locator-maeve --hostname-for-clients=locator-maeve --properties-file=/geode/config/gemfire.properties --security-properties-file=/geode/config/gfsecurity.properties --J=-Dgemfire.ssl-keystore=/geode/config/locator-maeve-keystore.jks
+start server --name=server-dolores --max-heap=256m --hostname-for-clients=server-dolores --locators=localhost[10334] --properties-file=/geode/config/gemfire.properties --security-properties-file=/geode/config/gfsecurity.properties --J=-Dgemfire.ssl-keystore=/geode/config/server-dolores-keystore.jks
+connect --locator=localhost[10334] --use-ssl=true --security-properties-file=/geode/config/gfsecurity.properties
+create region --name=jellyfish --type=REPLICATE
+