Add SSL support for sentinel-datasource-redis (#3045)
This commit is contained in:
parent
cc6923f078
commit
74f7d184cf
|
|
@ -15,7 +15,7 @@
|
|||
<properties>
|
||||
<java.source.version>1.8</java.source.version>
|
||||
<java.target.version>1.8</java.target.version>
|
||||
<lettuce.version>5.0.1.RELEASE</lettuce.version>
|
||||
<lettuce.version>5.3.1.RELEASE</lettuce.version>
|
||||
<redis.mock.version>0.1.6</redis.mock.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ import com.alibaba.csp.sentinel.util.StringUtil;
|
|||
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.SslOptions;
|
||||
import io.lettuce.core.api.sync.RedisCommands;
|
||||
import io.lettuce.core.cluster.ClusterClientOptions;
|
||||
import io.lettuce.core.cluster.RedisClusterClient;
|
||||
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
|
||||
import io.lettuce.core.cluster.pubsub.StatefulRedisClusterPubSubConnection;
|
||||
|
|
@ -33,10 +35,10 @@ import io.lettuce.core.pubsub.RedisPubSubAdapter;
|
|||
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
|
||||
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -94,19 +96,70 @@ public class RedisDataSource<T> extends AbstractDataSource<String, T> {
|
|||
subscribeFromChannel(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* init SslOptions, support jks or pem format
|
||||
*
|
||||
* @param connectionConfig Redis connection config
|
||||
* @return a new SslOptions
|
||||
*/
|
||||
private SslOptions initSslOptions(RedisConnectionConfig connectionConfig) {
|
||||
if (!connectionConfig.isSslEnable()){
|
||||
return null;
|
||||
}
|
||||
|
||||
SslOptions.Builder sslOptionsBuilder = SslOptions.builder();
|
||||
|
||||
if (connectionConfig.getTrustedCertificatesPath() != null){
|
||||
if (connectionConfig.getTrustedCertificatesPath().endsWith(".jks")){
|
||||
// if the value is end with .jks,think it is java key store format,to invoke truststore method
|
||||
sslOptionsBuilder.truststore(
|
||||
new File(connectionConfig.getTrustedCertificatesPath()),
|
||||
connectionConfig.getTrustedCertificatesJksPassword()
|
||||
);
|
||||
} else {
|
||||
// if the value is not end with .jks,think it is pem format,to invoke trustManager method
|
||||
sslOptionsBuilder.trustManager(new File(connectionConfig.getTrustedCertificatesPath()));
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionConfig.getKeyCertChainFilePath() != null || connectionConfig.getKeyFilePath() != null) {
|
||||
if (connectionConfig.getKeyFilePath().endsWith(".jks")){
|
||||
sslOptionsBuilder.keystore(
|
||||
new File(connectionConfig.getKeyCertChainFilePath()),
|
||||
connectionConfig.getKeyFilePassword() == null ? null : connectionConfig.getKeyFilePassword().toCharArray()
|
||||
);
|
||||
} else {
|
||||
sslOptionsBuilder.keyManager(
|
||||
new File(connectionConfig.getKeyCertChainFilePath()),
|
||||
new File(connectionConfig.getKeyFilePath()),
|
||||
connectionConfig.getKeyFilePassword() == null ? null : connectionConfig.getKeyFilePassword().toCharArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
return sslOptionsBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Redis client fromm {@code RedisConnectionConfig}.
|
||||
*
|
||||
* @return a new {@link RedisClient}
|
||||
*/
|
||||
private RedisClient getRedisClient(RedisConnectionConfig connectionConfig) {
|
||||
RedisClient redisClient;
|
||||
if (connectionConfig.getRedisSentinels().size() == 0) {
|
||||
RecordLog.info("[RedisDataSource] Creating stand-alone mode Redis client");
|
||||
return getRedisStandaloneClient(connectionConfig);
|
||||
redisClient = getRedisStandaloneClient(connectionConfig);
|
||||
} else {
|
||||
RecordLog.info("[RedisDataSource] Creating Redis Sentinel mode Redis client");
|
||||
return getRedisSentinelClient(connectionConfig);
|
||||
redisClient = getRedisSentinelClient(connectionConfig);
|
||||
}
|
||||
SslOptions sslOptions = initSslOptions(connectionConfig);
|
||||
if (sslOptions != null){
|
||||
redisClient.setOptions(
|
||||
ClusterClientOptions.builder().sslOptions(sslOptions).build()
|
||||
);
|
||||
}
|
||||
return redisClient;
|
||||
}
|
||||
|
||||
private RedisClusterClient getRedisClusterClient(RedisConnectionConfig connectionConfig) {
|
||||
|
|
@ -119,6 +172,7 @@ public class RedisDataSource<T> extends AbstractDataSource<String, T> {
|
|||
RedisURI.Builder clusterRedisUriBuilder = RedisURI.builder();
|
||||
clusterRedisUriBuilder.withHost(config.getHost())
|
||||
.withPort(config.getPort())
|
||||
.withSsl(config.isSslEnable())
|
||||
.withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
|
||||
//All redis nodes must have same password
|
||||
if (password != null) {
|
||||
|
|
@ -126,9 +180,17 @@ public class RedisDataSource<T> extends AbstractDataSource<String, T> {
|
|||
}
|
||||
redisUris.add(clusterRedisUriBuilder.build());
|
||||
}
|
||||
return RedisClusterClient.create(redisUris);
|
||||
RedisClusterClient redisClusterClient = RedisClusterClient.create(redisUris);
|
||||
SslOptions sslOptions = initSslOptions(connectionConfig);
|
||||
if (sslOptions != null){
|
||||
redisClusterClient.setOptions(
|
||||
ClusterClientOptions.builder().sslOptions(sslOptions).build()
|
||||
);
|
||||
}
|
||||
return redisClusterClient;
|
||||
}
|
||||
|
||||
|
||||
private RedisClient getRedisStandaloneClient(RedisConnectionConfig connectionConfig) {
|
||||
char[] password = connectionConfig.getPassword();
|
||||
String clientName = connectionConfig.getClientName();
|
||||
|
|
@ -136,6 +198,7 @@ public class RedisDataSource<T> extends AbstractDataSource<String, T> {
|
|||
redisUriBuilder.withHost(connectionConfig.getHost())
|
||||
.withPort(connectionConfig.getPort())
|
||||
.withDatabase(connectionConfig.getDatabase())
|
||||
.withSsl(connectionConfig.isSslEnable())
|
||||
.withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
|
||||
if (password != null) {
|
||||
redisUriBuilder.withPassword(connectionConfig.getPassword());
|
||||
|
|
@ -160,6 +223,7 @@ public class RedisDataSource<T> extends AbstractDataSource<String, T> {
|
|||
sentinelRedisUriBuilder.withClientName(clientName);
|
||||
}
|
||||
sentinelRedisUriBuilder.withSentinelMasterId(connectionConfig.getRedisSentinelMasterId())
|
||||
.withSsl(connectionConfig.isSslEnable())
|
||||
.withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
|
||||
return RedisClient.create(sentinelRedisUriBuilder.build());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,12 @@ public class RedisConnectionConfig {
|
|||
private String host;
|
||||
private String redisSentinelMasterId;
|
||||
private int port;
|
||||
private boolean sslEnable;
|
||||
private String trustedCertificatesPath;
|
||||
private String trustedCertificatesJksPassword;
|
||||
private String keyCertChainFilePath;
|
||||
private String keyFilePath;
|
||||
private String keyFilePassword;
|
||||
private int database;
|
||||
private String clientName;
|
||||
private char[] password;
|
||||
|
|
@ -329,6 +335,12 @@ public class RedisConnectionConfig {
|
|||
private int database;
|
||||
private String clientName;
|
||||
private char[] password;
|
||||
private boolean sslEnable;
|
||||
private String trustedCertificatesPath;
|
||||
private String trustedCertificatesJksPassword;
|
||||
private String keyCertChainFilePath;
|
||||
private String keyFilePath;
|
||||
private String keyFilePassword;
|
||||
private long timeout = DEFAULT_TIMEOUT_MILLISECONDS;
|
||||
private final List<RedisHostAndPort> redisSentinels = new ArrayList<RedisHostAndPort>();
|
||||
private final List<RedisHostAndPort> redisClusters = new ArrayList<RedisHostAndPort>();
|
||||
|
|
@ -563,6 +575,7 @@ public class RedisConnectionConfig {
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures authentication.
|
||||
*
|
||||
|
|
@ -619,6 +632,75 @@ public class RedisConnectionConfig {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sslEnable.
|
||||
*
|
||||
* @param sslEnable sslEnable
|
||||
* @return the value of Builder
|
||||
*/
|
||||
public RedisConnectionConfig.Builder withSslEnable(boolean sslEnable) {
|
||||
this.sslEnable = sslEnable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trustedCertificatesPath.
|
||||
*
|
||||
* @param trustedCertificatesPath trustedCertificatesPath
|
||||
* @return the value of Builder
|
||||
*/
|
||||
public RedisConnectionConfig.Builder withTrustedCertificatesPath(String trustedCertificatesPath) {
|
||||
|
||||
AssertUtil.notEmpty(trustedCertificatesPath, "trusted certificates path must not empty");
|
||||
|
||||
this.trustedCertificatesPath = trustedCertificatesPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trustedCertificatesJksPassword.
|
||||
*
|
||||
* @param trustedCertificatesJksPassword trustedCertificatesJksPassword
|
||||
* @return the value of Builder
|
||||
*/
|
||||
public RedisConnectionConfig.Builder withTrustedCertificatesJksPassword(String trustedCertificatesJksPassword) {
|
||||
this.trustedCertificatesJksPassword = trustedCertificatesJksPassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyCertChainFilePath.
|
||||
*
|
||||
* @param keyCertChainFilePath keyCertChainFilePath
|
||||
* @return the value of Builder
|
||||
*/
|
||||
public RedisConnectionConfig.Builder withKeyCertChainFilePath(String keyCertChainFilePath) {
|
||||
this.keyCertChainFilePath = keyCertChainFilePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyFilePath.
|
||||
*
|
||||
* @param keyFilePath keyFilePath
|
||||
* @return the value of Builder
|
||||
*/
|
||||
public RedisConnectionConfig.Builder withKeyFilePath(String keyFilePath) {
|
||||
this.keyFilePath = keyFilePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyFilePassword.
|
||||
*
|
||||
* @param keyFilePassword keyFilePassword
|
||||
* @return the value of Builder
|
||||
*/
|
||||
public RedisConnectionConfig.Builder withKeyFilePassword(String keyFilePassword) {
|
||||
this.keyFilePassword = keyFilePassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the RedisConnectionConfig.
|
||||
*/
|
||||
|
|
@ -630,32 +712,41 @@ public class RedisConnectionConfig {
|
|||
+ "Sentinel");
|
||||
}
|
||||
|
||||
RedisConnectionConfig redisURI = new RedisConnectionConfig();
|
||||
redisURI.setHost(host);
|
||||
redisURI.setPort(port);
|
||||
RedisConnectionConfig redisConnectionConfig = new RedisConnectionConfig();
|
||||
redisConnectionConfig.setHost(host);
|
||||
redisConnectionConfig.setPort(port);
|
||||
|
||||
if (password != null) {
|
||||
redisURI.setPassword(password);
|
||||
if (sslEnable){
|
||||
redisConnectionConfig.setSslEnable(true);
|
||||
redisConnectionConfig.setTrustedCertificatesPath(trustedCertificatesPath);
|
||||
redisConnectionConfig.setTrustedCertificatesJksPassword(trustedCertificatesJksPassword);
|
||||
redisConnectionConfig.setKeyCertChainFilePath(keyCertChainFilePath);
|
||||
redisConnectionConfig.setKeyFilePath(keyFilePath);
|
||||
redisConnectionConfig.setKeyFilePassword(keyFilePassword);
|
||||
}
|
||||
|
||||
redisURI.setDatabase(database);
|
||||
redisURI.setClientName(clientName);
|
||||
if (password != null) {
|
||||
redisConnectionConfig.setPassword(password);
|
||||
}
|
||||
|
||||
redisURI.setRedisSentinelMasterId(redisSentinelMasterId);
|
||||
redisConnectionConfig.setDatabase(database);
|
||||
redisConnectionConfig.setClientName(clientName);
|
||||
|
||||
redisConnectionConfig.setRedisSentinelMasterId(redisSentinelMasterId);
|
||||
|
||||
for (RedisHostAndPort sentinel : redisSentinels) {
|
||||
redisURI.getRedisSentinels().add(
|
||||
redisConnectionConfig.getRedisSentinels().add(
|
||||
new RedisConnectionConfig(sentinel.getHost(), sentinel.getPort(), timeout));
|
||||
}
|
||||
|
||||
for (RedisHostAndPort sentinel : redisClusters) {
|
||||
redisURI.getRedisClusters().add(
|
||||
redisConnectionConfig.getRedisClusters().add(
|
||||
new RedisConnectionConfig(sentinel.getHost(), sentinel.getPort(), timeout));
|
||||
}
|
||||
|
||||
redisURI.setTimeout(timeout);
|
||||
redisConnectionConfig.setTimeout(timeout);
|
||||
|
||||
return redisURI;
|
||||
return redisConnectionConfig;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -665,4 +756,125 @@ public class RedisConnectionConfig {
|
|||
private static boolean isValidPort(int port) {
|
||||
return port >= 0 && port <= 65535;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of trustedCertificatesPath.
|
||||
*
|
||||
* @return the value of trustedCertificatesPath
|
||||
*/
|
||||
public String getTrustedCertificatesPath() {
|
||||
return trustedCertificatesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trustedCertificatesPath.
|
||||
* <p>
|
||||
* <p>You can use getTrustedCertificatesPath() to get the value of trustedCertificatesPath</p>
|
||||
*
|
||||
* @param trustedCertificatesPath trustedCertificatesPath
|
||||
*/
|
||||
public void setTrustedCertificatesPath(String trustedCertificatesPath) {
|
||||
this.trustedCertificatesPath = trustedCertificatesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of trustedCertificatesJksPassword.
|
||||
*
|
||||
* @return the value of trustedCertificatesJksPassword
|
||||
*/
|
||||
public String getTrustedCertificatesJksPassword() {
|
||||
return trustedCertificatesJksPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trustedCertificatesJksPassword.
|
||||
* <p>
|
||||
* <p>You can use getTrustedCertificatesJksPassword() to get the value of trustedCertificatesJksPassword</p>
|
||||
*
|
||||
* @param trustedCertificatesJksPassword trustedCertificatesJksPassword
|
||||
*/
|
||||
public void setTrustedCertificatesJksPassword(String trustedCertificatesJksPassword) {
|
||||
this.trustedCertificatesJksPassword = trustedCertificatesJksPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of keyCertChainFilePath.
|
||||
*
|
||||
* @return the value of keyCertChainFilePath
|
||||
*/
|
||||
public String getKeyCertChainFilePath() {
|
||||
return keyCertChainFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyCertChainFilePath.
|
||||
* <p>
|
||||
* <p>You can use getKeyCertChainFilePath() to get the value of keyCertChainFilePath</p>
|
||||
*
|
||||
* @param keyCertChainFilePath keyCertChainFilePath
|
||||
*/
|
||||
public void setKeyCertChainFilePath(String keyCertChainFilePath) {
|
||||
this.keyCertChainFilePath = keyCertChainFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of keyFilePath.
|
||||
*
|
||||
* @return the value of keyFilePath
|
||||
*/
|
||||
public String getKeyFilePath() {
|
||||
return keyFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyFilePath.
|
||||
* <p>
|
||||
* <p>You can use getKeyFilePath() to get the value of keyFilePath</p>
|
||||
*
|
||||
* @param keyFilePath keyFilePath
|
||||
*/
|
||||
public void setKeyFilePath(String keyFilePath) {
|
||||
this.keyFilePath = keyFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of keyFilePassword.
|
||||
*
|
||||
* @return the value of keyFilePassword
|
||||
*/
|
||||
public String getKeyFilePassword() {
|
||||
return keyFilePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keyFilePassword.
|
||||
* <p>
|
||||
* <p>You can use getKeyFilePassword() to get the value of keyFilePassword</p>
|
||||
*
|
||||
* @param keyFilePassword keyFilePassword
|
||||
*/
|
||||
public void setKeyFilePassword(String keyFilePassword) {
|
||||
this.keyFilePassword = keyFilePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sslEnable.
|
||||
* <p>
|
||||
* <p>You can use isSslEnable() to get the value of sslEnable</p>
|
||||
*
|
||||
* @param sslEnable sslEnable
|
||||
*/
|
||||
public void setSslEnable(boolean sslEnable) {
|
||||
this.sslEnable = sslEnable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value of sslEnable.
|
||||
*
|
||||
* @return the value of sslEnable
|
||||
*/
|
||||
public boolean isSslEnable() {
|
||||
return sslEnable;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public class RedisConnectionConfigTest {
|
|||
Assert.assertEquals(host, redisConnectionConfig.getHost());
|
||||
Assert.assertEquals(RedisConnectionConfig.DEFAULT_REDIS_PORT, redisConnectionConfig.getPort());
|
||||
Assert.assertEquals(RedisConnectionConfig.DEFAULT_TIMEOUT_MILLISECONDS, redisConnectionConfig.getTimeout());
|
||||
Assert.assertFalse(redisConnectionConfig.isSslEnable());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -133,4 +134,32 @@ public class RedisConnectionConfigTest {
|
|||
Assert.assertNull(redisConnectionConfig.getHost());
|
||||
Assert.assertEquals(3, redisConnectionConfig.getRedisClusters().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedisSsl() throws Exception {
|
||||
String host = "localhost";
|
||||
int port = 1879;
|
||||
String trustedCertificatesPath = "trustedCertificatesPath";
|
||||
String trustedCertificatesJksPassword = "trustedCertificatesJksPassword";
|
||||
String keyCertChainFilePath = "keyCertChainFilePath";
|
||||
String keyFilePath = "keyFilePath";
|
||||
String keyFilePassword = "keyFilePassword";
|
||||
RedisConnectionConfig redisConnectionConfig = RedisConnectionConfig.Builder.redis(host)
|
||||
.withHost(host)
|
||||
.withPort(port)
|
||||
.withSslEnable(true)
|
||||
.withTrustedCertificatesPath(trustedCertificatesPath)
|
||||
.withTrustedCertificatesJksPassword(trustedCertificatesJksPassword)
|
||||
.withKeyCertChainFilePath(keyCertChainFilePath)
|
||||
.withKeyFilePath(keyFilePath)
|
||||
.withKeyFilePassword(keyFilePassword)
|
||||
.build();
|
||||
|
||||
Assert.assertTrue(redisConnectionConfig.isSslEnable());
|
||||
Assert.assertEquals(redisConnectionConfig.getTrustedCertificatesPath(), trustedCertificatesPath);
|
||||
Assert.assertEquals(redisConnectionConfig.getTrustedCertificatesJksPassword(), trustedCertificatesJksPassword);
|
||||
Assert.assertEquals(redisConnectionConfig.getKeyCertChainFilePath(), keyCertChainFilePath);
|
||||
Assert.assertEquals(redisConnectionConfig.getKeyFilePath(), keyFilePath);
|
||||
Assert.assertEquals(redisConnectionConfig.getKeyFilePassword(), keyFilePassword);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue