DATAREDIS-574 - Introduce RedisPassword value object.
Encapsulate Redis passwords within a GC-friendly container that allows mapping and consumption in a functional style. Original Pull Request: #236
This commit is contained in:
committed by
Christoph Strobl
parent
a403a530d3
commit
3819ded01c
@@ -47,7 +47,7 @@ public class RedisClusterConfiguration {
|
||||
|
||||
private Set<RedisNode> clusterNodes;
|
||||
private Integer maxRedirects;
|
||||
private String password;
|
||||
private RedisPassword password = RedisPassword.none();
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisClusterConfiguration}.
|
||||
@@ -183,15 +183,18 @@ public class RedisClusterConfiguration {
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public String getPassword() {
|
||||
public RedisPassword getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* @param password must not be {@literal null}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
public void setPassword(RedisPassword password) {
|
||||
|
||||
Assert.notNull(password, "RedisPassword must not be null!");
|
||||
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.redis.connection;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object which may or may not contain a Redis password.
|
||||
* <p/>
|
||||
* If a password is present, {@code isPresent()} will return {@code true} and {@code get()} will return the value.
|
||||
* <p/>
|
||||
* The password is stored as character array.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@EqualsAndHashCode
|
||||
public class RedisPassword {
|
||||
|
||||
private static final RedisPassword NONE = new RedisPassword(new char[0]);
|
||||
|
||||
private final char[] thePassword;
|
||||
|
||||
/**
|
||||
* Create a {@link RedisPassword} from a {@link String}.
|
||||
*
|
||||
* @param passwordAsString the password as string.
|
||||
* @return the {@link RedisPassword} for {@code passwordAsString}.
|
||||
*/
|
||||
public static RedisPassword of(String passwordAsString) {
|
||||
|
||||
return Optional.ofNullable(passwordAsString) //
|
||||
.filter(it -> it.length() != 0) //
|
||||
.map(it -> new RedisPassword(it.toCharArray())) //
|
||||
.orElseGet(RedisPassword::none);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link RedisPassword} from a {@code char} array.
|
||||
*
|
||||
* @param passwordAsChars the password as string.
|
||||
* @return the {@link RedisPassword} for {@code passwordAsChars}.
|
||||
*/
|
||||
public static RedisPassword of(char[] passwordAsChars) {
|
||||
|
||||
return Optional.ofNullable(passwordAsChars) //
|
||||
.filter(it -> it.length != 0) //
|
||||
.map(it -> new RedisPassword(Arrays.copyOf(it, it.length))) //
|
||||
.orElseGet(RedisPassword::none);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an absent {@link RedisPassword}.
|
||||
*
|
||||
* @return the absent {@link RedisPassword}.
|
||||
*/
|
||||
public static RedisPassword none() {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if there is a password present, otherwise {@code false}.
|
||||
*
|
||||
* @return {@code true} if there is a password present, otherwise {@code false}
|
||||
*/
|
||||
public boolean isPresent() {
|
||||
return thePassword.length != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password value if present. Throws {@link NoSuchElementException} if the password is absent.
|
||||
*
|
||||
* @return the password.
|
||||
* @throws NoSuchElementException if the password is absent.
|
||||
*/
|
||||
public char[] get() throws NoSuchElementException {
|
||||
|
||||
if (isPresent()) {
|
||||
return Arrays.copyOf(thePassword, thePassword.length);
|
||||
}
|
||||
|
||||
throw new NoSuchElementException("No password present.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the password using a {@link Function} and return a {@link Optional} containing the mapped value.
|
||||
* <p/>
|
||||
* Absent passwords return a {@link Optional#empty()}.
|
||||
*
|
||||
* @param mapper must not be {@literal null}.
|
||||
* @return the mapped result.
|
||||
*/
|
||||
public <R> Optional<R> map(Function<char[], R> mapper) {
|
||||
|
||||
Assert.notNull(mapper, "Mapper function must not be null!");
|
||||
|
||||
if (isPresent()) {
|
||||
return Optional.ofNullable(mapper.apply(thePassword));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adopt the password to {@link Optional} containing the password value.
|
||||
* <p/>
|
||||
* Absent passwords return a {@link Optional#empty()}.
|
||||
*
|
||||
* @return the {@link Optional} containing the password value.
|
||||
*/
|
||||
public Optional<char[]> toOptional() {
|
||||
|
||||
if (isPresent()) {
|
||||
return Optional.ofNullable(get());
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[%s]", getClass().getSimpleName(), isPresent() ? "*****" : "<none>");
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import org.springframework.util.StringUtils;
|
||||
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using connecting
|
||||
* to <a href="http://redis.io/topics/sentinel">Redis Sentinel(s)</a>. Useful when setting up a high availability Redis
|
||||
* environment.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
@@ -48,7 +48,7 @@ public class RedisSentinelConfiguration {
|
||||
private NamedNode master;
|
||||
private Set<RedisNode> sentinels;
|
||||
private int database;
|
||||
private String password;
|
||||
private RedisPassword password = RedisPassword.none();
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisSentinelConfiguration}.
|
||||
@@ -59,12 +59,12 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Creates {@link RedisSentinelConfiguration} for given hostPort combinations.
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* sentinelHostAndPorts[0] = 127.0.0.1:23679 sentinelHostAndPorts[1] = 127.0.0.1:23680 ...
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
*
|
||||
* @param sentinelHostAndPorts must not be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@@ -74,14 +74,14 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Creates {@link RedisSentinelConfiguration} looking up values in given {@link PropertySource}.
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* spring.redis.sentinel.master=myMaster
|
||||
* spring.redis.sentinel.nodes=127.0.0.1:23679,127.0.0.1:23680,127.0.0.1:23681
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param propertySource must not be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@@ -103,7 +103,7 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Set {@literal Sentinels} to connect to.
|
||||
*
|
||||
*
|
||||
* @param sentinels must not be {@literal null}.
|
||||
*/
|
||||
public void setSentinels(Iterable<RedisNode> sentinels) {
|
||||
@@ -119,7 +119,7 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Returns an {@link Collections#unmodifiableSet(Set)} of {@literal Sentinels}.
|
||||
*
|
||||
*
|
||||
* @return {@link Set} of sentinels. Never {@literal null}.
|
||||
*/
|
||||
public Set<RedisNode> getSentinels() {
|
||||
@@ -128,7 +128,7 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Add sentinel.
|
||||
*
|
||||
*
|
||||
* @param sentinel must not be {@literal null}.
|
||||
*/
|
||||
public void addSentinel(RedisNode sentinel) {
|
||||
@@ -139,7 +139,7 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Set the master node via its name.
|
||||
*
|
||||
*
|
||||
* @param name must not be {@literal null}.
|
||||
*/
|
||||
public void setMaster(final String name) {
|
||||
@@ -156,7 +156,7 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Set the master.
|
||||
*
|
||||
*
|
||||
* @param master must not be {@literal null}.
|
||||
*/
|
||||
public void setMaster(NamedNode master) {
|
||||
@@ -167,7 +167,7 @@ public class RedisSentinelConfiguration {
|
||||
|
||||
/**
|
||||
* Get the {@literal Sentinel} master node.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public NamedNode getMaster() {
|
||||
@@ -246,15 +246,18 @@ public class RedisSentinelConfiguration {
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public String getPassword() {
|
||||
public RedisPassword getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* @param password must not be {@literal null}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
public void setPassword(RedisPassword password) {
|
||||
|
||||
Assert.notNull(password, "RedisPassword must not be null!");
|
||||
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class RedisStandaloneConfiguration {
|
||||
private String hostName = DEFAULT_HOST;
|
||||
private int port = DEFAULT_PORT;
|
||||
private int database;
|
||||
private String password;
|
||||
private RedisPassword password = RedisPassword.none();
|
||||
|
||||
/**
|
||||
* Create a new default {@link RedisStandaloneConfiguration}.
|
||||
@@ -114,14 +114,17 @@ public class RedisStandaloneConfiguration {
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getPassword() {
|
||||
public RedisPassword getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* @param password must not be {@literal null}.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
public void setPassword(RedisPassword password) {
|
||||
|
||||
Assert.notNull(password, "RedisPassword must not be null!");
|
||||
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,15 +50,7 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.data.redis.ExceptionTranslationStrategy;
|
||||
import org.springframework.data.redis.PassThroughExceptionTranslationStrategy;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.connection.ClusterCommandExecutor;
|
||||
import org.springframework.data.redis.connection.RedisClusterConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisClusterConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConnection;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.*;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -312,7 +304,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
|
||||
|
||||
Client client = jedis.getClient();
|
||||
|
||||
client.setPassword(getPassword());
|
||||
getRedisPassword().map(String::new).ifPresent(client::setPassword);
|
||||
client.setDb(getDatabase());
|
||||
|
||||
return jedis;
|
||||
@@ -343,9 +335,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
|
||||
clientConfiguration.getSslParameters().orElse(null), //
|
||||
clientConfiguration.getHostnameVerifier().orElse(null));
|
||||
|
||||
if (StringUtils.hasLength(getPassword())) {
|
||||
shardInfo.setPassword(getPassword());
|
||||
}
|
||||
getRedisPassword().map(String::new).ifPresent(shardInfo::setPassword);
|
||||
|
||||
int readTimeout = getReadTimeout();
|
||||
|
||||
@@ -558,6 +548,10 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
|
||||
* @return password for authentication.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return getRedisPassword().map(String::new).orElse(null);
|
||||
}
|
||||
|
||||
private RedisPassword getRedisPassword() {
|
||||
|
||||
if (isRedisSentinelAware()) {
|
||||
return sentinelConfig.getPassword();
|
||||
@@ -581,16 +575,16 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
|
||||
public void setPassword(String password) {
|
||||
|
||||
if (isRedisSentinelAware()) {
|
||||
sentinelConfig.setPassword(password);
|
||||
sentinelConfig.setPassword(RedisPassword.of(password));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRedisClusterAware()) {
|
||||
clusterConfig.setPassword(password);
|
||||
clusterConfig.setPassword(RedisPassword.of(password));
|
||||
return;
|
||||
}
|
||||
|
||||
standaloneConfig.setPassword(password);
|
||||
standaloneConfig.setPassword(RedisPassword.of(password));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,6 @@ import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.connection.*;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Connection factory creating <a href="http://github.com/mp911de/lettuce">Lettuce</a>-based connections.
|
||||
@@ -549,6 +548,10 @@ public class LettuceConnectionFactory
|
||||
* @return password for authentication.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return getRedisPassword().map(String::new).orElse(null);
|
||||
}
|
||||
|
||||
private RedisPassword getRedisPassword() {
|
||||
|
||||
if (isRedisSentinelAware()) {
|
||||
return sentinelConfiguration.getPassword();
|
||||
@@ -572,16 +575,16 @@ public class LettuceConnectionFactory
|
||||
public void setPassword(String password) {
|
||||
|
||||
if (isRedisSentinelAware()) {
|
||||
sentinelConfiguration.setPassword(password);
|
||||
sentinelConfiguration.setPassword(RedisPassword.of(password));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isClusterAware()) {
|
||||
clusterConfiguration.setPassword(password);
|
||||
clusterConfiguration.setPassword(RedisPassword.of(password));
|
||||
return;
|
||||
}
|
||||
|
||||
standaloneConfig.setPassword(password);
|
||||
standaloneConfig.setPassword(RedisPassword.of(password));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -786,9 +789,7 @@ public class LettuceConnectionFactory
|
||||
|
||||
RedisURI redisUri = LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration);
|
||||
|
||||
if (StringUtils.hasText(getPassword())) {
|
||||
redisUri.setPassword(getPassword());
|
||||
}
|
||||
getRedisPassword().toOptional().ifPresent(redisUri::setPassword);
|
||||
|
||||
return redisUri;
|
||||
}
|
||||
@@ -796,9 +797,8 @@ public class LettuceConnectionFactory
|
||||
private RedisURI createRedisURIAndApplySettings(String host, int port) {
|
||||
|
||||
RedisURI.Builder builder = RedisURI.Builder.redis(host, port);
|
||||
if (StringUtils.hasText(getPassword())) {
|
||||
builder.withPassword(getPassword());
|
||||
}
|
||||
|
||||
getRedisPassword().toOptional().ifPresent(builder::withPassword);
|
||||
|
||||
builder.withSsl(clientConfiguration.useSsl());
|
||||
builder.withVerifyPeer(clientConfiguration.isVerifyPeer());
|
||||
|
||||
Reference in New Issue
Block a user