DATAREDIS-1060 - Redis password should not automatically be applied to Sentinel.
We now expose two separate properties in RedisSentinelConfiguration to configure the data password individually from the sentinel password. Original pull request: #495.
This commit is contained in:
committed by
Mark Paluch
parent
df9c57ad98
commit
1955074eb7
@@ -337,6 +337,79 @@ public interface RedisConfiguration {
|
||||
* @return {@link Set} of sentinels. Never {@literal null}.
|
||||
*/
|
||||
Set<RedisNode> getSentinels();
|
||||
|
||||
/**
|
||||
* Get the {@link RedisPassword} used when authenticating with a Redis Server.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
default RedisPassword getDataNodePassword() {
|
||||
return getPassword();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and set a {@link RedisPassword} to be used when authenticating with Sentinel from the given {@link String}
|
||||
*
|
||||
* @param password can be {@literal null}.
|
||||
* @throws IllegalStateException if the {@link #useDataNodeAuthenticationForSentinel(boolean) Data Node Password}
|
||||
* should be used for authenticating with Redis Sentinel.
|
||||
* @since 2.2.2
|
||||
*/
|
||||
default void setSentinelPassword(@Nullable String password) {
|
||||
setSentinelPassword(RedisPassword.of(password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and set a {@link RedisPassword} to be used when authenticating with Sentinel from the given
|
||||
* {@link Character} sequence.
|
||||
*
|
||||
* @param password can be {@literal null}.
|
||||
* @throws IllegalStateException if the {@link #useDataNodeAuthenticationForSentinel(boolean) Data Node Password}
|
||||
* should be used for authenticating with Redis Sentinel.
|
||||
* @since 2.2.2
|
||||
*/
|
||||
default void setSentinelPassword(@Nullable char[] password) {
|
||||
setSentinelPassword(RedisPassword.of(password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link RedisPassword} to be used when authenticating with Sentinel.
|
||||
*
|
||||
* @param password must not be {@literal null} use {@link RedisPassword#none()} instead.
|
||||
* @throws IllegalStateException if the {@link #useDataNodeAuthenticationForSentinel(boolean) Data Node Password}
|
||||
* should be used for authenticating with Redis Sentinel.
|
||||
* @since 2.2.2
|
||||
*/
|
||||
void setSentinelPassword(RedisPassword password);
|
||||
|
||||
/**
|
||||
* Get the {@link RedisPassword} to use when connecting to a Redis Sentinel. <br />
|
||||
* This can be the password explicitly set via {@link #setSentinelPassword(RedisPassword)}, or the
|
||||
* {@link #getDataNodePassword() Data Node password} if it should be also used for
|
||||
* {@link #getUseDataNodeAuthenticationForSentinel() sentinel}, or {@link RedisPassword#none()} if no password has
|
||||
* been set.
|
||||
*
|
||||
* @return the {@link RedisPassword} for authenticating with Sentinel.
|
||||
* @since 2.2.2
|
||||
*/
|
||||
RedisPassword getSentinelPassword();
|
||||
|
||||
/**
|
||||
* Use the {@link #getDataNodePassword() RedisPassword} also for authentication with Redis Sentinel.
|
||||
*
|
||||
* @param useDataNodeAuthenticationForSentinel
|
||||
* @throws IllegalStateException if a {@link #getSentinelPassword() Sentinel Password} is already set.
|
||||
* @since 2.2.2
|
||||
*/
|
||||
void useDataNodeAuthenticationForSentinel(boolean useDataNodeAuthenticationForSentinel);
|
||||
|
||||
/**
|
||||
* Use the {@link #getDataNodePassword() RedisPassword} also for authentication with Redis Sentinel.
|
||||
*
|
||||
* @return
|
||||
* @since 2.2.2
|
||||
*/
|
||||
boolean getUseDataNodeAuthenticationForSentinel();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.redis.connection;
|
||||
|
||||
import static org.springframework.util.Assert.*;
|
||||
import static org.springframework.util.Assert.hasText;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -46,11 +44,15 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
|
||||
private static final String REDIS_SENTINEL_MASTER_CONFIG_PROPERTY = "spring.redis.sentinel.master";
|
||||
private static final String REDIS_SENTINEL_NODES_CONFIG_PROPERTY = "spring.redis.sentinel.nodes";
|
||||
private static final String REDIS_SENTINEL_PASSWORD_CONFIG_PROPERTY = "spring.redis.sentinel.password";
|
||||
|
||||
private @Nullable NamedNode master;
|
||||
private Set<RedisNode> sentinels;
|
||||
private int database;
|
||||
private RedisPassword password = RedisPassword.none();
|
||||
|
||||
private RedisPassword dataNodePassword = RedisPassword.none();
|
||||
private RedisPassword sentinelPassword = RedisPassword.none();
|
||||
private boolean useDataNodePasswordForSentinel = false;
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisSentinelConfiguration}.
|
||||
@@ -89,7 +91,7 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
*/
|
||||
public RedisSentinelConfiguration(PropertySource<?> propertySource) {
|
||||
|
||||
notNull(propertySource, "PropertySource must not be null!");
|
||||
Assert.notNull(propertySource, "PropertySource must not be null!");
|
||||
|
||||
this.sentinels = new LinkedHashSet<>();
|
||||
|
||||
@@ -101,6 +103,10 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
appendSentinels(
|
||||
commaDelimitedListToSet(propertySource.getProperty(REDIS_SENTINEL_NODES_CONFIG_PROPERTY).toString()));
|
||||
}
|
||||
|
||||
if (propertySource.containsProperty(REDIS_SENTINEL_PASSWORD_CONFIG_PROPERTY)) {
|
||||
this.setSentinelPassword(propertySource.getProperty(REDIS_SENTINEL_PASSWORD_CONFIG_PROPERTY).toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +116,7 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
*/
|
||||
public void setSentinels(Iterable<RedisNode> sentinels) {
|
||||
|
||||
notNull(sentinels, "Cannot set sentinels to 'null'.");
|
||||
Assert.notNull(sentinels, "Cannot set sentinels to 'null'.");
|
||||
|
||||
this.sentinels.clear();
|
||||
|
||||
@@ -134,7 +140,7 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
*/
|
||||
public void addSentinel(RedisNode sentinel) {
|
||||
|
||||
notNull(sentinel, "Sentinel must not be 'null'.");
|
||||
Assert.notNull(sentinel, "Sentinel must not be 'null'.");
|
||||
this.sentinels.add(sentinel);
|
||||
}
|
||||
|
||||
@@ -144,7 +150,7 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
*/
|
||||
public void setMaster(NamedNode master) {
|
||||
|
||||
notNull(master, "Sentinel master node must not be 'null'.");
|
||||
Assert.notNull(master, "Sentinel master node must not be 'null'.");
|
||||
this.master = master;
|
||||
}
|
||||
|
||||
@@ -230,7 +236,7 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
*/
|
||||
@Override
|
||||
public RedisPassword getPassword() {
|
||||
return password;
|
||||
return dataNodePassword;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -242,15 +248,60 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
|
||||
Assert.notNull(password, "RedisPassword must not be null!");
|
||||
|
||||
this.password = password;
|
||||
this.dataNodePassword = password;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setSentinelPassword(org.springframework.data.redis.connection.RedisPassword)
|
||||
*/
|
||||
public void setSentinelPassword(RedisPassword sentinelPassword) {
|
||||
|
||||
Assert.state(!useDataNodePasswordForSentinel,
|
||||
"Configuration uses Redis Data Node password for authenticating with Sentinel. Please set 'RedisSentinelConfiguration.useDataNodeAuthenticationForSentinel(false)' before using this option.");
|
||||
Assert.notNull(sentinelPassword, "SentinelPassword must not be null!");
|
||||
this.sentinelPassword = sentinelPassword;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setSentinelPassword()
|
||||
*/
|
||||
@Override
|
||||
public RedisPassword getSentinelPassword() {
|
||||
return getUseDataNodeAuthenticationForSentinel() ? this.dataNodePassword : sentinelPassword;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#useDataNodeAuthenticationForSentinel(boolean)
|
||||
*/
|
||||
@Override
|
||||
public void useDataNodeAuthenticationForSentinel(boolean useDataNodeAuthenticationForSentinel) {
|
||||
|
||||
if (useDataNodeAuthenticationForSentinel) {
|
||||
Assert.state(!this.sentinelPassword.isPresent(),
|
||||
"Configuration already defines a password for authenticating with Sentinel. Please use 'RedisSentinelConfiguration.setSentinelPassword(RedisPassword.none())' remove the password.");
|
||||
}
|
||||
|
||||
this.useDataNodePasswordForSentinel = useDataNodeAuthenticationForSentinel;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getUseDataNodeAuthenticationForSentinel()
|
||||
*/
|
||||
@Override
|
||||
public boolean getUseDataNodeAuthenticationForSentinel() {
|
||||
return this.useDataNodePasswordForSentinel;
|
||||
}
|
||||
|
||||
private RedisNode readHostAndPortFromString(String hostAndPort) {
|
||||
|
||||
String[] args = split(hostAndPort, ":");
|
||||
|
||||
notNull(args, "HostAndPort need to be seperated by ':'.");
|
||||
isTrue(args.length == 2, "Host and Port String needs to specified as host:port");
|
||||
Assert.notNull(args, "HostAndPort need to be seperated by ':'.");
|
||||
Assert.isTrue(args.length == 2, "Host and Port String needs to specified as host:port");
|
||||
return new RedisNode(args[0], Integer.valueOf(args[1]).intValue());
|
||||
}
|
||||
|
||||
@@ -261,8 +312,8 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
|
||||
*/
|
||||
private static Map<String, Object> asMap(String master, Set<String> sentinelHostAndPorts) {
|
||||
|
||||
hasText(master, "Master address must not be null or empty!");
|
||||
notNull(sentinelHostAndPorts, "SentinelHostAndPorts must not be null!");
|
||||
Assert.hasText(master, "Master address must not be null or empty!");
|
||||
Assert.notNull(sentinelHostAndPorts, "SentinelHostAndPorts must not be null!");
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(REDIS_SENTINEL_MASTER_CONFIG_PROPERTY, master);
|
||||
|
||||
@@ -1080,7 +1080,6 @@ public class LettuceConnectionFactory
|
||||
|
||||
applyToAll(redisUri, it -> {
|
||||
|
||||
getRedisPassword().toOptional().ifPresent(it::setPassword);
|
||||
clientConfiguration.getClientName().ifPresent(it::setClientName);
|
||||
|
||||
it.setSsl(clientConfiguration.isUseSsl());
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusComma
|
||||
import org.springframework.data.redis.connection.RedisListCommands.Position;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisNode.NodeType;
|
||||
import org.springframework.data.redis.connection.RedisPassword;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisServer;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
|
||||
@@ -198,7 +199,8 @@ abstract public class LettuceConverters extends Converters {
|
||||
};
|
||||
|
||||
SCORED_VALUE_TO_TUPLE = source -> source != null
|
||||
? new DefaultTuple(source.getValue(), Double.valueOf(source.getScore())) : null;
|
||||
? new DefaultTuple(source.getValue(), Double.valueOf(source.getScore()))
|
||||
: null;
|
||||
|
||||
BYTES_LIST_TO_TUPLE_LIST_CONVERTER = source -> {
|
||||
|
||||
@@ -297,7 +299,8 @@ abstract public class LettuceConverters extends Converters {
|
||||
};
|
||||
|
||||
GEO_COORDINATE_TO_POINT_CONVERTER = geoCoordinate -> geoCoordinate != null
|
||||
? new Point(geoCoordinate.getX().doubleValue(), geoCoordinate.getY().doubleValue()) : null;
|
||||
? new Point(geoCoordinate.getX().doubleValue(), geoCoordinate.getY().doubleValue())
|
||||
: null;
|
||||
GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER = new ListConverter<>(GEO_COORDINATE_TO_POINT_CONVERTER);
|
||||
|
||||
KEY_VALUE_UNWRAPPER = source -> source.getValueOrElse(null);
|
||||
@@ -637,15 +640,21 @@ abstract public class LettuceConverters extends Converters {
|
||||
Assert.notNull(sentinelConfiguration, "RedisSentinelConfiguration is required");
|
||||
|
||||
Set<RedisNode> sentinels = sentinelConfiguration.getSentinels();
|
||||
RedisURI.Builder builder = null;
|
||||
RedisURI.Builder builder = RedisURI.builder();
|
||||
for (RedisNode sentinel : sentinels) {
|
||||
|
||||
if (builder == null) {
|
||||
builder = RedisURI.Builder.sentinel(sentinel.getHost(), sentinel.getPort(),
|
||||
sentinelConfiguration.getMaster().getName());
|
||||
} else {
|
||||
builder.withSentinel(sentinel.getHost(), sentinel.getPort());
|
||||
RedisURI.Builder uri = RedisURI.Builder.sentinel(sentinel.getHost(), sentinel.getPort(),
|
||||
sentinelConfiguration.getMaster().getName());
|
||||
|
||||
if (sentinelConfiguration.getSentinelPassword().isPresent()) {
|
||||
uri.withPassword(sentinelConfiguration.getSentinelPassword().get());
|
||||
}
|
||||
builder.withSentinel(uri.build());
|
||||
}
|
||||
|
||||
RedisPassword password = sentinelConfiguration.getPassword();
|
||||
if (password.isPresent()) {
|
||||
builder.withPassword(password.get());
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
||||
Reference in New Issue
Block a user