diff --git a/boms/geode-all-bom/src/test/resources/expected-pom.xml b/boms/geode-all-bom/src/test/resources/expected-pom.xml
index 7df23cd5261f..f8c6696bccd7 100644
--- a/boms/geode-all-bom/src/test/resources/expected-pom.xml
+++ b/boms/geode-all-bom/src/test/resources/expected-pom.xml
@@ -472,7 +472,7 @@
redis.clients
jedis
- 2.9.0
+ 3.2.0
compile
diff --git a/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy b/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
index 2c72c75b6f53..152430b6d74a 100644
--- a/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
+++ b/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
@@ -156,7 +156,7 @@ class DependencyConstraints implements Plugin {
api(group: 'org.springframework.ldap', name: 'spring-ldap-core', version: '2.3.2.RELEASE')
api(group: 'org.springframework.shell', name: 'spring-shell', version: '1.2.0.RELEASE')
api(group: 'pl.pragmatists', name: 'JUnitParams', version: '1.1.0')
- api(group: 'redis.clients', name: 'jedis', version: '2.9.0')
+ api(group: 'redis.clients', name: 'jedis', version: '3.2.0')
api(group: 'xerces', name: 'xercesImpl', version: '2.12.0')
api(group: 'com.arakelian', name: 'java-jq', version: '0.10.1')
api(group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-joda', version: '2.9.8')
diff --git a/geode-redis/build.gradle b/geode-redis/build.gradle
index b107fe9b7f3c..740142545b81 100644
--- a/geode-redis/build.gradle
+++ b/geode-redis/build.gradle
@@ -32,6 +32,7 @@ dependencies {
testCompile(project(':geode-junit'))
testCompile('org.mockito:mockito-core')
+ integrationTestCompile(project(':geode-dunit'))
integrationTestCompile(project(':geode-junit'))
integrationTestCompile('redis.clients:jedis')
diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/GeoJUnitTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/GeoJUnitTest.java
index d8d29fd4aa72..221055f33eb9 100755
--- a/geode-redis/src/integrationTest/java/org/apache/geode/redis/GeoJUnitTest.java
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/GeoJUnitTest.java
@@ -37,7 +37,7 @@
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;
-import redis.clients.jedis.params.geo.GeoRadiusParam;
+import redis.clients.jedis.params.GeoRadiusParam;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.GemFireCache;
diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/SSLTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/SSLTest.java
new file mode 100644
index 000000000000..13fa4f011052
--- /dev/null
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/SSLTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.redis;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import redis.clients.jedis.Jedis;
+
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.internal.admin.SSLConfig;
+import org.apache.geode.internal.net.SSLConfigurationFactory;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.test.junit.categories.RedisTest;
+import org.apache.geode.test.junit.rules.ServerStarterRule;
+
+@Category({RedisTest.class})
+public class SSLTest {
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @ClassRule
+ public static ServerStarterRule sslEnabledServer = new ServerStarterRule()
+ .withSSL("server", true, true)
+ .withProperty("redis-bind-address", "localhost")
+ .withProperty("redis-port", "11211")
+ .withAutoStart();
+
+
+ @Test
+ public void canConnectOverSSL() {
+ SSLConfig sslConfigForComponent = SSLConfigurationFactory.getSSLConfigForComponent(
+ ((InternalDistributedSystem) sslEnabledServer.getCache().getDistributedSystem())
+ .getConfig(),
+ SecurableCommunicationChannel.SERVER);
+
+ System.setProperty("javax.net.ssl.trustStore", sslConfigForComponent.getTruststore());
+ System.setProperty("javax.net.ssl.trustStoreType", "JKS");
+
+ Jedis localhost = new Jedis("localhost", 11211, true);
+
+ assertThat(localhost.ping()).isEqualTo("PONG");
+ }
+
+ @Test
+ public void cannotConnectOverCleartext() {
+ SSLConfig sslConfigForComponent = SSLConfigurationFactory.getSSLConfigForComponent(
+ ((InternalDistributedSystem) sslEnabledServer.getCache().getDistributedSystem())
+ .getConfig(),
+ SecurableCommunicationChannel.ALL);
+
+ System.setProperty("javax.net.ssl.trustStore", sslConfigForComponent.getTruststore());
+ System.setProperty("javax.net.ssl.trustStoreType", "JKS");
+
+ Jedis localhost = new Jedis("localhost", 11211, false);
+
+ assertThatThrownBy(() -> localhost.ping());
+ }
+
+}
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java b/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java
index 27748deadebe..da8e0e51a1fd 100644
--- a/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/GeodeRedisServer.java
@@ -16,10 +16,12 @@
import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
+import java.security.KeyStore;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
@@ -30,6 +32,8 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.net.ssl.KeyManagerFactory;
+
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
@@ -44,6 +48,8 @@
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.oio.OioServerSocketChannel;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
import io.netty.util.concurrent.Future;
import org.apache.geode.LogWriter;
@@ -59,11 +65,14 @@
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.util.CacheListenerAdapter;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.internal.admin.SSLConfig;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.InternalRegionFactory;
import org.apache.geode.internal.hll.HyperLogLogPlus;
import org.apache.geode.internal.inet.LocalHostUtil;
+import org.apache.geode.internal.net.SSLConfigurationFactory;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.redis.internal.ByteArrayWrapper;
import org.apache.geode.redis.internal.ByteToCommandDecoder;
import org.apache.geode.redis.internal.Coder;
@@ -513,6 +522,7 @@ public Thread newThread(Runnable r) {
String pwd = system.getConfig().getRedisPassword();
final byte[] pwdB = Coder.stringToBytes(pwd);
ServerBootstrap b = new ServerBootstrap();
+
b.group(bossGroup, workerGroup).channel(socketClass)
.childHandler(new ChannelInitializer() {
@Override
@@ -521,6 +531,7 @@ public void initChannel(SocketChannel ch) throws Exception {
logger.fine("GeodeRedisServer-Connection established with " + ch.remoteAddress());
}
ChannelPipeline p = ch.pipeline();
+ addSSLIfEnabled(ch, p);
p.addLast(ByteToCommandDecoder.class.getSimpleName(), new ByteToCommandDecoder());
p.addLast(ExecutionHandlerContext.class.getSimpleName(),
new ExecutionHandlerContext(ch, cache, regionCache, GeodeRedisServer.this, pwdB,
@@ -546,6 +557,37 @@ public void initChannel(SocketChannel ch) throws Exception {
this.serverChannel = f.channel();
}
+ private void addSSLIfEnabled(SocketChannel ch, ChannelPipeline p) {
+
+ SSLConfig sslConfigForComponent =
+ SSLConfigurationFactory.getSSLConfigForComponent(
+ ((InternalDistributedSystem) cache.getDistributedSystem()).getConfig(),
+ SecurableCommunicationChannel.SERVER);
+
+ if (!sslConfigForComponent.isEnabled()) {
+ return;
+ }
+
+ SslContext sslContext;
+ try {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(new FileInputStream(sslConfigForComponent.getKeystore()),
+ sslConfigForComponent.getKeystorePassword().toCharArray()/**/);
+
+ // Set up key manager factory to use our key store
+ KeyManagerFactory kmf =
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, sslConfigForComponent.getKeystorePassword().toCharArray());
+
+ SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(kmf);
+ sslContext = sslContextBuilder.build();
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ p.addLast(sslContext.newHandler(ch.alloc()));
+ }
+
/**
* Takes an entry event and processes it. If the entry denotes that a {@link
* RedisDataType#REDIS_LIST} or {@link RedisDataType#REDIS_SORTEDSET} was created then this