Skip to content

Commit

Permalink
Polishing #1202
Browse files Browse the repository at this point in the history
Add author and since tags, tweak Javadoc.
Memoize auth(…) with username for reconnect and re-authentication.

Split tests into tests that require Redis 6 and those that do not require Redis 6 to guard these against older/newer Redis versions.

Original pull request: #1249
  • Loading branch information
mp911de committed Apr 1, 2020
1 parent 2e508bc commit c32a1b4
Show file tree
Hide file tree
Showing 24 changed files with 284 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
* @param <V> Value type.
* @author Will Glozer
* @author Mark Paluch
* @author Tugdual Grall
*/
@SuppressWarnings("unchecked")
public abstract class AbstractRedisAsyncCommands<K, V> implements RedisHashAsyncCommands<K, V>, RedisKeyAsyncCommands<K, V>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
* @param <V> Value type.
* @author Mark Paluch
* @author Nikolai Perevozchikov
* @author Tugdual Grall
* @since 4.0
*/
public abstract class AbstractRedisReactiveCommands<K, V> implements RedisHashReactiveCommands<K, V>,
Expand Down
24 changes: 23 additions & 1 deletion src/main/java/io/lettuce/core/ConnectionState.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package io.lettuce.core;

import java.util.List;

import io.lettuce.core.protocol.ProtocolVersion;

/**
Expand Down Expand Up @@ -95,7 +97,27 @@ void setHandshakeResponse(HandshakeResponse handshakeResponse) {
this.handshakeResponse = handshakeResponse;
}

void setUsername(String username) {
/**
* Sets username/password state based on the argument count from an {@code AUTH} command.
*
* @param args
*/
protected void setUserNamePassword(List<char[]> args) {

if (args.isEmpty()) {
return;
}

if (args.size() > 1) {
setUsername(new String(args.get(0)));
setPassword(args.get(1));
} else {
setUsername(null);
setPassword(args.get(0));
}
}

protected void setUsername(String username) {
this.username = username;
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/io/lettuce/core/RedisCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* @param <V>
* @author Mark Paluch
* @author Zhang Jessey
* @author Tugdual Grall
*/
@SuppressWarnings({ "unchecked", "varargs" })
class RedisCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/io/lettuce/core/RedisHandshake.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* connection state restoration. This class is part of the internal API.
*
* @author Mark Paluch
* @author Tugdual Grall
* @since 6.0
*/
class RedisHandshake implements ConnectionInitializer {
Expand Down Expand Up @@ -151,8 +152,9 @@ private CompletableFuture<Void> initializeResp3(Channel channel) {
* @return
*/
private CompletableFuture<?> initiateHandshakeResp2(Channel channel) {

if (connectionState.hasUsername()) {
return dispatch(channel, this.commandBuilder.auth(connectionState.getUsername() ,connectionState.getPassword()));
return dispatch(channel, this.commandBuilder.auth(connectionState.getUsername(), connectionState.getPassword()));
} else if (connectionState.hasPassword()) {
return dispatch(channel, this.commandBuilder.auth(connectionState.getPassword()));
} else if (this.pingOnConnect) {
Expand Down
19 changes: 13 additions & 6 deletions src/main/java/io/lettuce/core/RedisURI.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,23 @@
*
* <h3>URI syntax</h3>
*
* <b>Redis Standalone</b> <blockquote> <i>redis</i><b>{@code ://}</b>[<i>password@</i>]<i>host</i> [<b>{@code :} </b>
* <i>port</i>][<b>{@code /}</b><i>database</i>][<b>{@code ?}</b> [<i>timeout=timeout</i>[<i>d|h|m|s|ms|us|ns</i>]] [
* <i>&amp;database=database</i>] [<i>&amp;clientName=clientName</i>]] </blockquote>
* <b>Redis Standalone</b> <blockquote> <i>redis</i><b>{@code ://}</b>[[<i>username</i>{@code :}]<i>password@</i>]<i>host</i>
* [<b>{@code :} </b> <i>port</i>][<b>{@code /}</b><i>database</i>][<b>{@code ?}</b>
* [<i>timeout=timeout</i>[<i>d|h|m|s|ms|us|ns</i>]] [ <i>&amp;database=database</i>] [<i>&amp;clientName=clientName</i>]]
* </blockquote>
*
* <b>Redis Standalone (SSL)</b> <blockquote> <i>rediss</i><b>{@code ://}</b>[<i>password@</i>]<i>host</i> [<b>{@code :} </b>
* <b>Redis Standalone (SSL)</b> <blockquote>
* <i>rediss</i><b>{@code ://}</b>[[<i>username</i>{@code :}]<i>password@</i>]<i>host</i> [<b>{@code :} </b>
* <i>port</i>][<b>{@code /}</b><i>database</i>][<b>{@code ?}</b> [<i>timeout=timeout</i>[<i>d|h|m|s|ms|us|ns</i>]] [
* <i>&amp;database=database</i>] [<i>&amp;clientName=clientName</i>]] </blockquote>
*
* Redis Standalone (Unix Domain Sockets)</b> <blockquote> <i>redis-socket</i><b>{@code ://} </b>[<i>password@</i>]<i>path</i>[
* Redis Standalone (Unix Domain Sockets)</b> <blockquote> <i>redis-socket</i><b>{@code ://}
* </b>[[<i>username</i>{@code :}]<i>password@</i>]<i>path</i>[
* <b>{@code ?}</b>[<i>timeout=timeout</i>[<i>d|h|m|s|ms|us|ns</i>]][<i>&amp;database=database</i>]
* [<i>&amp;clientName=clientName</i>]] </blockquote>
*
* <b>Redis Sentinel</b> <blockquote> <i>redis-sentinel</i><b>{@code ://}</b>[<i>password@</i>]<i>host1</i> [<b>{@code :} </b>
* <b>Redis Sentinel</b> <blockquote>
* <i>redis-sentinel</i><b>{@code ://}</b>[[<i>username</i>{@code :}]<i>password@</i>]<i>host1</i> [<b>{@code :} </b>
* <i>port1</i>][, <i>host2</i> [<b>{@code :}</b><i>port2</i>]][, <i>hostN</i> [<b>{@code :}</b><i>portN</i>]][<b>{@code /} </b>
* <i>database</i>][<b>{@code ?} </b>[<i>timeout=timeout</i>[<i>d|h|m|s|ms|us|ns</i>]] [
* <i>&amp;sentinelMasterId=sentinelMasterId</i>] [<i>&amp;database=database</i>] [<i>&amp;clientName=clientName</i>]]
Expand All @@ -86,6 +90,9 @@
* Note: When using Redis Sentinel, the password from the URI applies to the data nodes only. Sentinel authentication must be
* configured for each {@link #getSentinels() sentinel node}.
* </p>
* <p>
* Note:Usernames are supported as of Redis 6.
* </p>
*
* <p>
* <b>Schemes</b>
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/io/lettuce/core/StatefulRedisConnectionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
Expand Down Expand Up @@ -157,16 +158,14 @@ protected <T> RedisCommand<K, V, T> preProcessCommand(RedisCommand<K, V, T> comm
local = attachOnComplete(local, status -> {
if ("OK".equals(status)) {

char[] password = CommandArgsAccessor.getFirstCharArray(command.getArgs());
List<char[]> args = CommandArgsAccessor.getCharArrayArguments(command.getArgs());

if (password != null) {
state.setPassword(password);
if (!args.isEmpty()) {
state.setUserNamePassword(args);
} else {

String stringPassword = CommandArgsAccessor.getFirstString(command.getArgs());
if (stringPassword != null) {
state.setPassword(stringPassword.toCharArray());
}
List<String> strings = CommandArgsAccessor.getStringArguments(command.getArgs());
state.setUserNamePassword(strings.stream().map(String::toCharArray).collect(Collectors.toList()));
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ public interface RedisAsyncCommands<K, V> extends BaseRedisAsyncCommands<K, V>,
RedisFuture<String> auth(CharSequence password);

/**
* Authenticate to the server.
* Authenticate to the server with username and password. Requires Redis 6 or newer.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
* @since 6.0
*/
RedisFuture<String> auth(String username, CharSequence password);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ public interface RedisReactiveCommands<K, V> extends BaseRedisReactiveCommands<K
Mono<String> auth(CharSequence password);

/**
* Authenticate to the server.
* Authenticate to the server with username and password. Requires Redis 6 or newer.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
* @since 6.0
*/
Mono<String> auth(String username, CharSequence password);

Expand Down
11 changes: 6 additions & 5 deletions src/main/java/io/lettuce/core/api/sync/RedisCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,22 @@ public interface RedisCommands<K, V> extends BaseRedisCommands<K, V>, RedisClust
RedisStreamCommands<K, V>, RedisStringCommands<K, V>, RedisTransactionalCommands<K, V> {

/**
* Authenticate to the server with username and password.
* Authenticate to the server.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
*/
String auth(String username, CharSequence password);
String auth(CharSequence password);

/**
* Authenticate to the server.
* Authenticate to the server with username and password. Requires Redis 6 or newer.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
* @since 6.0
*/
String auth(CharSequence password);
String auth(String username, CharSequence password);

/**
* Change the selected database for the current Commands.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import io.lettuce.core.*;
import io.lettuce.core.api.StatefulRedisConnection;
Expand Down Expand Up @@ -195,16 +196,15 @@ private <T> RedisCommand<K, V, T> preProcessCommand(RedisCommand<K, V, T> comman
if (local.getType().name().equals(AUTH.name())) {
local = attachOnComplete(local, status -> {
if (status.equals("OK")) {
char[] password = CommandArgsAccessor.getFirstCharArray(command.getArgs());
List<char[]> args = CommandArgsAccessor.getCharArrayArguments(command.getArgs());

if (password != null) {
this.connectionState.setPassword(password);
if (!args.isEmpty()) {
this.connectionState.setUserNamePassword(args);
} else {

String stringPassword = CommandArgsAccessor.getFirstString(command.getArgs());
if (stringPassword != null) {
this.connectionState.setPassword(stringPassword.toCharArray());
}
List<String> stringArgs = CommandArgsAccessor.getStringArguments(command.getArgs());
this.connectionState
.setUserNamePassword(stringArgs.stream().map(String::toCharArray).collect(Collectors.toList()));
}
}
});
Expand Down Expand Up @@ -264,8 +264,8 @@ ConnectionState getConnectionState() {
static class ClusterConnectionState extends ConnectionState {

@Override
protected void setPassword(char[] password) {
super.setPassword(password);
protected void setUserNamePassword(List<char[]> args) {
super.setUserNamePassword(args);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ public interface RedisClusterAsyncCommands<K, V> extends BaseRedisAsyncCommands<
RedisFuture<String> auth(CharSequence password);

/**
* Authenticate to the server.
* Authenticate to the server with username and password. Requires Redis 6 or newer.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
* @since 6.0
*/
RedisFuture<String> auth(String username, CharSequence password);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ public interface RedisClusterReactiveCommands<K, V> extends BaseRedisReactiveCom
Mono<String> auth(CharSequence password);

/**
* Authenticate to the server.
* Authenticate to the server with username and password. Requires Redis 6 or newer.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
* @since 6.0
*/
Mono<String> auth(String username, CharSequence password);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ public interface RedisClusterCommands<K, V> extends BaseRedisCommands<K, V>, Red
String auth(CharSequence password);

/**
* Authenticate to the server.
* Authenticate to the server with username and password. Requires Redis 6 or newer.
*
* @param username the username
* @param password the password
* @return String simple-string-reply
* @since 6.0
*/
String auth(String username, CharSequence password);

Expand Down
50 changes: 49 additions & 1 deletion src/main/java/io/lettuce/core/protocol/CommandArgsAccessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package io.lettuce.core.protocol;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import io.lettuce.core.protocol.CommandArgs.CharArrayArgument;
import io.lettuce.core.protocol.CommandArgs.SingularArgument;
Expand Down Expand Up @@ -69,7 +71,7 @@ public static <K, V> String getFirstString(CommandArgs<K, V> commandArgs) {
}

/**
* Get the first {@link char}-array argument.
* Get the first {@code char[]}-array argument.
*
* @param commandArgs must not be null.
* @return the first {@link String} argument or {@literal null}.
Expand All @@ -87,6 +89,52 @@ public static <K, V> char[] getFirstCharArray(CommandArgs<K, V> commandArgs) {
return null;
}

/**
* Get the all {@link String} arguments.
*
* @param commandArgs must not be null.
* @return the first {@link String} argument or {@literal null}.
* @since 6.0
*/
public static <K, V> List<String> getStringArguments(CommandArgs<K, V> commandArgs) {

List<String> args = new ArrayList<>();

for (SingularArgument singularArgument : commandArgs.singularArguments) {

if (singularArgument instanceof StringArgument) {
args.add(((StringArgument) singularArgument).val);
}
}

return args;
}

/**
* Get the all {@code char[]} arguments.
*
* @param commandArgs must not be null.
* @return the first {@link String} argument or {@literal null}.
* @since 6.0
*/
public static <K, V> List<char[]> getCharArrayArguments(CommandArgs<K, V> commandArgs) {

List<char[]> args = new ArrayList<>();

for (SingularArgument singularArgument : commandArgs.singularArguments) {

if (singularArgument instanceof CharArrayArgument) {
args.add(((CharArrayArgument) singularArgument).val);
}

if (singularArgument instanceof StringArgument) {
args.add(((StringArgument) singularArgument).val.toCharArray());
}
}

return args;
}

/**
* Get the first {@link Long integer} argument.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import io.lettuce.test.condition.EnabledOnCommand;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import io.lettuce.core.api.StatefulRedisConnection;
Expand Down Expand Up @@ -131,6 +132,7 @@ void testHitRequestQueueLimitReconnectWithAuthCommand() {
}

@Test
@EnabledOnCommand("ACL")
void testHitRequestQueueLimitReconnectWithAuthUsernamePasswordCommand() {

WithPassword.run(client, () -> {
Expand Down
Loading

0 comments on commit c32a1b4

Please sign in to comment.