Skip to content

Commit

Permalink
GEODE-8616: Enabling SSL for Redis-API (apache#4733)
Browse files Browse the repository at this point in the history
  • Loading branch information
Venkateswara Prasath Durairaj authored Feb 26, 2020
1 parent 7236070 commit 5f7312a
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 3 deletions.
2 changes: 1 addition & 1 deletion boms/geode-all-bom/src/test/resources/expected-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<version>3.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class DependencyConstraints implements Plugin<Project> {
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')
Expand Down
1 change: 1 addition & 0 deletions geode-redis/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<SocketChannel>() {
@Override
Expand All @@ -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,
Expand All @@ -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
Expand Down

0 comments on commit 5f7312a

Please sign in to comment.