Fixed - CertificateException while connecting to Azure or AWS Elasticache config endpoint. #1296

pull/1344/head
Nikita 7 years ago
parent 0a49fdb050
commit 9a179e14cd

@ -55,6 +55,7 @@ public class RedisClientConfig {
private boolean keepAlive; private boolean keepAlive;
private boolean tcpNoDelay; private boolean tcpNoDelay;
private String sslHostname;
private boolean sslEnableEndpointIdentification = true; private boolean sslEnableEndpointIdentification = true;
private SslProvider sslProvider = SslProvider.JDK; private SslProvider sslProvider = SslProvider.JDK;
private URI sslTruststore; private URI sslTruststore;
@ -89,6 +90,15 @@ public class RedisClientConfig {
this.sslKeystore = config.sslKeystore; this.sslKeystore = config.sslKeystore;
this.sslKeystorePassword = config.sslKeystorePassword; this.sslKeystorePassword = config.sslKeystorePassword;
this.resolverGroup = config.resolverGroup; this.resolverGroup = config.resolverGroup;
this.sslHostname = config.sslHostname;
}
public String getSslHostname() {
return sslHostname;
}
public RedisClientConfig setSslHostname(String sslHostname) {
this.sslHostname = sslHostname;
return this;
} }
public RedisClientConfig setAddress(String host, int port) { public RedisClientConfig setAddress(String host, int port) {

@ -33,6 +33,7 @@ import org.redisson.client.RedisClient;
import org.redisson.client.RedisClientConfig; import org.redisson.client.RedisClientConfig;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.config.SslProvider; import org.redisson.config.SslProvider;
import org.redisson.misc.URIBuilder;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel; import io.netty.channel.Channel;
@ -162,7 +163,12 @@ public class RedisChannelInitializer extends ChannelInitializer<Channel> {
} }
SslContext sslContext = sslContextBuilder.build(); SslContext sslContext = sslContextBuilder.build();
SSLEngine sslEngine = sslContext.newEngine(ch.alloc(), config.getAddress().getHost(), config.getAddress().getPort()); String hostname = config.getSslHostname();
if (hostname == null || URIBuilder.isValidIP(hostname)) {
hostname = config.getAddress().getHost();
}
SSLEngine sslEngine = sslContext.newEngine(ch.alloc(), hostname, config.getAddress().getPort());
sslEngine.setSSLParameters(sslParams); sslEngine.setSSLParameters(sslParams);
SslHandler sslHandler = new SslHandler(sslEngine); SslHandler sslHandler = new SslHandler(sslEngine);

@ -82,6 +82,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
private RedisStrictCommand<List<ClusterNodeInfo>> clusterNodesCommand; private RedisStrictCommand<List<ClusterNodeInfo>> clusterNodesCommand;
private String configEndpointHostName;
private boolean isConfigEndpoint; private boolean isConfigEndpoint;
private AddressResolver<InetSocketAddress> resolver; private AddressResolver<InetSocketAddress> resolver;
@ -95,7 +97,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
Throwable lastException = null; Throwable lastException = null;
List<String> failedMasters = new ArrayList<String>(); List<String> failedMasters = new ArrayList<String>();
for (URI addr : cfg.getNodeAddresses()) { for (URI addr : cfg.getNodeAddresses()) {
RFuture<RedisConnection> connectionFuture = connectToNode(cfg, addr, null); RFuture<RedisConnection> connectionFuture = connectToNode(cfg, addr, null, addr.getHost());
try { try {
RedisConnection connection = connectionFuture.syncUninterruptibly().getNow(); RedisConnection connection = connectionFuture.syncUninterruptibly().getNow();
@ -104,6 +106,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
Future<List<InetSocketAddress>> addrsFuture = resolver.resolveAll(InetSocketAddress.createUnresolved(addr.getHost(), addr.getPort())); Future<List<InetSocketAddress>> addrsFuture = resolver.resolveAll(InetSocketAddress.createUnresolved(addr.getHost(), addr.getPort()));
List<InetSocketAddress> allAddrs = addrsFuture.syncUninterruptibly().getNow(); List<InetSocketAddress> allAddrs = addrsFuture.syncUninterruptibly().getNow();
if (allAddrs.size() > 1) { if (allAddrs.size() > 1) {
configEndpointHostName = addr.getHost();
isConfigEndpoint = true; isConfigEndpoint = true;
} else { } else {
resolver.close(); resolver.close();
@ -178,8 +181,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
@Override @Override
protected RedisClientConfig createRedisConfig(NodeType type, URI address, int timeout, int commandTimeout) { protected RedisClientConfig createRedisConfig(NodeType type, URI address, int timeout, int commandTimeout, String sslHostname) {
RedisClientConfig result = super.createRedisConfig(type, address, timeout, commandTimeout); RedisClientConfig result = super.createRedisConfig(type, address, timeout, commandTimeout, sslHostname);
result.setReadOnly(type == NodeType.SLAVE && config.getReadMode() != ReadMode.MASTER); result.setReadOnly(type == NodeType.SLAVE && config.getReadMode() != ReadMode.MASTER);
return result; return result;
} }
@ -198,7 +201,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
final RPromise<Collection<RFuture<Void>>> result = new RedissonPromise<Collection<RFuture<Void>>>(); final RPromise<Collection<RFuture<Void>>> result = new RedissonPromise<Collection<RFuture<Void>>>();
RFuture<RedisConnection> connectionFuture = connectToNode(cfg, partition.getMasterAddress(), null); RFuture<RedisConnection> connectionFuture = connectToNode(cfg, partition.getMasterAddress(), null, configEndpointHostName);
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -351,7 +354,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return; return;
} }
final URI uri = iterator.next(); final URI uri = iterator.next();
RFuture<RedisConnection> connectionFuture = connectToNode(cfg, uri, null); RFuture<RedisConnection> connectionFuture = connectToNode(cfg, uri, null, configEndpointHostName);
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -652,6 +655,10 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
} }
public String getConfigEndpointHostName() {
return configEndpointHostName;
}
@Override @Override
public int calcSlot(String key) { public int calcSlot(String key) {
if (key == null) { if (key == null) {

@ -97,11 +97,11 @@ public interface ConnectionManager {
RFuture<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command); RFuture<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command);
RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout); RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout, String sslHostname);
RedisClient createClient(NodeType type, InetSocketAddress address, URI uri); RedisClient createClient(NodeType type, InetSocketAddress address, URI uri, String sslHostname);
RedisClient createClient(NodeType type, URI address); RedisClient createClient(NodeType type, URI address, String sslHostname);
MasterSlaveEntry getEntry(RedisClient redisClient); MasterSlaveEntry getEntry(RedisClient redisClient);

@ -250,7 +250,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
} }
protected RFuture<RedisConnection> connectToNode(BaseMasterSlaveServersConfig<?> cfg, final URI addr, RedisClient client) { protected RFuture<RedisConnection> connectToNode(BaseMasterSlaveServersConfig<?> cfg, final URI addr, RedisClient client, String sslHostname) {
final Object key; final Object key;
if (client != null) { if (client != null) {
key = client; key = client;
@ -263,7 +263,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
if (addr != null) { if (addr != null) {
client = createClient(NodeType.MASTER, addr, cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); client = createClient(NodeType.MASTER, addr, cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts(), sslHostname);
} }
final RPromise<RedisConnection> result = new RedissonPromise<RedisConnection>(); final RPromise<RedisConnection> result = new RedissonPromise<RedisConnection>();
RFuture<RedisConnection> future = client.connectAsync(); RFuture<RedisConnection> future = client.connectAsync();
@ -430,15 +430,15 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
@Override @Override
public RedisClient createClient(NodeType type, URI address) { public RedisClient createClient(NodeType type, URI address, String sslHostname) {
RedisClient client = createClient(type, address, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts()); RedisClient client = createClient(type, address, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts(), sslHostname);
clientEntries.put(client, new RedisClientEntry(client, commandExecutor, type)); clientEntries.put(client, new RedisClientEntry(client, commandExecutor, type));
return client; return client;
} }
@Override @Override
public RedisClient createClient(NodeType type, InetSocketAddress address, URI uri) { public RedisClient createClient(NodeType type, InetSocketAddress address, URI uri, String sslHostname) {
RedisClient client = createClient(type, address, uri, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts()); RedisClient client = createClient(type, address, uri, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts(), sslHostname);
clientEntries.put(client, new RedisClientEntry(client, commandExecutor, type)); clientEntries.put(client, new RedisClientEntry(client, commandExecutor, type));
return client; return client;
} }
@ -452,19 +452,19 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
@Override @Override
public RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout) { public RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout, String sslHostname) {
RedisClientConfig redisConfig = createRedisConfig(type, address, timeout, commandTimeout); RedisClientConfig redisConfig = createRedisConfig(type, address, timeout, commandTimeout, sslHostname);
return RedisClient.create(redisConfig); return RedisClient.create(redisConfig);
} }
private RedisClient createClient(NodeType type, InetSocketAddress address, URI uri, int timeout, int commandTimeout) { private RedisClient createClient(NodeType type, InetSocketAddress address, URI uri, int timeout, int commandTimeout, String sslHostname) {
RedisClientConfig redisConfig = createRedisConfig(type, null, timeout, commandTimeout); RedisClientConfig redisConfig = createRedisConfig(type, null, timeout, commandTimeout, sslHostname);
redisConfig.setAddress(address, uri); redisConfig.setAddress(address, uri);
return RedisClient.create(redisConfig); return RedisClient.create(redisConfig);
} }
protected RedisClientConfig createRedisConfig(NodeType type, URI address, int timeout, int commandTimeout) { protected RedisClientConfig createRedisConfig(NodeType type, URI address, int timeout, int commandTimeout, String sslHostname) {
RedisClientConfig redisConfig = new RedisClientConfig(); RedisClientConfig redisConfig = new RedisClientConfig();
redisConfig.setAddress(address) redisConfig.setAddress(address)
.setTimer(timer) .setTimer(timer)
@ -474,6 +474,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
.setSocketChannelClass(socketChannelClass) .setSocketChannelClass(socketChannelClass)
.setConnectTimeout(timeout) .setConnectTimeout(timeout)
.setCommandTimeout(commandTimeout) .setCommandTimeout(commandTimeout)
.setSslHostname(sslHostname)
.setSslEnableEndpointIdentification(config.isSslEnableEndpointIdentification()) .setSslEnableEndpointIdentification(config.isSslEnableEndpointIdentification())
.setSslProvider(config.getSslProvider()) .setSslProvider(config.getSslProvider())
.setSslTruststore(config.getSslTruststore()) .setSslTruststore(config.getSslTruststore())

@ -35,6 +35,7 @@ import org.redisson.client.protocol.CommandData;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.pubsub.PubSubType; import org.redisson.client.protocol.pubsub.PubSubType;
import org.redisson.cluster.ClusterConnectionManager;
import org.redisson.cluster.ClusterSlotRange; import org.redisson.cluster.ClusterSlotRange;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.ReadMode; import org.redisson.config.ReadMode;
@ -77,6 +78,8 @@ public class MasterSlaveEntry {
final AtomicBoolean active = new AtomicBoolean(true); final AtomicBoolean active = new AtomicBoolean(true);
String sslHostname;
public MasterSlaveEntry(Set<ClusterSlotRange> slotRanges, ConnectionManager connectionManager, MasterSlaveServersConfig config) { public MasterSlaveEntry(Set<ClusterSlotRange> slotRanges, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
for (ClusterSlotRange clusterSlotRange : slotRanges) { for (ClusterSlotRange clusterSlotRange : slotRanges) {
for (int i = clusterSlotRange.getStartSlot(); i < clusterSlotRange.getEndSlot() + 1; i++) { for (int i = clusterSlotRange.getStartSlot(); i < clusterSlotRange.getEndSlot() + 1; i++) {
@ -89,6 +92,10 @@ public class MasterSlaveEntry {
slaveBalancer = new LoadBalancerManager(config, connectionManager, this); slaveBalancer = new LoadBalancerManager(config, connectionManager, this);
writeConnectionPool = new MasterConnectionPool(config, connectionManager, this); writeConnectionPool = new MasterConnectionPool(config, connectionManager, this);
pubSubConnectionPool = new MasterPubSubConnectionPool(config, connectionManager, this); pubSubConnectionPool = new MasterPubSubConnectionPool(config, connectionManager, this);
if (connectionManager instanceof ClusterConnectionManager) {
sslHostname = ((ClusterConnectionManager) connectionManager).getConfigEndpointHostName();
}
} }
public MasterSlaveServersConfig getConfig() { public MasterSlaveServersConfig getConfig() {
@ -111,13 +118,13 @@ public class MasterSlaveEntry {
} }
public RFuture<RedisClient> setupMasterEntry(InetSocketAddress address, URI uri) { public RFuture<RedisClient> setupMasterEntry(InetSocketAddress address, URI uri) {
RedisClient client = connectionManager.createClient(NodeType.MASTER, address, uri); RedisClient client = connectionManager.createClient(NodeType.MASTER, address, uri, sslHostname);
return setupMasterEntry(client); return setupMasterEntry(client);
} }
public RFuture<RedisClient> setupMasterEntry(URI address) { public RFuture<RedisClient> setupMasterEntry(URI address) {
RedisClient client = connectionManager.createClient(NodeType.MASTER, address); RedisClient client = connectionManager.createClient(NodeType.MASTER, address, sslHostname);
return setupMasterEntry(client); return setupMasterEntry(client);
} }
@ -404,12 +411,12 @@ public class MasterSlaveEntry {
} }
private RFuture<Void> addSlave(InetSocketAddress address, URI uri, final boolean freezed, final NodeType nodeType) { private RFuture<Void> addSlave(InetSocketAddress address, URI uri, final boolean freezed, final NodeType nodeType) {
RedisClient client = connectionManager.createClient(NodeType.SLAVE, address, uri); RedisClient client = connectionManager.createClient(NodeType.SLAVE, address, uri, sslHostname);
return addSlave(client, freezed, nodeType); return addSlave(client, freezed, nodeType);
} }
private RFuture<Void> addSlave(URI address, final boolean freezed, final NodeType nodeType) { private RFuture<Void> addSlave(URI address, final boolean freezed, final NodeType nodeType) {
RedisClient client = connectionManager.createClient(NodeType.SLAVE, address); RedisClient client = connectionManager.createClient(NodeType.SLAVE, address, sslHostname);
return addSlave(client, freezed, nodeType); return addSlave(client, freezed, nodeType);
} }

@ -67,7 +67,7 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager {
initTimer(this.config); initTimer(this.config);
for (URI addr : cfg.getNodeAddresses()) { for (URI addr : cfg.getNodeAddresses()) {
RFuture<RedisConnection> connectionFuture = connectToNode(cfg, addr, null); RFuture<RedisConnection> connectionFuture = connectToNode(cfg, addr, null, addr.getHost());
connectionFuture.awaitUninterruptibly(); connectionFuture.awaitUninterruptibly();
RedisConnection connection = connectionFuture.getNow(); RedisConnection connection = connectionFuture.getNow();
if (connection == null) { if (connection == null) {
@ -119,7 +119,7 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager {
return; return;
} }
RFuture<RedisConnection> connectionFuture = connectToNode(cfg, addr, null); RFuture<RedisConnection> connectionFuture = connectToNode(cfg, addr, null, addr.getHost());
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {

@ -90,7 +90,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
this.sentinelResolver = resolverGroup.getResolver(getGroup().next()); this.sentinelResolver = resolverGroup.getResolver(getGroup().next());
for (URI addr : cfg.getSentinelAddresses()) { for (URI addr : cfg.getSentinelAddresses()) {
RedisClient client = createClient(NodeType.SENTINEL, addr, this.config.getConnectTimeout(), this.config.getRetryInterval() * this.config.getRetryAttempts()); RedisClient client = createClient(NodeType.SENTINEL, addr, this.config.getConnectTimeout(), this.config.getRetryInterval() * this.config.getRetryAttempts(), null);
try { try {
RedisConnection connection = client.connect(); RedisConnection connection = client.connect();
if (!connection.isActive()) { if (!connection.isActive()) {
@ -261,7 +261,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
} }
RedisClient client = iterator.next(); RedisClient client = iterator.next();
RFuture<RedisConnection> connectionFuture = connectToNode(null, null, client); RFuture<RedisConnection> connectionFuture = connectToNode(null, null, client, null);
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -433,7 +433,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
return RedissonPromise.newSucceededFuture(null); return RedissonPromise.newSucceededFuture(null);
} }
client = createClient(NodeType.SENTINEL, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); client = createClient(NodeType.SENTINEL, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts(), null);
RedisClient oldClient = sentinels.putIfAbsent(key, client); RedisClient oldClient = sentinels.putIfAbsent(key, client);
if (oldClient != null) { if (oldClient != null) {
return RedissonPromise.newSucceededFuture(null); return RedissonPromise.newSucceededFuture(null);

@ -17,6 +17,7 @@ package org.redisson.misc;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.util.regex.Pattern;
/** /**
* *
@ -24,20 +25,29 @@ import java.net.URI;
*/ */
public class URIBuilder { public class URIBuilder {
private static final Pattern ipv4Pattern = Pattern.compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])", Pattern.CASE_INSENSITIVE);
private static final Pattern ipv6Pattern = Pattern.compile("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}", Pattern.CASE_INSENSITIVE);
public static URI create(String uri) { public static URI create(String uri) {
URI u = URI.create(uri); URI u = URI.create(uri);
//Let's assuming most of the time it is OK. // Let's assuming most of the time it is OK.
if (u.getHost() != null) { if (u.getHost() != null) {
return u; return u;
} }
String s = uri.substring(0, uri.lastIndexOf(":")) String s = uri.substring(0, uri.lastIndexOf(":")).replaceFirst("redis://", "").replaceFirst("rediss://", "");
.replaceFirst("redis://", "") // Assuming this is an IPv6 format, other situations will be handled by
.replaceFirst("rediss://", ""); // Netty at a later stage.
//Assuming this is an IPv6 format, other situations will be handled by
//Netty at a later stage.
return URI.create(uri.replace(s, "[" + s + "]")); return URI.create(uri.replace(s, "[" + s + "]"));
} }
public static boolean isValidIP(String host) {
if (ipv4Pattern.matcher(host).matches()) {
return true;
}
return ipv6Pattern.matcher(host).matches();
}
public static boolean compare(InetSocketAddress entryAddr, URI addr) { public static boolean compare(InetSocketAddress entryAddr, URI addr) {
if (((entryAddr.getHostName() != null && entryAddr.getHostName().equals(addr.getHost())) if (((entryAddr.getHostName() != null && entryAddr.getHostName().equals(addr.getHost()))
|| entryAddr.getAddress().getHostAddress().equals(addr.getHost())) || entryAddr.getAddress().getHostAddress().equals(addr.getHost()))

Loading…
Cancel
Save