Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SSL support to JedisCluster #1550

Merged
merged 12 commits into from Aug 1, 2018
15 changes: 15 additions & 0 deletions Makefile
Expand Up @@ -218,6 +218,21 @@ pid = /tmp/stunnel.pid
[redis]
accept = 127.0.0.1:6390
connect = 127.0.0.1:6379
[redis_cluster_1]
accept = 127.0.0.1:8379
connect = 127.0.0.1:7379
[redis_cluster_2]
accept = 127.0.0.1:8380
connect = 127.0.001:7380
[redis_cluster_3]
accept = 127.0.0.1:8381
connect = 127.0.001:7381
[redis_cluster_4]
accept = 127.0.0.1:8382
connect = 127.0.0.1:7382
[redis_cluster_5]
accept = 127.0.0.1:8383
connect = 127.0.0.1:7383
endef

export REDIS1_CONF
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryJedisCluster.java
Expand Up @@ -16,6 +16,10 @@
import java.util.Map;
import java.util.Set;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.util.JedisClusterHashTagUtil;

Expand Down Expand Up @@ -63,6 +67,19 @@ public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeo
connectionTimeout, soTimeout, password, clientName);
this.maxAttempts = maxAttempts;
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts, String password, String clientName, GenericObjectPoolConfig poolConfig,
boolean ssl) {
this(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig, ssl, null, null, null, null);
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts, String password, String clientName, GenericObjectPoolConfig poolConfig,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier, JedisClusterPortMap portMap) {
this.connectionHandler = new JedisSlotBasedConnectionHandler(jedisClusterNode, poolConfig,
connectionTimeout, soTimeout, password, clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, portMap);
this.maxAttempts = maxAttempts;
}

@Override
public void close() {
Expand Down
34 changes: 33 additions & 1 deletion src/main/java/redis/clients/jedis/JedisCluster.java
Expand Up @@ -14,6 +14,10 @@
import java.util.Map.Entry;
import java.util.Set;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import redis.clients.jedis.params.SetParams;
Expand Down Expand Up @@ -61,6 +65,20 @@ public JedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig) {
this(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig);
}

public JedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig,
boolean ssl) {
super(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig, ssl);
}

public JedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier, JedisClusterPortMap portMap) {
super(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig,
ssl, sslSocketFactory, sslParameters, hostnameVerifier, portMap);
}

public JedisCluster(Set<HostAndPort> nodes) {
this(nodes, DEFAULT_TIMEOUT);
Expand Down Expand Up @@ -100,7 +118,21 @@ public JedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, in
public JedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig) {
super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig);
}
}

public JedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig,
boolean ssl) {
super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig, ssl);
}

public JedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier, JedisClusterPortMap portMap) {
super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig,
ssl, sslSocketFactory, sslParameters, hostnameVerifier, portMap);
}

@Override
public String set(final String key, final String value) {
Expand Down
Expand Up @@ -4,6 +4,10 @@
import java.util.Map;
import java.util.Set;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import redis.clients.jedis.exceptions.JedisConnectionException;
Expand All @@ -18,9 +22,17 @@ public JedisClusterConnectionHandler(Set<HostAndPort> nodes,

public JedisClusterConnectionHandler(Set<HostAndPort> nodes,
final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, String clientName) {
this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout, password, clientName);
initializeSlotsCache(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName);
}
this(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName, false, null, null, null, null);
}

public JedisClusterConnectionHandler(Set<HostAndPort> nodes,
final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, String clientName,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier, JedisClusterPortMap portMap) {
this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout, password, clientName,
ssl, sslSocketFactory, sslParameters, hostnameVerifier, portMap);
initializeSlotsCache(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
}

abstract Jedis getConnection();

Expand All @@ -34,12 +46,12 @@ public Map<String, JedisPool> getNodes() {
return cache.getNodes();
}

private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig,
int connectionTimeout, int soTimeout, String password, String clientName) {
private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, String clientName,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) {
for (HostAndPort hostAndPort : startNodes) {
Jedis jedis = null;
try {
jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), connectionTimeout, soTimeout);
jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), connectionTimeout, soTimeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
if (password != null) {
jedis.auth(password);
}
Expand Down
38 changes: 34 additions & 4 deletions src/main/java/redis/clients/jedis/JedisClusterInfoCache.java
Expand Up @@ -8,6 +8,10 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import redis.clients.jedis.exceptions.JedisConnectionException;
Expand All @@ -29,19 +33,37 @@ public class JedisClusterInfoCache {
private String password;
private String clientName;

private boolean ssl;
private SSLSocketFactory sslSocketFactory;
private SSLParameters sslParameters;
private HostnameVerifier hostnameVerifier;
private JedisClusterPortMap portMap;

private static final int MASTER_NODE_INDEX = 2;

public JedisClusterInfoCache(final GenericObjectPoolConfig poolConfig, int timeout) {
this(poolConfig, timeout, timeout, null, null);
}

public JedisClusterInfoCache(final GenericObjectPoolConfig poolConfig,
final int connectionTimeout, final int soTimeout, final String password, final String clientName) {
sazzad16 marked this conversation as resolved.
Show resolved Hide resolved
this(poolConfig, connectionTimeout, soTimeout, password, clientName, false, null, null, null, null);
}

public JedisClusterInfoCache(final GenericObjectPoolConfig poolConfig,
final int connectionTimeout, final int soTimeout, final String password, final String clientName,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier, JedisClusterPortMap portMap) {
this.poolConfig = poolConfig;
this.connectionTimeout = connectionTimeout;
this.soTimeout = soTimeout;
this.password = password;
this.clientName = clientName;
this.ssl = ssl;
this.sslSocketFactory = sslSocketFactory;
this.sslParameters = sslParameters;
this.hostnameVerifier = hostnameVerifier;
this.portMap = portMap;
}

public void discoverClusterNodesAndSlots(Jedis jedis) {
Expand Down Expand Up @@ -143,8 +165,15 @@ private void discoverClusterSlots(Jedis jedis) {
}

private HostAndPort generateHostAndPort(List<Object> hostInfos) {
return new HostAndPort(SafeEncoder.encode((byte[]) hostInfos.get(0)),
((Long) hostInfos.get(1)).intValue());
String host = SafeEncoder.encode((byte[]) hostInfos.get(0));
int port = ((Long) hostInfos.get(1)).intValue();
if (ssl && portMap != null) {
Integer mappedPort = portMap.getSSLPort(port);
if (mappedPort != null) {
port = mappedPort;
}
}
return new HostAndPort(host, port);
}

public JedisPool setupNodeIfNotExist(HostAndPort node) {
Expand All @@ -155,7 +184,8 @@ public JedisPool setupNodeIfNotExist(HostAndPort node) {
if (existingPool != null) return existingPool;

JedisPool nodePool = new JedisPool(poolConfig, node.getHost(), node.getPort(),
connectionTimeout, soTimeout, password, 0, clientName, false, null, null, null);
connectionTimeout, soTimeout, password, 0, clientName,
ssl, sslSocketFactory, sslParameters, hostnameVerifier);
nodes.put(nodeKey, nodePool);
return nodePool;
} finally {
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/redis/clients/jedis/JedisClusterPortMap.java
@@ -0,0 +1,5 @@
package redis.clients.jedis;

public interface JedisClusterPortMap {
int getSSLPort(int port);
}
Expand Up @@ -5,6 +5,10 @@

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;

import redis.clients.jedis.exceptions.JedisException;
import redis.clients.jedis.exceptions.JedisNoReachableClusterNodeException;

Expand All @@ -27,6 +31,11 @@ public JedisSlotBasedConnectionHandler(Set<HostAndPort> nodes, GenericObjectPool
public JedisSlotBasedConnectionHandler(Set<HostAndPort> nodes, GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, String clientName) {
super(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName);
}

public JedisSlotBasedConnectionHandler(Set<HostAndPort> nodes, GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, String clientName,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier, JedisClusterPortMap portMap) {
super(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, portMap);
}

@Override
public Jedis getConnection() {
Expand Down