You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by pi...@apache.org on 2018/03/30 23:46:53 UTC
[geode] branch develop updated: GEODE-4817: Add support for SSL to
the experimental driver. (#1683)
This is an automated email from the ASF dual-hosted git repository.
pivotalsarge 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 5809567 GEODE-4817: Add support for SSL to the experimental driver. (#1683)
5809567 is described below
commit 5809567ed4609b2e2ef48ce5a86ed7c57d9c77d7
Author: Michael "Sarge" Dodge <md...@pivotal.io>
AuthorDate: Fri Mar 30 16:46:49 2018 -0700
GEODE-4817: Add support for SSL to the experimental driver. (#1683)
* GEODE-4817: Add support for SSL to the experimental driver.
- Adding a test that a locator can shut itself down
with SSL. In order to use a locator with SSL, the
locator must trust itself. Modifying the truststore
and adding a test of shutting down a locator with SSL.
- The locator needs to trust itself. Fixing the
truststore so that this test can shutdown.
Signed-off-by: Dan Smith <ds...@pivotal.io>
* GEODE-4817: Adding ssl tests with bad certificates
Adding tests that the client cannot connect if the server or the client
has a bad ssl certificate.
* GEODE-4817: Adding protocols and cipher parameters to the experimental driver
Adding parameters that let the user restrict the protocols and ciphers
used.
---
.../cache/client/internal/LocatorSSLJUnitTest.java | 57 ++++++
.../cache/client/internal/cacheserver.truststore | Bin 844 -> 1658 bytes
.../geode/experimental/driver/DriverFactory.java | 85 ++++++++-
.../geode/experimental/driver/ProtobufChannel.java | 65 ++++---
.../geode/experimental/driver/ProtobufDriver.java | 13 +-
.../geode/experimental/driver/SocketFactory.java | 203 +++++++++++++++++++++
.../apache/geode/experimental/driver/SSLTest.java | 187 +++++++++++++++++++
.../geode/experimental/driver/bogusclient.keystore | Bin 0 -> 1115 bytes
.../geode/experimental/driver/bogusserver.keystore | Bin 0 -> 1299 bytes
.../geode/experimental/driver/cacheserver.keystore | Bin 0 -> 1253 bytes
.../experimental/driver/cacheserver.truststore | Bin 0 -> 2519 bytes
.../geode/experimental/driver/client.keystore | Bin 844 -> 1251 bytes
.../geode/experimental/driver/client.truststore | Bin 0 -> 846 bytes
13 files changed, 572 insertions(+), 38 deletions(-)
diff --git a/geode-core/src/test/java/org/apache/geode/cache/client/internal/LocatorSSLJUnitTest.java b/geode-core/src/test/java/org/apache/geode/cache/client/internal/LocatorSSLJUnitTest.java
new file mode 100644
index 0000000..a93edb3
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/cache/client/internal/LocatorSSLJUnitTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.cache.client.internal;
+
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.distributed.Locator;
+import org.apache.geode.test.junit.categories.ClientServerTest;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.util.test.TestUtil;
+
+@Category({UnitTest.class, ClientServerTest.class})
+public class LocatorSSLJUnitTest {
+ private final String SERVER_KEY_STORE =
+ TestUtil.getResourcePath(LocatorSSLJUnitTest.class, "cacheserver.keystore");
+ private final String SERVER_TRUST_STORE =
+ TestUtil.getResourcePath(LocatorSSLJUnitTest.class, "cacheserver.truststore");
+
+ @Test
+ public void canStopLocatorWithSSL() throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty(MCAST_PORT, "0");
+ properties.put(SSL_ENABLED_COMPONENTS, "all");
+ properties.put(SSL_KEYSTORE_TYPE, "jks");
+ properties.put(SSL_KEYSTORE, SERVER_KEY_STORE);
+ properties.put(SSL_KEYSTORE_PASSWORD, "password");
+ properties.put(SSL_TRUSTSTORE, SERVER_TRUST_STORE);
+ properties.put(SSL_TRUSTSTORE_PASSWORD, "password");
+
+ Locator locator = Locator.startLocatorAndDS(0, null, properties);
+ locator.stop();
+ }
+}
diff --git a/geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore b/geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore
index 3920963..4b887ee 100644
Binary files a/geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore and b/geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore differ
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/DriverFactory.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/DriverFactory.java
index b6cf205..91c2843 100644
--- a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/DriverFactory.java
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/DriverFactory.java
@@ -47,6 +47,26 @@ public class DriverFactory {
private String password = null;
/**
+ * Path to SSL key store; SSL is <em>not</em> used if <code>null</code>.
+ */
+ private String keyStorePath;
+
+ /**
+ * Path to SSL trust store; SSL is <em>not</em> used if <code>null</code>.
+ */
+ private String trustStorePath;
+
+ /**
+ * Space-separated list of the SSL protocols to enable.
+ */
+ private String protocols;
+
+ /**
+ * Space-separated list of the SSL cipher suites to enable.
+ */
+ private String ciphers;
+
+ /**
* Adds a locator at <code>host</code> and <code>port</code> to the set of locators to use.
*
* @param host Internet address or host name.
@@ -59,16 +79,6 @@ public class DriverFactory {
}
/**
- * Creates a driver configured to use all the locators about which this driver factory knows.
- *
- * @return New driver.
- * @throws Exception
- */
- public Driver create() throws Exception {
- return new ProtobufDriver(locators, username, password);
- }
-
- /**
* Specifies the user name with which to authenticate with the server.
*
* @param username User identity as a string; may be <code>null</code>.
@@ -89,4 +99,59 @@ public class DriverFactory {
this.password = password;
return this;
}
+
+ /**
+ * Specifies the key store to use with SSL.
+ *
+ * @param keyStorePath Path to the SSL key store.
+ * @return This driver factory.
+ */
+ public DriverFactory setKeyStorePath(String keyStorePath) {
+ this.keyStorePath = keyStorePath;
+ return this;
+ }
+
+ /**
+ * Specifies the trust store to use with SSL.
+ *
+ * @param trustStorePath Path to the SSL trust store.
+ * @return This driver factory.
+ */
+ public DriverFactory setTrustStorePath(String trustStorePath) {
+ this.trustStorePath = trustStorePath;
+ return this;
+ }
+
+ /**
+ * Specifies the protocols to enable.
+ *
+ * @param protocols Space-separated list of the SSL protocols to enable.
+ * @return This driver factory.
+ */
+ public DriverFactory setProtocols(String protocols) {
+ this.protocols = protocols;
+ return this;
+ }
+
+ /**
+ * Specifies the cipher suites to enable.
+ *
+ * @param ciphers Space-separated list of the SSL cipher suites to enable.
+ * @return This driver factory.
+ */
+ public DriverFactory setCiphers(String ciphers) {
+ this.ciphers = ciphers;
+ return this;
+ }
+
+ /**
+ * Creates a driver configured to use all the locators about which this driver factory knows.
+ *
+ * @return New driver.
+ * @throws Exception
+ */
+ public Driver create() throws Exception {
+ return new ProtobufDriver(locators, username, password, keyStorePath, trustStorePath, protocols,
+ ciphers);
+ }
}
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufChannel.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufChannel.java
index 8ddbe6f..890d43c 100644
--- a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufChannel.java
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufChannel.java
@@ -17,8 +17,10 @@ package org.apache.geode.experimental.driver;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.security.GeneralSecurityException;
import java.util.Objects;
import java.util.Set;
@@ -32,42 +34,33 @@ import org.apache.geode.internal.protocol.protobuf.v1.ConnectionAPI;
import org.apache.geode.internal.protocol.protobuf.v1.LocatorAPI;
class ProtobufChannel {
-
- private final Set<InetSocketAddress> locators;
/**
* Socket to a GemFire server that has Protobuf enabled.
*/
final Socket socket;
- public ProtobufChannel(final Set<InetSocketAddress> locators, String username, String password)
- throws IOException {
- this.locators = locators;
- this.socket = connectToAServer(username, password);
- }
-
- Message sendRequest(final Message request, MessageTypeCase expectedResult) throws IOException {
- final OutputStream outputStream = socket.getOutputStream();
- request.writeDelimitedTo(outputStream);
- Message response = readResponse();
-
- if (!response.getMessageTypeCase().equals(expectedResult)) {
- throw new RuntimeException(
- "Got invalid response for request " + request + ", response " + response);
- }
- return response;
+ public ProtobufChannel(final Set<InetSocketAddress> locators, String username, String password,
+ String keyStorePath, String trustStorePath, String protocols, String ciphers)
+ throws GeneralSecurityException, IOException {
+ socket = connectToAServer(locators, username, password, keyStorePath, trustStorePath, protocols,
+ ciphers);
}
public void close() throws IOException {
- this.socket.close();
+ socket.close();
}
public boolean isClosed() {
- return this.socket.isClosed();
+ return socket.isClosed();
}
- private Socket connectToAServer(String username, String password) throws IOException {
- InetSocketAddress server = findAServer(username, password);
- Socket socket = new Socket(server.getAddress(), server.getPort());
+ private Socket connectToAServer(final Set<InetSocketAddress> locators, String username,
+ String password, String keyStorePath, String trustStorePath, String protocols, String ciphers)
+ throws GeneralSecurityException, IOException {
+ InetSocketAddress server =
+ findAServer(locators, username, password, keyStorePath, trustStorePath, protocols, ciphers);
+ Socket socket = createSocket(server.getAddress(), server.getPort(), keyStorePath,
+ trustStorePath, protocols, ciphers);
socket.setTcpNoDelay(true);
socket.setSendBufferSize(65535);
socket.setReceiveBufferSize(65535);
@@ -96,13 +89,16 @@ class ProtobufChannel {
*
* @return The server chosen by the Locator service for this client
*/
- private InetSocketAddress findAServer(String username, String password) throws IOException {
+ private InetSocketAddress findAServer(final Set<InetSocketAddress> locators, String username,
+ String password, String keyStorePath, String trustStorePath, String protocols, String ciphers)
+ throws GeneralSecurityException, IOException {
IOException lastException = null;
for (InetSocketAddress locator : locators) {
Socket locatorSocket = null;
try {
- locatorSocket = new Socket(locator.getAddress(), locator.getPort());
+ locatorSocket = createSocket(locator.getAddress(), locator.getPort(), keyStorePath,
+ trustStorePath, protocols, ciphers);
final OutputStream outputStream = locatorSocket.getOutputStream();
final InputStream inputStream = locatorSocket.getInputStream();
@@ -179,6 +175,18 @@ class ProtobufChannel {
}
}
+ Message sendRequest(final Message request, MessageTypeCase expectedResult) throws IOException {
+ final OutputStream outputStream = socket.getOutputStream();
+ request.writeDelimitedTo(outputStream);
+ Message response = readResponse();
+
+ if (!response.getMessageTypeCase().equals(expectedResult)) {
+ throw new RuntimeException(
+ "Got invalid response for request " + request + ", response " + response);
+ }
+ return response;
+ }
+
private Message readResponse() throws IOException {
final InputStream inputStream = socket.getInputStream();
Message response = ClientProtocol.Message.parseDelimitedFrom(inputStream);
@@ -192,4 +200,11 @@ class ProtobufChannel {
return response;
}
+ private Socket createSocket(InetAddress host, int port, String keyStorePath,
+ String trustStorePath, String protocols, String ciphers)
+ throws GeneralSecurityException, IOException {
+ return new SocketFactory().setHost(host).setPort(port).setTimeout(5000)
+ .setKeyStorePath(keyStorePath).setTrustStorePath(trustStorePath).setProtocols(protocols)
+ .setCiphers(ciphers).connect();
+ }
}
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufDriver.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufDriver.java
index bded2b0..c780ea8 100644
--- a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufDriver.java
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/ProtobufDriver.java
@@ -16,6 +16,7 @@ package org.apache.geode.experimental.driver;
import java.io.IOException;
import java.net.InetSocketAddress;
+import java.security.GeneralSecurityException;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -47,11 +48,17 @@ public class ProtobufDriver implements Driver {
* GemFire servers that have Protobuf enabled.
* @param username User identity as a string; may be <code>null</code>.
* @param password User proof as a string; may be <code>null</code>.
+ * @param keyStorePath Path to SSL key store; SSL is <em>not</em> used if <code>null</code>.
+ * @param trustStorePath Path to SSL trust store; SSL is <em>not</em> used if <code>null</code>.
+ * @param protocols Space-separated list of the SSL protocols to enable.
+ * @param ciphers Space-separated list of the SSL cipher suites to enable.
* @throws IOException
*/
- ProtobufDriver(Set<InetSocketAddress> locators, String username, String password)
- throws IOException {
- this.channel = new ProtobufChannel(locators, username, password);
+ ProtobufDriver(Set<InetSocketAddress> locators, String username, String password,
+ String keyStorePath, String trustStorePath, String protocols, String ciphers)
+ throws GeneralSecurityException, IOException {
+ this.channel = new ProtobufChannel(locators, username, password, keyStorePath, trustStorePath,
+ protocols, ciphers);
}
@Override
diff --git a/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/SocketFactory.java b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/SocketFactory.java
new file mode 100644
index 0000000..eefc8e1
--- /dev/null
+++ b/geode-experimental-driver/src/main/java/org/apache/geode/experimental/driver/SocketFactory.java
@@ -0,0 +1,203 @@
+/*
+ * 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.experimental.driver;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.Objects;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+public class SocketFactory {
+ private InetAddress host;
+ private int port;
+ private int timeout = -1;
+ private String keyStorePath;
+ private String trustStorePath;
+ private String protocols;
+ private String ciphers;
+
+ public SocketFactory() {
+ // Do nothing.
+ }
+
+ public InetAddress getHost() {
+ return host;
+ }
+
+ public SocketFactory setHost(InetAddress host) {
+ this.host = host;
+ return this;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public SocketFactory setPort(int port) {
+ this.port = port;
+ return this;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public SocketFactory setTimeout(int timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ public String getKeyStorePath() {
+ return keyStorePath;
+ }
+
+ public SocketFactory setKeyStorePath(String keyStorePath) {
+ this.keyStorePath = keyStorePath;
+ return this;
+ }
+
+ public String getTrustStorePath() {
+ return trustStorePath;
+ }
+
+ public SocketFactory setTrustStorePath(String trustStorePath) {
+ this.trustStorePath = trustStorePath;
+ return this;
+ }
+
+ public String getProtocols() {
+ return protocols;
+ }
+
+ public SocketFactory setProtocols(String protocols) {
+ this.protocols = protocols;
+ return this;
+ }
+
+ public String getCiphers() {
+ return ciphers;
+ }
+
+ public SocketFactory setCiphers(String ciphers) {
+ this.ciphers = ciphers;
+ return this;
+ }
+
+ public boolean isSsl() {
+ return (!Objects.isNull(keyStorePath) && !keyStorePath.isEmpty())
+ || (!Objects.isNull(trustStorePath) && !trustStorePath.isEmpty());
+ }
+
+ public Socket connect() throws GeneralSecurityException, IOException {
+ Socket socket;
+
+ SocketAddress sockaddr = new InetSocketAddress(host, port);
+ if (isSsl()) {
+ final SSLContext sslContext = getSSLContextInstance();
+ final KeyManager[] keyManagers = getKeyManagers();
+ final TrustManager[] trustManagers = getTrustManagers();
+ sslContext.init(keyManagers, trustManagers, null /* use the default secure random */);
+
+ javax.net.SocketFactory socketFactory = sslContext.getSocketFactory();
+ socket = socketFactory.createSocket();
+
+ socket.connect(sockaddr, Math.max(timeout, 0));
+ if (socket instanceof SSLSocket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ sslSocket.setUseClientMode(true); // Should this depend on clientSide?
+ sslSocket.setEnableSessionCreation(true);
+ if (timeout > 0) {
+ sslSocket.setSoTimeout(timeout);
+ }
+ if (protocols != null) {
+ sslSocket.setEnabledProtocols(protocols.split(" "));
+ }
+ if (ciphers != null) {
+ sslSocket.setEnabledCipherSuites(ciphers.split(" "));
+ }
+ sslSocket.startHandshake();
+ }
+ } else {
+ socket = new Socket();
+ socket.connect(sockaddr, Math.max(timeout, 0));
+ }
+
+ return socket;
+ }
+
+ private SSLContext getSSLContextInstance() throws IOException {
+ String[] knownAlgorithms = {"SSL", "SSLv2", "SSLv3", "TLS", "TLSv1", "TLSv1.1", "TLSv1.2"};
+ for (String algo : knownAlgorithms) {
+ try {
+ return SSLContext.getInstance(algo);
+ } catch (NoSuchAlgorithmException e) {
+ // continue
+ }
+ }
+ throw new IOException("SSL not configured correctly, unable create an SSLContext");
+ }
+
+ private TrustManager[] getTrustManagers()
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
+ if (Objects.isNull(trustStorePath)) {
+ return new TrustManager[0];
+ }
+
+ String trustStoreType = "jks";
+ KeyStore keyStore = KeyStore.getInstance(trustStoreType);
+ FileInputStream fileInputStream = new FileInputStream(trustStorePath);
+ char[] password = "password".toCharArray();
+ keyStore.load(fileInputStream, password);
+
+ TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(keyStore);
+ return tmf.getTrustManagers();
+ }
+
+ private KeyManager[] getKeyManagers() throws KeyStoreException, IOException,
+ NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
+ if (Objects.isNull(keyStorePath)) {
+ return new KeyManager[0];
+ }
+
+ String keyStoreType = "jks";
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ FileInputStream fileInputStream = new FileInputStream(keyStorePath);
+ char[] password = "password".toCharArray();
+ keyStore.load(fileInputStream, password);
+
+ KeyManagerFactory keyManagerFactory =
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(keyStore, password);
+ return keyManagerFactory.getKeyManagers();
+ }
+}
diff --git a/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/SSLTest.java b/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/SSLTest.java
new file mode 100644
index 0000000..6cd3e7a
--- /dev/null
+++ b/geode-experimental-driver/src/test/java/org/apache/geode/experimental/driver/SSLTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.experimental.driver;
+
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_REQUIRE_AUTHENTICATION;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.internal.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.net.ssl.SSLException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.Locator;
+import org.apache.geode.internal.net.SocketCreatorFactory;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.apache.geode.util.test.TestUtil;
+
+@Category(IntegrationTest.class)
+public class SSLTest {
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private final String SERVER_KEY_STORE =
+ TestUtil.getResourcePath(SSLTest.class, "cacheserver.keystore");
+ private final String SERVER_TRUST_STORE =
+ TestUtil.getResourcePath(SSLTest.class, "cacheserver.truststore");
+ private final String BOGUSSERVER_KEY_STORE =
+ TestUtil.getResourcePath(SSLTest.class, "bogusserver.keystore");
+ private final String BOGUSCLIENT_KEY_STORE =
+ TestUtil.getResourcePath(SSLTest.class, "bogusclient.keystore");
+ private final String CLIENT_KEY_STORE =
+ TestUtil.getResourcePath(SSLTest.class, "client.keystore");
+ private final String CLIENT_TRUST_STORE =
+ TestUtil.getResourcePath(SSLTest.class, "client.truststore");
+ private Locator locator;
+ private Cache cache;
+ private Driver driver;
+ private int locatorPort;
+
+ @Before
+ public void enableProtobuf() throws Exception {
+ System.setProperty("geode.feature-protobuf-protocol", "true");
+ }
+
+ private void startLocator(String keyStore, boolean twoWayAuthentication, String protocols,
+ String ciphers) throws IOException {
+ // Create a cache
+ Properties properties = new Properties();
+ properties.put(SSL_ENABLED_COMPONENTS, "all");
+ properties.put(SSL_KEYSTORE_TYPE, "jks");
+ properties.put(SSL_KEYSTORE, keyStore);
+ properties.put(SSL_PROTOCOLS, protocols);
+ properties.put(SSL_CIPHERS, ciphers);
+ properties.put(SSL_KEYSTORE_PASSWORD, "password");
+ properties.put(SSL_TRUSTSTORE, SERVER_TRUST_STORE);
+ properties.put(SSL_TRUSTSTORE_PASSWORD, "password");
+ properties.put(SSL_REQUIRE_AUTHENTICATION, String.valueOf(twoWayAuthentication));
+
+ CacheFactory cf = new CacheFactory(properties);
+ cf.set(ConfigurationProperties.MCAST_PORT, "0");
+ cache = cf.create();
+ cache.createRegionFactory(RegionShortcut.REPLICATE).create("region");
+
+ // Start a locator
+ locator = Locator.startLocatorAndDS(0, null, properties);
+ locatorPort = locator.getPort();
+ }
+
+ private void startServer() throws IOException {
+ CacheServer server = cache.addCacheServer();
+ server.setPort(0);
+ server.start();
+ }
+
+ @After
+ public void cleanup() {
+ cache.close();
+ locator.stop();
+ SocketCreatorFactory.close();
+ }
+
+ @Test
+ public void driverFailsToConnectWhenThereAreNoServers() throws Exception {
+ startLocator(SERVER_KEY_STORE, true, "any", "any");
+ expectedException.expect(IOException.class);
+ driver = new DriverFactory().addLocator("localhost", locatorPort).create();
+ }
+
+ @Test
+ public void driverCanConnectWithTwoWayAuthentication() throws Exception {
+ startLocator(SERVER_KEY_STORE, true, "any", "any");
+ startServer();
+ driver = new DriverFactory().addLocator("localhost", locatorPort)
+ .setTrustStorePath(CLIENT_TRUST_STORE).setKeyStorePath(CLIENT_KEY_STORE).create();
+ Set<String> regionsOnServer = driver.getRegionNames();
+ assertEquals(Collections.singleton("region"), regionsOnServer);
+ assertTrue(driver.isConnected());
+ }
+
+ @Test
+ public void driverCannotConnectWithBogusClientKeystore() throws Exception {
+ startLocator(SERVER_KEY_STORE, true, "any", "any");
+ startServer();
+ expectedException.expect(SSLException.class);
+ driver = new DriverFactory().addLocator("localhost", locatorPort)
+ .setTrustStorePath(CLIENT_TRUST_STORE).setKeyStorePath(BOGUSCLIENT_KEY_STORE).create();
+ }
+
+ @Test
+ public void driverCannotConnectWithBogusServerKeystore() throws Exception {
+ startLocator(BOGUSSERVER_KEY_STORE, true, "any", "any");
+ startServer();
+ expectedException.expect(SSLException.class);
+ driver = new DriverFactory().addLocator("localhost", locatorPort)
+ .setTrustStorePath(CLIENT_TRUST_STORE).setKeyStorePath(CLIENT_KEY_STORE).create();
+ }
+
+ @Test
+ public void driverCanConnectWithOneWayAuthentication() throws Exception {
+ startLocator(SERVER_KEY_STORE, false, "any", "any");
+ startServer();
+ driver = new DriverFactory().addLocator("localhost", locatorPort)
+ .setTrustStorePath(CLIENT_TRUST_STORE).create();
+ Set<String> regionsOnServer = driver.getRegionNames();
+ assertEquals(Collections.singleton("region"), regionsOnServer);
+ assertTrue(driver.isConnected());
+ }
+
+ @Test
+ public void driverCannotConnectIfProtocolsMismatch() throws Exception {
+ startLocator(SERVER_KEY_STORE, true, "TLSv1.1", "any");
+ startServer();
+ expectedException.expect(SSLException.class);
+ driver = new DriverFactory().addLocator("localhost", locatorPort)
+ .setTrustStorePath(CLIENT_TRUST_STORE).setKeyStorePath(CLIENT_KEY_STORE)
+ .setProtocols("TLSv1.2").create();
+ }
+
+ @Test
+ public void driverCannotConnectIfCiphersMismatch() throws Exception {
+ startLocator(SERVER_KEY_STORE, true, "any", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256");
+ startServer();
+ expectedException.expect(SSLException.class);
+ driver = new DriverFactory().addLocator("localhost", locatorPort)
+ .setTrustStorePath(CLIENT_TRUST_STORE).setKeyStorePath(CLIENT_KEY_STORE)
+ .setCiphers("TLS_DHE_DSS_WITH_AES_128_CBC_SHA").create();
+ }
+}
diff --git a/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/bogusclient.keystore b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/bogusclient.keystore
new file mode 100644
index 0000000..8dce373
Binary files /dev/null and b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/bogusclient.keystore differ
diff --git a/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/bogusserver.keystore b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/bogusserver.keystore
new file mode 100644
index 0000000..d6e2523
Binary files /dev/null and b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/bogusserver.keystore differ
diff --git a/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/cacheserver.keystore b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/cacheserver.keystore
new file mode 100644
index 0000000..adbea7b
Binary files /dev/null and b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/cacheserver.keystore differ
diff --git a/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/cacheserver.truststore b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/cacheserver.truststore
new file mode 100644
index 0000000..0cfb813
Binary files /dev/null and b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/cacheserver.truststore differ
diff --git a/geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/client.keystore
similarity index 61%
copy from geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore
copy to geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/client.keystore
index 3920963..38a315d 100644
Binary files a/geode-core/src/test/resources/org/apache/geode/cache/client/internal/cacheserver.truststore and b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/client.keystore differ
diff --git a/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/client.truststore b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/client.truststore
new file mode 100644
index 0000000..d598b86
Binary files /dev/null and b/geode-experimental-driver/src/test/resources/org/apache/geode/experimental/driver/client.truststore differ
--
To stop receiving notification emails like this one, please contact
pivotalsarge@apache.org.