From f558dbb1f28d4cf972af4be3de92ec2cd1fd9cc0 Mon Sep 17 00:00:00 2001 From: "aleksandar.todorov" Date: Thu, 9 Jul 2026 11:57:13 +0300 Subject: [PATCH 1/2] Make clean transition from reactive to async credentials provider --- .../TokenBasedRedisCredentialsProvider.java | 11 ++--- .../core/RedisAuthenticationHandler.java | 10 ++--- .../core/RedisCredentialsProvider.java | 26 ++++-------- .../java/io/lettuce/core/RedisHandshake.java | 6 ++- src/main/java/io/lettuce/core/RedisURI.java | 2 +- .../core/StaticCredentialsProvider.java | 2 +- .../java/io/lettuce/core/Subscription.java | 28 +++++++++++++ ...faultAzureCredentialsIntegrationTests.java | 3 +- .../authx/EntraIdIntegrationTests.java | 5 +-- ...okenBasedRedisCredentialsProviderTest.java | 22 +++++----- .../ConnectionCommandIntegrationTests.java | 4 +- .../MyStreamingRedisCredentialsProvider.java | 4 +- .../lettuce/core/RedisHandshakeUnitTests.java | 2 +- .../core/RedisURIBuilderUnitTests.java | 42 +++++++++++-------- .../io/lettuce/core/RedisURIUnitTests.java | 10 ++--- .../cluster/RedisClusterURIUtilUnitTests.java | 6 +-- 16 files changed, 104 insertions(+), 79 deletions(-) create mode 100644 src/main/java/io/lettuce/core/Subscription.java diff --git a/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java b/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java index 014dd85d43..5c2043dab4 100644 --- a/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java +++ b/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java @@ -8,6 +8,7 @@ import io.lettuce.core.RedisCredentials; import io.lettuce.core.RedisCredentialsProvider; +import io.lettuce.core.Subscription; import io.lettuce.core.internal.LettuceAssert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,7 +53,7 @@ public class TokenBasedRedisCredentialsProvider implements RedisCredentialsProvi private static final Logger log = LoggerFactory.getLogger(TokenBasedRedisCredentialsProvider.class); - private static class SimpleSubscription implements CredentialsSubscription { + private static class SimpleSubscription implements Subscription { private final TokenBasedRedisCredentialsProvider provider; @@ -205,7 +206,7 @@ private static void dispatchOnError(SimpleSubscription subscription, Throwable t * @return a {@link CompletionStage} that completes with the latest Redis credentials */ @Override - public CompletionStage resolveCredentials() { + public CompletionStage resolveCredentialsAsync() { CompletableFuture result = new CompletableFuture<>(); credentialsFutureRef.get().whenComplete((creds, throwable) -> { if (throwable != null) { @@ -218,7 +219,7 @@ public CompletionStage resolveCredentials() { } @Override - public CredentialsSubscription subscribeToCredentials(Consumer onNext, Consumer onError) { + public Subscription subscribeToCredentials(Consumer onNext, Consumer onError) { if (isClosed) { throw new IllegalStateException("Credentials provider closed"); } @@ -280,7 +281,7 @@ public void close() { *
    *
  • Subscriber {@code onNext}/{@code onError} callbacks for live token renewals run on the {@link TokenManager}'s renewal * thread. A slow or blocking subscriber can delay or miss subsequent renewals.
  • - *
  • Continuations chained off {@link #resolveCredentials()} run on the renewal thread when the initial future + *
  • Continuations chained off {@link #resolveCredentialsAsync()} run on the renewal thread when the initial future * completes.
  • *
  • Replay deliveries to a newly subscribing consumer run on the subscribing thread.
  • *
@@ -323,7 +324,7 @@ public static TokenBasedRedisCredentialsProvider create(TokenAuthConfig tokenAut *
    *
  • Subscriber {@code onNext}/{@code onError} callbacks for live token renewals run on the {@link TokenManager}'s renewal * thread. A slow or blocking subscriber can delay or miss subsequent renewals.
  • - *
  • Continuations chained off {@link #resolveCredentials()} run on the renewal thread when the initial future + *
  • Continuations chained off {@link #resolveCredentialsAsync()} run on the renewal thread when the initial future * completes.
  • *
  • Replay deliveries to a newly subscribing consumer run on the subscribing thread.
  • *
diff --git a/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java b/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java index d0e3c47da6..5fe9dac919 100644 --- a/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java +++ b/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java @@ -6,7 +6,6 @@ */ package io.lettuce.core; -import io.lettuce.core.RedisCredentialsProvider.CredentialsSubscription; import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.codec.RedisCodec; import io.lettuce.core.event.connection.ReauthenticationEvent; @@ -48,7 +47,7 @@ public class RedisAuthenticationHandler { private final RedisCredentialsProvider credentialsProvider; - private final AtomicReference credentialsSubscription = new AtomicReference<>(); + private final AtomicReference credentialsSubscription = new AtomicReference<>(); private final Boolean isPubSubConnection; @@ -128,10 +127,9 @@ public void subscribe() { return; } - CredentialsSubscription credentialsSub = credentialsProvider.subscribeToCredentials(this::reauthenticate, - this::onError); + Subscription credentialsSub = credentialsProvider.subscribeToCredentials(this::reauthenticate, this::onError); - CredentialsSubscription oldSub = credentialsSubscription.getAndSet(credentialsSub); + Subscription oldSub = credentialsSubscription.getAndSet(credentialsSub); if (oldSub != null) { try { oldSub.close(); @@ -145,7 +143,7 @@ public void subscribe() { * Unsubscribes from the current credentials stream. */ public void unsubscribe() { - CredentialsSubscription sub = credentialsSubscription.getAndSet(null); + Subscription sub = credentialsSubscription.getAndSet(null); if (sub != null) { try { sub.close(); diff --git a/src/main/java/io/lettuce/core/RedisCredentialsProvider.java b/src/main/java/io/lettuce/core/RedisCredentialsProvider.java index 86dc509b96..b75314f3d9 100644 --- a/src/main/java/io/lettuce/core/RedisCredentialsProvider.java +++ b/src/main/java/io/lettuce/core/RedisCredentialsProvider.java @@ -1,6 +1,5 @@ package io.lettuce.core; -import java.io.Closeable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.Consumer; @@ -22,26 +21,17 @@ @FunctionalInterface public interface RedisCredentialsProvider { - /** - * Handle to a subscription created by {@link #subscribeToCredentials(Consumer, Consumer)}. Closing the subscription stops - * the provider from delivering further credential updates to the registered consumers. - */ - interface CredentialsSubscription extends Closeable { - - @Override - void close(); - - } - /** * Returns {@link RedisCredentials} that can be used to authorize a Redis connection. Each implementation of * {@code RedisCredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation * might load credentials from an existing key management system, or load new credentials when credentials are rotated. If - * an error occurs during the loading of credentials or credentials could not be found, a runtime exception will be raised. + * an error occurs during the loading of credentials or credentials could not be found, the returned {@link CompletionStage} + * completes exceptionally. * - * @return a {@link CompletionStage} emitting {@link RedisCredentials} that can be used to authorize a Redis connection. + * @return a {@link CompletionStage} that completes with the {@link RedisCredentials} used to authorize a Redis connection. + * @since 7.7 */ - CompletionStage resolveCredentials(); + CompletionStage resolveCredentialsAsync(); /** * Creates a new {@link RedisCredentialsProvider} from a given {@link Supplier}. @@ -101,10 +91,10 @@ default boolean supportsStreaming() { * * @param onNext consumer invoked with each new {@link RedisCredentials} value, must not be {@code null}. * @param onError consumer invoked with errors observed while producing credentials, must not be {@code null}. - * @return a {@link CredentialsSubscription} that can be used to stop receiving updates. + * @return a {@link Subscription} that can be used to stop receiving updates. * @throws UnsupportedOperationException if the provider does not support streaming credentials. */ - default CredentialsSubscription subscribeToCredentials(Consumer onNext, Consumer onError) { + default Subscription subscribeToCredentials(Consumer onNext, Consumer onError) { throw new UnsupportedOperationException("Streaming credentials are not supported by this provider."); } @@ -116,7 +106,7 @@ default CredentialsSubscription subscribeToCredentials(Consumer resolveCredentials() { + default CompletionStage resolveCredentialsAsync() { try { RedisCredentials credentials = resolveCredentialsNow(); if (credentials == null) { diff --git a/src/main/java/io/lettuce/core/RedisHandshake.java b/src/main/java/io/lettuce/core/RedisHandshake.java index bd221e8542..89e6cd4dc7 100644 --- a/src/main/java/io/lettuce/core/RedisHandshake.java +++ b/src/main/java/io/lettuce/core/RedisHandshake.java @@ -210,7 +210,8 @@ private CompletableFuture initiateHandshakeResp2(Channel channel, RedisCreden ((RedisCredentialsProvider.ImmediateRedisCredentialsProvider) credentialsProvider).resolveCredentialsNow()); } - CompletableFuture credentialsFuture = credentialsProvider.resolveCredentials().toCompletableFuture(); + CompletableFuture credentialsFuture = credentialsProvider.resolveCredentialsAsync() + .toCompletableFuture(); return credentialsFuture.thenComposeAsync(credentials -> dispatchAuthOrPing(channel, credentials)); } @@ -243,7 +244,8 @@ private CompletionStage> initiateHandshakeResp3(Channel chan ((RedisCredentialsProvider.ImmediateRedisCredentialsProvider) credentialsProvider).resolveCredentialsNow()); } - CompletableFuture credentialsFuture = credentialsProvider.resolveCredentials().toCompletableFuture(); + CompletableFuture credentialsFuture = credentialsProvider.resolveCredentialsAsync() + .toCompletableFuture(); return credentialsFuture.thenComposeAsync(credentials -> dispatchHello(channel, credentials)); } diff --git a/src/main/java/io/lettuce/core/RedisURI.java b/src/main/java/io/lettuce/core/RedisURI.java index 0d52688aaf..3e5e412d0f 100644 --- a/src/main/java/io/lettuce/core/RedisURI.java +++ b/src/main/java/io/lettuce/core/RedisURI.java @@ -976,7 +976,7 @@ private String getAuthority(String scheme, boolean maskCredentials) { // would get asterix for each character of the password. RedisCredentials creds; try { - creds = credentialsProvider.resolveCredentials().toCompletableFuture().join(); + creds = credentialsProvider.resolveCredentialsAsync().toCompletableFuture().join(); } catch (Exception e) { throw Exceptions.bubble(e); } diff --git a/src/main/java/io/lettuce/core/StaticCredentialsProvider.java b/src/main/java/io/lettuce/core/StaticCredentialsProvider.java index 507e1e0d4a..931eab2f36 100644 --- a/src/main/java/io/lettuce/core/StaticCredentialsProvider.java +++ b/src/main/java/io/lettuce/core/StaticCredentialsProvider.java @@ -44,7 +44,7 @@ public StaticCredentialsProvider(RedisCredentials credentials) { } @Override - public CompletionStage resolveCredentials() { + public CompletionStage resolveCredentialsAsync() { return future; } diff --git a/src/main/java/io/lettuce/core/Subscription.java b/src/main/java/io/lettuce/core/Subscription.java new file mode 100644 index 0000000000..6f84990d93 --- /dev/null +++ b/src/main/java/io/lettuce/core/Subscription.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026-Present, Redis Ltd. All rights reserved. + * SPDX-License-Identifier: MIT + */ +package io.lettuce.core; + +import java.io.Closeable; + +/** + * Handle to a callback subscription on a Lettuce streaming SPI, such as + * {@link io.lettuce.core.RedisCredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)} + * or {@link io.lettuce.core.event.EventBus}. Closing the subscription stops delivery of further values to the registered + * callback. + *

+ * This is not related to {@code org.reactivestreams.Subscription} or to Redis Pub/Sub channel subscriptions. + * + * @author Aleksandar Todorov + * @since 7.7 + */ +public interface Subscription extends Closeable { + + /** + * Stop delivering to the registered callback. Idempotent; calling it more than once has no further effect and never throws. + */ + @Override + void close(); + +} diff --git a/src/test/java/io/lettuce/authx/DefaultAzureCredentialsIntegrationTests.java b/src/test/java/io/lettuce/authx/DefaultAzureCredentialsIntegrationTests.java index 2f0624ede5..c8083d4316 100644 --- a/src/test/java/io/lettuce/authx/DefaultAzureCredentialsIntegrationTests.java +++ b/src/test/java/io/lettuce/authx/DefaultAzureCredentialsIntegrationTests.java @@ -79,7 +79,8 @@ public void cleanUp() { @Test public void azureTokenAuthWithDefaultAzureCredentials() throws ExecutionException, InterruptedException, TimeoutException { - RedisCredentials credentials = credentialsProvider.resolveCredentials().toCompletableFuture().get(5, TimeUnit.SECONDS); + RedisCredentials credentials = credentialsProvider.resolveCredentialsAsync().toCompletableFuture().get(5, + TimeUnit.SECONDS); assertThat(credentials).isNotNull(); String key = UUID.randomUUID().toString(); diff --git a/src/test/java/io/lettuce/authx/EntraIdIntegrationTests.java b/src/test/java/io/lettuce/authx/EntraIdIntegrationTests.java index 5064990cdb..3e552a379b 100644 --- a/src/test/java/io/lettuce/authx/EntraIdIntegrationTests.java +++ b/src/test/java/io/lettuce/authx/EntraIdIntegrationTests.java @@ -1,7 +1,6 @@ package io.lettuce.authx; import io.lettuce.core.*; -import io.lettuce.core.RedisCredentialsProvider.CredentialsSubscription; import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.reactive.RedisReactiveCommands; @@ -116,7 +115,7 @@ public void renewalDuringOperationsTest() throws InterruptedException { commandThread.start(); CountDownLatch latch = new CountDownLatch(10); // Wait for at least 10 token renewalss - CredentialsSubscription subscription = credentialsProvider.subscribeToCredentials(cred -> latch.countDown(), t -> { + Subscription subscription = credentialsProvider.subscribeToCredentials(cred -> latch.countDown(), t -> { }); try { assertThat(latch.await(2, TimeUnit.SECONDS)).isTrue(); // Wait to reach 10 renewals @@ -150,7 +149,7 @@ public void renewalDuringPubSubOperationsTest() throws InterruptedException { pubsubThread.start(); CountDownLatch latch = new CountDownLatch(10); - CredentialsSubscription subscription = credentialsProvider.subscribeToCredentials(cred -> latch.countDown(), t -> { + Subscription subscription = credentialsProvider.subscribeToCredentials(cred -> latch.countDown(), t -> { }); try { assertThat(latch.await(2, TimeUnit.SECONDS)).isTrue(); // Wait for at least 10 token renewals diff --git a/src/test/java/io/lettuce/authx/TokenBasedRedisCredentialsProviderTest.java b/src/test/java/io/lettuce/authx/TokenBasedRedisCredentialsProviderTest.java index a71e1d3e7d..ac5eb66161 100644 --- a/src/test/java/io/lettuce/authx/TokenBasedRedisCredentialsProviderTest.java +++ b/src/test/java/io/lettuce/authx/TokenBasedRedisCredentialsProviderTest.java @@ -2,7 +2,7 @@ import io.lettuce.TestTags; import io.lettuce.core.RedisCredentials; -import io.lettuce.core.RedisCredentialsProvider.CredentialsSubscription; +import io.lettuce.core.Subscription; import io.lettuce.core.TestTokenManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -44,7 +44,7 @@ public void setUp() { public void shouldReturnPreviouslyEmittedTokenWhenResolved() { tokenManager.emitToken(testToken("test-user", "token-1")); - Mono credentials = Mono.fromCompletionStage(credentialsProvider.resolveCredentials()); + Mono credentials = Mono.fromCompletionStage(credentialsProvider.resolveCredentialsAsync()); StepVerifier.create(credentials).assertNext(actual -> { assertThat(actual.getUsername()).isEqualTo("test-user"); @@ -57,7 +57,7 @@ public void shouldReturnLatestEmittedTokenWhenResolved() { tokenManager.emitToken(testToken("test-user", "token-2")); tokenManager.emitToken(testToken("test-user", "token-3")); // Latest token - Mono credentials = Mono.fromCompletionStage(credentialsProvider.resolveCredentials()); + Mono credentials = Mono.fromCompletionStage(credentialsProvider.resolveCredentialsAsync()); StepVerifier.create(credentials).assertNext(actual -> { assertThat(actual.getUsername()).isEqualTo("test-user"); @@ -71,7 +71,7 @@ public void shouldReturnTokenEmittedBeforeSubscription() { tokenManager.emitToken(testToken("test-user", "token-1")); // Test resolveCredentials - Mono credentials1 = Mono.fromCompletionStage(credentialsProvider.resolveCredentials()); + Mono credentials1 = Mono.fromCompletionStage(credentialsProvider.resolveCredentialsAsync()); StepVerifier.create(credentials1).assertNext(actual -> { assertThat(actual.getUsername()).isEqualTo("test-user"); @@ -81,7 +81,7 @@ public void shouldReturnTokenEmittedBeforeSubscription() { // Emit second token and subscribe another tokenManager.emitToken(testToken("test-user", "token-2")); tokenManager.emitToken(testToken("test-user", "token-3")); - Mono credentials2 = Mono.fromCompletionStage(credentialsProvider.resolveCredentials()); + Mono credentials2 = Mono.fromCompletionStage(credentialsProvider.resolveCredentialsAsync()); StepVerifier.create(credentials2).assertNext(actual -> { assertThat(actual.getUsername()).isEqualTo("test-user"); assertThat(new String(actual.getPassword())).isEqualTo("token-3"); @@ -90,7 +90,7 @@ public void shouldReturnTokenEmittedBeforeSubscription() { @Test public void shouldWaitForAndReturnTokenWhenEmittedLater() { - Mono result = Mono.fromCompletionStage(credentialsProvider.resolveCredentials()); + Mono result = Mono.fromCompletionStage(credentialsProvider.resolveCredentialsAsync()); tokenManager.emitTokenWithDelay(testToken("test-user", "delayed-token"), 100); // Emit token after 100ms StepVerifier.create(result) @@ -104,12 +104,12 @@ public void shouldStopDeliveringToSubscribersOnClose() throws InterruptedExcepti List received2 = new CopyOnWriteArrayList<>(); CountDownLatch firstTokenLatch = new CountDownLatch(2); - CredentialsSubscription sub1 = credentialsProvider.subscribeToCredentials(c -> { + Subscription sub1 = credentialsProvider.subscribeToCredentials(c -> { received1.add(c); firstTokenLatch.countDown(); }, t -> { }); - CredentialsSubscription sub2 = credentialsProvider.subscribeToCredentials(c -> { + Subscription sub2 = credentialsProvider.subscribeToCredentials(c -> { received2.add(c); firstTokenLatch.countDown(); }, t -> { @@ -140,7 +140,7 @@ public void shouldPropagateMultipleTokensOnStream() throws InterruptedException List received = new CopyOnWriteArrayList<>(); CountDownLatch latch = new CountDownLatch(2); - CredentialsSubscription sub = credentialsProvider.subscribeToCredentials(c -> { + Subscription sub = credentialsProvider.subscribeToCredentials(c -> { received.add(c); latch.countDown(); }, t -> { @@ -166,7 +166,7 @@ public void shouldReplayLatestTokenToNewSubscriber() throws InterruptedException AtomicReference received = new AtomicReference<>(); CountDownLatch latch = new CountDownLatch(1); - CredentialsSubscription sub = credentialsProvider.subscribeToCredentials(c -> { + Subscription sub = credentialsProvider.subscribeToCredentials(c -> { received.set(c); latch.countDown(); }, t -> { @@ -187,7 +187,7 @@ public void shouldPropagateTokenRequestErrorsToSubscribers() throws InterruptedE CountDownLatch tokensLatch = new CountDownLatch(2); CountDownLatch errorLatch = new CountDownLatch(1); - CredentialsSubscription sub = credentialsProvider.subscribeToCredentials(c -> { + Subscription sub = credentialsProvider.subscribeToCredentials(c -> { received.add(c); tokensLatch.countDown(); }, t -> { diff --git a/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java b/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java index c1c34cfe58..1146bd7678 100644 --- a/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java @@ -285,8 +285,8 @@ void authInvalidPassword() { } catch (RedisException e) { assertThat(e.getMessage()).startsWith("ERR").contains("AUTH"); StatefulRedisConnectionImpl connectionImpl = (StatefulRedisConnectionImpl) connection; - assertThat(connectionImpl.getConnectionState().getCredentialsProvider().resolveCredentials().toCompletableFuture() - .join().getPassword()).isNull(); + assertThat(connectionImpl.getConnectionState().getCredentialsProvider().resolveCredentialsAsync() + .toCompletableFuture().join().getPassword()).isNull(); } finally { connection.close(); } diff --git a/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java b/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java index 38dd1cc915..48988e00a8 100644 --- a/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java +++ b/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java @@ -30,12 +30,12 @@ public boolean supportsStreaming() { } @Override - public CompletionStage resolveCredentials() { + public CompletionStage resolveCredentialsAsync() { return credentialsFutureRef.get(); } @Override - public CredentialsSubscription subscribeToCredentials(Consumer onNext, Consumer onError) { + public Subscription subscribeToCredentials(Consumer onNext, Consumer onError) { LettuceAssert.notNull(onNext, "onNext consumer must not be null"); LettuceAssert.notNull(onError, "onError consumer must not be null"); Listener listener = new Listener(onNext, onError); diff --git a/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java b/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java index 926ffb1b4e..dbd128a852 100644 --- a/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java @@ -359,7 +359,7 @@ static class DelayedRedisCredentialsProvider implements RedisCredentialsProvider private final Sinks.One credentialsSink = Sinks.one(); @Override - public CompletionStage resolveCredentials() { + public CompletionStage resolveCredentialsAsync() { return credentialsSink.asMono().toFuture(); } diff --git a/src/test/java/io/lettuce/core/RedisURIBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisURIBuilderUnitTests.java index 1c2ee31b65..34aabc07cb 100644 --- a/src/test/java/io/lettuce/core/RedisURIBuilderUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisURIBuilderUnitTests.java @@ -171,7 +171,7 @@ void redisFromUrl() { assertThat(result.getSentinels()).isEmpty(); assertThat(result.getHost()).isEqualTo("localhost"); assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); - StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -183,14 +183,14 @@ void redisFromUrl() { @Test void redisFromUrlNoPassword() { RedisURI redisURI = RedisURI.create("redis://localhost:1234/5"); - StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isNull(); }).verifyComplete(); redisURI = RedisURI.create("redis://h:@localhost.com:14589"); - StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isNull(); @@ -201,7 +201,7 @@ void redisFromUrlNoPassword() { void redisFromUrlPassword() { RedisURI redisURI = RedisURI.create("redis://h:password@localhost.com:14589"); - StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isEqualTo("h"); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -236,7 +236,7 @@ void redisSslFromUrl() { assertThat(result.getSentinels()).isEmpty(); assertThat(result.getHost()).isEqualTo("localhost"); assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); - StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -254,7 +254,7 @@ void redisSentinelFromUrl() { assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); assertThat(result.getSentinelMasterId()).isEqualTo("master"); assertThat(result.toString()).contains("master"); - StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -266,7 +266,7 @@ void redisSentinelFromUrl() { assertThat(result.getHost()).isNull(); assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); assertThat(result.getSentinelMasterId()).isEqualTo("master"); - StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -291,7 +291,7 @@ void withAuthenticatedSentinel() { RedisURI result = RedisURI.Builder.sentinel("host", 1234, "master", "foo").build(); RedisURI sentinel = result.getSentinels().get(0); - StepVerifier.create(Mono.fromCompletionStage(sentinel.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(sentinel.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("foo".toCharArray()); @@ -309,7 +309,7 @@ void withTlsSentinel() { assertThat(sentinel.isStartTls()).isTrue(); assertThat(sentinel.isVerifyPeer()).isFalse(); - StepVerifier.create(Mono.fromCompletionStage(sentinel.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(sentinel.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("foo".toCharArray()); @@ -324,14 +324,16 @@ void withAuthenticatedSentinelUri() { RedisURI result = RedisURI.Builder.sentinel("host", 1234, "master").withSentinel(sentinel).build(); StepVerifier - .create(Mono.fromCompletionStage(result.getSentinels().get(0).getCredentialsProvider().resolveCredentials())) + .create(Mono + .fromCompletionStage(result.getSentinels().get(0).getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isNull(); }).verifyComplete(); StepVerifier - .create(Mono.fromCompletionStage(result.getSentinels().get(1).getCredentialsProvider().resolveCredentials())) + .create(Mono + .fromCompletionStage(result.getSentinels().get(1).getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("bar".toCharArray()); @@ -344,14 +346,16 @@ void withAuthenticatedSentinelWithSentinel() { RedisURI result = RedisURI.Builder.sentinel("host", 1234, "master", "foo").withSentinel("bar").build(); StepVerifier - .create(Mono.fromCompletionStage(result.getSentinels().get(0).getCredentialsProvider().resolveCredentials())) + .create(Mono + .fromCompletionStage(result.getSentinels().get(0).getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("foo".toCharArray()); }).verifyComplete(); StepVerifier - .create(Mono.fromCompletionStage(result.getSentinels().get(1).getCredentialsProvider().resolveCredentials())) + .create(Mono + .fromCompletionStage(result.getSentinels().get(1).getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isNull(); @@ -361,14 +365,16 @@ void withAuthenticatedSentinelWithSentinel() { .withSentinel("bar", 1234, "baz").build(); StepVerifier - .create(Mono.fromCompletionStage(result.getSentinels().get(0).getCredentialsProvider().resolveCredentials())) + .create(Mono + .fromCompletionStage(result.getSentinels().get(0).getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isNull(); }).verifyComplete(); StepVerifier - .create(Mono.fromCompletionStage(result.getSentinels().get(1).getCredentialsProvider().resolveCredentials())) + .create(Mono + .fromCompletionStage(result.getSentinels().get(1).getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("baz".toCharArray()); @@ -425,7 +431,7 @@ void redisSocket() throws IOException { assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); assertThat(result.isSsl()).isFalse(); - StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isNull(); @@ -444,7 +450,7 @@ void redisSocketWithPassword() throws IOException { assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); assertThat(result.isSsl()).isFalse(); - StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(result.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -497,7 +503,7 @@ void shouldInitializeBuilder() { assertThat(target.isSsl()).isEqualTo(source.isSsl()); assertThat(target.isVerifyPeer()).isEqualTo(source.isVerifyPeer()); - StepVerifier.create(Mono.fromCompletionStage(target.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(target.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("baz".toCharArray()); diff --git a/src/test/java/io/lettuce/core/RedisURIUnitTests.java b/src/test/java/io/lettuce/core/RedisURIUnitTests.java index 189ccdfad6..8c5aa2b3f5 100644 --- a/src/test/java/io/lettuce/core/RedisURIUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisURIUnitTests.java @@ -284,7 +284,7 @@ void escapeCharacterParsingTest() throws UnsupportedEncodingException { String uri = "redis-sentinel://" + translatedPassword + "@h1:1234,h2:1234,h3:1234/0?sentinelMasterId=masterId"; RedisURI redisURI = RedisURI.create(uri); assertThat(redisURI.getSentinels().get(0).getHost()).isEqualTo("h1"); - StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo(password.toCharArray()); @@ -294,7 +294,7 @@ void escapeCharacterParsingTest() throws UnsupportedEncodingException { uri = "redis://" + translatedPassword + "@h1:1234/0"; redisURI = RedisURI.create(uri); assertThat(redisURI.getHost()).isEqualTo("h1"); - StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(redisURI.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo(password.toCharArray()); @@ -427,7 +427,7 @@ void shouldApplyAuthentication() { RedisURI target = new RedisURI(); target.applyAuthentication(source); - StepVerifier.create(Mono.fromCompletionStage(target.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(target.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isEqualTo("foo"); assertThat(credentials.getPassword()).isEqualTo("bar".toCharArray()); @@ -436,7 +436,7 @@ void shouldApplyAuthentication() { source.setCredentialsProvider(new StaticCredentialsProvider(null, "bar".toCharArray())); target.applyAuthentication(source); - StepVerifier.create(Mono.fromCompletionStage(target.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(target.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("bar".toCharArray()); @@ -451,7 +451,7 @@ void shouldApplyAuthentication() { RedisURI targetCp = new RedisURI(); targetCp.applyAuthentication(sourceCp); - StepVerifier.create(Mono.fromCompletionStage(targetCp.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(targetCp.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isEqualTo("suppliedUsername"); assertThat(credentials.getPassword()).isEqualTo("suppliedPassword".toCharArray()); diff --git a/src/test/java/io/lettuce/core/cluster/RedisClusterURIUtilUnitTests.java b/src/test/java/io/lettuce/core/cluster/RedisClusterURIUtilUnitTests.java index 58bef69fcf..6a12545698 100644 --- a/src/test/java/io/lettuce/core/cluster/RedisClusterURIUtilUnitTests.java +++ b/src/test/java/io/lettuce/core/cluster/RedisClusterURIUtilUnitTests.java @@ -75,7 +75,7 @@ void testSslWithPasswordSingleHost() { assertThat(host1.isStartTls()).isTrue(); assertThat(host1.getHost()).isEqualTo("host1"); assertThat(host1.getPort()).isEqualTo(6379); - StepVerifier.create(Mono.fromCompletionStage(host1.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(host1.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -94,7 +94,7 @@ void testSslWithPasswordMultipleHosts() { assertThat(host1.isStartTls()).isTrue(); assertThat(host1.getHost()).isEqualTo("host1"); assertThat(host1.getPort()).isEqualTo(6379); - StepVerifier.create(Mono.fromCompletionStage(host1.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(host1.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); @@ -105,7 +105,7 @@ void testSslWithPasswordMultipleHosts() { assertThat(host2.isStartTls()).isTrue(); assertThat(host2.getHost()).isEqualTo("host2"); assertThat(host2.getPort()).isEqualTo(6380); - StepVerifier.create(Mono.fromCompletionStage(host2.getCredentialsProvider().resolveCredentials())) + StepVerifier.create(Mono.fromCompletionStage(host2.getCredentialsProvider().resolveCredentialsAsync())) .assertNext(credentials -> { assertThat(credentials.getUsername()).isNull(); assertThat(credentials.getPassword()).isEqualTo("password".toCharArray()); From 625a413537b30a372182156b9b4ed3e729a81192 Mon Sep 17 00:00:00 2001 From: "aleksandar.todorov" Date: Fri, 10 Jul 2026 17:00:31 +0300 Subject: [PATCH 2/2] Remove RedisCredentialsProvider and promote CredentialsProvider as primary --- .../TokenBasedRedisCredentialsProvider.java | 6 +-- .../java/io/lettuce/core/ClientOptions.java | 22 ++++----- .../java/io/lettuce/core/ConnectionState.java | 6 +-- ...Provider.java => CredentialsProvider.java} | 33 +++++++------- .../core/RedisAuthenticationHandler.java | 20 ++++----- .../java/io/lettuce/core/RedisHandshake.java | 12 ++--- src/main/java/io/lettuce/core/RedisURI.java | 45 +++++++++---------- .../core/StaticCredentialsProvider.java | 5 +-- .../java/io/lettuce/core/Subscription.java | 2 +- .../connection/ReauthenticationEvent.java | 2 +- .../ReauthenticationFailedEvent.java | 2 +- .../core/failover/api/ImmutableRedisURI.java | 4 +- .../ConnectionCommandIntegrationTests.java | 4 +- .../MyStreamingRedisCredentialsProvider.java | 2 +- .../RedisAuthenticationHandlerUnitTests.java | 16 +++---- .../lettuce/core/RedisHandshakeUnitTests.java | 4 +- .../io/lettuce/core/RedisURIUnitTests.java | 6 +-- 17 files changed, 94 insertions(+), 97 deletions(-) rename src/main/java/io/lettuce/core/{RedisCredentialsProvider.java => CredentialsProvider.java} (75%) diff --git a/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java b/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java index 5c2043dab4..37075819c0 100644 --- a/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java +++ b/src/main/java/io/lettuce/authx/TokenBasedRedisCredentialsProvider.java @@ -7,7 +7,7 @@ package io.lettuce.authx; import io.lettuce.core.RedisCredentials; -import io.lettuce.core.RedisCredentialsProvider; +import io.lettuce.core.CredentialsProvider; import io.lettuce.core.Subscription; import io.lettuce.core.internal.LettuceAssert; import org.slf4j.Logger; @@ -26,7 +26,7 @@ import java.util.function.Consumer; /** - * A {@link RedisCredentialsProvider} implementation that supports token-based authentication for Redis. + * A {@link CredentialsProvider} implementation that supports token-based authentication for Redis. *

* This provider uses a {@link TokenManager} to manage and renew tokens, ensuring that the Redis client can authenticate with * Redis using a dynamically updated token. This is particularly useful in scenarios where Redis access is controlled via @@ -49,7 +49,7 @@ * * @since 6.6 */ -public class TokenBasedRedisCredentialsProvider implements RedisCredentialsProvider, AutoCloseable { +public class TokenBasedRedisCredentialsProvider implements CredentialsProvider, AutoCloseable { private static final Logger log = LoggerFactory.getLogger(TokenBasedRedisCredentialsProvider.class); diff --git a/src/main/java/io/lettuce/core/ClientOptions.java b/src/main/java/io/lettuce/core/ClientOptions.java index 68f78a60c2..f29cb5a600 100644 --- a/src/main/java/io/lettuce/core/ClientOptions.java +++ b/src/main/java/io/lettuce/core/ClientOptions.java @@ -600,7 +600,7 @@ public DisconnectedBehavior getDisconnectedBehavior() { } /** - * Behavior for re-authentication when the {@link RedisCredentialsProvider} emits new credentials. Defaults to + * Behavior for re-authentication when the {@link CredentialsProvider} emits new credentials. Defaults to * {@link ReauthenticateBehavior#DEFAULT}. * * @return the currently set {@link ReauthenticateBehavior}. @@ -743,31 +743,31 @@ public TimeoutOptions getTimeoutOptions() { /** * Defines the re-authentication behavior of the Redis client. *

- * Certain implementations of the {@link RedisCredentialsProvider} could emit new credentials at runtime. This setting - * controls how the driver reacts to these newly emitted credentials. + * Certain implementations of the {@link CredentialsProvider} could emit new credentials at runtime. This setting controls + * how the driver reacts to these newly emitted credentials. */ public enum ReauthenticateBehavior { /** * This is the default behavior. The client will fetch current credentials from the underlying - * {@link RedisCredentialsProvider} only when the driver needs to, e.g. when the connection is first established or when - * it is re-established after a disconnect. + * {@link CredentialsProvider} only when the driver needs to, e.g. when the connection is first established or when it + * is re-established after a disconnect. *

*

- * No re-authentication is performed when new credentials are emitted by a {@link RedisCredentialsProvider} that - * supports streaming. The client does not subscribe to or react to any updates published by - * {@link RedisCredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)}. + * No re-authentication is performed when new credentials are emitted by a {@link CredentialsProvider} that supports + * streaming. The client does not subscribe to or react to any updates published by + * {@link CredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)}. *

*/ DEFAULT, /** - * Automatically triggers re-authentication whenever new credentials are emitted by a {@link RedisCredentialsProvider} - * that supports streaming, as indicated by {@link RedisCredentialsProvider#supportsStreaming()}. + * Automatically triggers re-authentication whenever new credentials are emitted by a {@link CredentialsProvider} that + * supports streaming, as indicated by {@link CredentialsProvider#supportsStreaming()}. * *

* When this behavior is enabled, the client subscribes to credential updates via - * {@link RedisCredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)} and + * {@link CredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)} and * issues an {@code AUTH} command to the Redis server each time new credentials are received. This behavior supports * dynamic credential scenarios, such as token-based authentication, or credential rotation where credentials are * refreshed periodically to maintain access. diff --git a/src/main/java/io/lettuce/core/ConnectionState.java b/src/main/java/io/lettuce/core/ConnectionState.java index 7641070310..281a16d77d 100644 --- a/src/main/java/io/lettuce/core/ConnectionState.java +++ b/src/main/java/io/lettuce/core/ConnectionState.java @@ -35,7 +35,7 @@ public class ConnectionState { private volatile HandshakeResponse handshakeResponse; - private volatile RedisCredentialsProvider credentialsProvider; + private volatile CredentialsProvider credentialsProvider; private volatile int db; @@ -129,11 +129,11 @@ protected void setUserNamePassword(List args) { } } - protected void setCredentialsProvider(RedisCredentialsProvider credentialsProvider) { + protected void setCredentialsProvider(CredentialsProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; } - public RedisCredentialsProvider getCredentialsProvider() { + public CredentialsProvider getCredentialsProvider() { return credentialsProvider; } diff --git a/src/main/java/io/lettuce/core/RedisCredentialsProvider.java b/src/main/java/io/lettuce/core/CredentialsProvider.java similarity index 75% rename from src/main/java/io/lettuce/core/RedisCredentialsProvider.java rename to src/main/java/io/lettuce/core/CredentialsProvider.java index b75314f3d9..5533079136 100644 --- a/src/main/java/io/lettuce/core/RedisCredentialsProvider.java +++ b/src/main/java/io/lettuce/core/CredentialsProvider.java @@ -19,13 +19,13 @@ * @since 6.2 */ @FunctionalInterface -public interface RedisCredentialsProvider { +public interface CredentialsProvider { /** * Returns {@link RedisCredentials} that can be used to authorize a Redis connection. Each implementation of - * {@code RedisCredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation - * might load credentials from an existing key management system, or load new credentials when credentials are rotated. If - * an error occurs during the loading of credentials or credentials could not be found, the returned {@link CompletionStage} + * {@code CredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation might + * load credentials from an existing key management system, or load new credentials when credentials are rotated. If an + * error occurs during the loading of credentials or credentials could not be found, the returned {@link CompletionStage} * completes exceptionally. * * @return a {@link CompletionStage} that completes with the {@link RedisCredentials} used to authorize a Redis connection. @@ -34,12 +34,12 @@ public interface RedisCredentialsProvider { CompletionStage resolveCredentialsAsync(); /** - * Creates a new {@link RedisCredentialsProvider} from a given {@link Supplier}. + * Creates a new {@link CredentialsProvider} from a given {@link Supplier}. * * @param supplier must not be {@code null}. * @return the {@link RedisCredentials} using credentials from {@link Supplier}. */ - static RedisCredentialsProvider from(Supplier supplier) { + static CredentialsProvider from(Supplier supplier) { LettuceAssert.notNull(supplier, "Supplier must not be null"); @@ -57,11 +57,11 @@ static RedisCredentialsProvider from(Supplier supplier) { } /** - * Some implementations of the {@link RedisCredentialsProvider} may support streaming new credentials, based on some event - * that originates outside the driver. In this case they should indicate that so the {@link RedisAuthenticationHandler} is - * able to process these new credentials. + * Some implementations of the {@link CredentialsProvider} may support streaming new credentials, based on some event that + * originates outside the driver. In this case they should indicate that so the {@link RedisAuthenticationHandler} is able + * to process these new credentials. * - * @return whether the {@link RedisCredentialsProvider} supports streaming credentials. + * @return whether the {@link CredentialsProvider} supports streaming credentials. */ default boolean supportsStreaming() { return false; @@ -99,11 +99,11 @@ default Subscription subscribeToCredentials(Consumer onNext, C } /** - * Extension to {@link RedisCredentialsProvider} that resolves credentials immediately without the need to defer the - * credential resolution. + * Extension to {@link CredentialsProvider} that resolves credentials immediately without the need to defer the credential + * resolution. */ @FunctionalInterface - interface ImmediateRedisCredentialsProvider extends RedisCredentialsProvider { + interface ImmediateRedisCredentialsProvider extends CredentialsProvider { @Override default CompletionStage resolveCredentialsAsync() { @@ -120,10 +120,9 @@ default CompletionStage resolveCredentialsAsync() { /** * Returns {@link RedisCredentials} that can be used to authorize a Redis connection. Each implementation of - * {@code RedisCredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation - * might load credentials from an existing key management system, or load new credentials when credentials are rotated. - * If an error occurs during the loading of credentials or credentials could not be found, a runtime exception will be - * raised. + * {@code CredentialsProvider} can choose its own strategy for loading credentials. For example, an implementation might + * load credentials from an existing key management system, or load new credentials when credentials are rotated. If an + * error occurs during the loading of credentials or credentials could not be found, a runtime exception will be raised. * * @return the resolved {@link RedisCredentials} that can be used to authorize a Redis connection. */ diff --git a/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java b/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java index 5fe9dac919..8b8a3a463e 100644 --- a/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java +++ b/src/main/java/io/lettuce/core/RedisAuthenticationHandler.java @@ -45,7 +45,7 @@ public class RedisAuthenticationHandler { private final StatefulRedisConnectionImpl connection; - private final RedisCredentialsProvider credentialsProvider; + private final CredentialsProvider credentialsProvider; private final AtomicReference credentialsSubscription = new AtomicReference<>(); @@ -61,11 +61,11 @@ public class RedisAuthenticationHandler { * Creates a new {@link RedisAuthenticationHandler}. * * @param connection the connection to authenticate - * @param credentialsProvider the implementation of {@link RedisCredentialsProvider} to use + * @param credentialsProvider the implementation of {@link CredentialsProvider} to use * @param isPubSubConnection {@code true} if the connection is a pub/sub connection */ - public RedisAuthenticationHandler(StatefulRedisConnectionImpl connection, - RedisCredentialsProvider credentialsProvider, Boolean isPubSubConnection) { + public RedisAuthenticationHandler(StatefulRedisConnectionImpl connection, CredentialsProvider credentialsProvider, + Boolean isPubSubConnection) { this.connection = connection; this.credentialsProvider = credentialsProvider; this.isPubSubConnection = isPubSubConnection; @@ -75,16 +75,16 @@ public RedisAuthenticationHandler(StatefulRedisConnectionImpl connection, * Creates a new {@link RedisAuthenticationHandler} if the connection supports re-authentication. * * @param connection the connection to authenticate - * @param credentialsProvider the implementation of {@link RedisCredentialsProvider} to use + * @param credentialsProvider the implementation of {@link CredentialsProvider} to use * @param isPubSubConnection {@code true} if the connection is a pub/sub connection * @param options the {@link ClientOptions} to use * @return a new {@link RedisAuthenticationHandler} if the connection supports re-authentication, otherwise an * implementation of the {@link RedisAuthenticationHandler} that does nothing * @since 6.6.0 - * @see RedisCredentialsProvider + * @see CredentialsProvider */ public static RedisAuthenticationHandler createHandler(StatefulRedisConnectionImpl connection, - RedisCredentialsProvider credentialsProvider, Boolean isPubSubConnection, ClientOptions options) { + CredentialsProvider credentialsProvider, Boolean isPubSubConnection, ClientOptions options) { if (isSupported(options)) { @@ -106,7 +106,7 @@ public static RedisAuthenticationHandler createHandler(StatefulRedi * * @return a new {@link RedisAuthenticationHandler} * @since 6.6.0 - * @see RedisCredentialsProvider + * @see CredentialsProvider */ public static RedisAuthenticationHandler createDefaultAuthenticationHandler() { return new DisabledAuthenticationHandler<>(); @@ -163,7 +163,7 @@ protected void reauthenticate(RedisCredentials credentials) { } /** - * Handles errors observed by the underlying {@link RedisCredentialsProvider} while producing credentials. + * Handles errors observed by the underlying {@link CredentialsProvider} while producing credentials. * * @param e the error reported by the credentials provider */ @@ -359,7 +359,7 @@ private String getEpid() { private static final class DisabledAuthenticationHandler extends RedisAuthenticationHandler { public DisabledAuthenticationHandler(StatefulRedisConnectionImpl connection, - RedisCredentialsProvider credentialsProvider, Boolean isPubSubConnection) { + CredentialsProvider credentialsProvider, Boolean isPubSubConnection) { super(null, null, null); } diff --git a/src/main/java/io/lettuce/core/RedisHandshake.java b/src/main/java/io/lettuce/core/RedisHandshake.java index 89e6cd4dc7..ac600723e1 100644 --- a/src/main/java/io/lettuce/core/RedisHandshake.java +++ b/src/main/java/io/lettuce/core/RedisHandshake.java @@ -203,11 +203,11 @@ private void onHelloResponse(Map response) { * @param credentialsProvider * @return */ - private CompletableFuture initiateHandshakeResp2(Channel channel, RedisCredentialsProvider credentialsProvider) { + private CompletableFuture initiateHandshakeResp2(Channel channel, CredentialsProvider credentialsProvider) { - if (credentialsProvider instanceof RedisCredentialsProvider.ImmediateRedisCredentialsProvider) { + if (credentialsProvider instanceof CredentialsProvider.ImmediateRedisCredentialsProvider) { return dispatchAuthOrPing(channel, - ((RedisCredentialsProvider.ImmediateRedisCredentialsProvider) credentialsProvider).resolveCredentialsNow()); + ((CredentialsProvider.ImmediateRedisCredentialsProvider) credentialsProvider).resolveCredentialsNow()); } CompletableFuture credentialsFuture = credentialsProvider.resolveCredentialsAsync() @@ -237,11 +237,11 @@ private CompletableFuture dispatchAuthOrPing(Channel channel, RedisCrede * @return */ private CompletionStage> initiateHandshakeResp3(Channel channel, - RedisCredentialsProvider credentialsProvider) { + CredentialsProvider credentialsProvider) { - if (credentialsProvider instanceof RedisCredentialsProvider.ImmediateRedisCredentialsProvider) { + if (credentialsProvider instanceof CredentialsProvider.ImmediateRedisCredentialsProvider) { return dispatchHello(channel, - ((RedisCredentialsProvider.ImmediateRedisCredentialsProvider) credentialsProvider).resolveCredentialsNow()); + ((CredentialsProvider.ImmediateRedisCredentialsProvider) credentialsProvider).resolveCredentialsNow()); } CompletableFuture credentialsFuture = credentialsProvider.resolveCredentialsAsync() diff --git a/src/main/java/io/lettuce/core/RedisURI.java b/src/main/java/io/lettuce/core/RedisURI.java index 3e5e412d0f..264212ea0a 100644 --- a/src/main/java/io/lettuce/core/RedisURI.java +++ b/src/main/java/io/lettuce/core/RedisURI.java @@ -138,7 +138,7 @@ * *

Authentication

Redis URIs may contain authentication details that effectively lead to usernames with passwords, * password-only, or no authentication. Connections are authenticated by using information provided through - * {@link RedisCredentials}. Credentials are obtained at connection time from {@link RedisCredentialsProvider}. When configuring + * {@link RedisCredentials}. Credentials are obtained at connection time from {@link CredentialsProvider}. When configuring * username/password on the URI statically, then a {@link StaticCredentialsProvider} holds the configured information. * *

@@ -243,7 +243,7 @@ public class RedisURI implements Serializable, ConnectionPoint { private String libraryVersion = LettuceVersion.getVersion(); - private RedisCredentialsProvider credentialsProvider = new StaticCredentialsProvider(null, null); + private CredentialsProvider credentialsProvider = new StaticCredentialsProvider(null, null); private boolean ssl = false; @@ -461,7 +461,7 @@ public void setSocket(String socket) { /** * Apply authentication from another {@link RedisURI}. The authentication settings of the {@code source} URI will be applied - * to this URI. That is in particular the {@link RedisCredentialsProvider}. + * to this URI. That is in particular the {@link CredentialsProvider}. * * @param source must not be {@code null}. * @since 6.0 @@ -478,11 +478,11 @@ public void applyAuthentication(RedisURI source) { /** * Sets the password to use to authenticate Redis connections. *

- * This method effectively overwrites any existing {@link RedisCredentialsProvider} with a new one, containing an empty - * username and the provided password. + * This method effectively overwrites any existing {@link CredentialsProvider} with a new one, containing an empty username + * and the provided password. * * @param password the password to use to authenticate Redis connections. - * @see #setCredentialsProvider(RedisCredentialsProvider) + * @see #setCredentialsProvider(CredentialsProvider) * @since 7.0 */ public void setAuthentication(CharSequence password) { @@ -494,11 +494,11 @@ public void setAuthentication(CharSequence password) { /** * Sets the password to use to authenticate Redis connections. *

- * This method effectively overwrites any existing {@link RedisCredentialsProvider} with a new one, containing an empty - * username and the provided password. + * This method effectively overwrites any existing {@link CredentialsProvider} with a new one, containing an empty username + * and the provided password. * * @param password the password to use to authenticate Redis connections. - * @see #setCredentialsProvider(RedisCredentialsProvider) + * @see #setCredentialsProvider(CredentialsProvider) * @since 7.0 */ public void setAuthentication(char[] password) { @@ -510,12 +510,12 @@ public void setAuthentication(char[] password) { /** * Sets the username and password to use to authenticate Redis connections. *

- * This method effectively overwrites any existing {@link RedisCredentialsProvider} with a new one, containing the provided + * This method effectively overwrites any existing {@link CredentialsProvider} with a new one, containing the provided * username and password. * * @param username the username to use to authenticate Redis connections. * @param password the password to use to authenticate Redis connections. - * @see #setCredentialsProvider(RedisCredentialsProvider) + * @see #setCredentialsProvider(CredentialsProvider) * @since 7.0 */ public void setAuthentication(String username, char[] password) { @@ -527,12 +527,12 @@ public void setAuthentication(String username, char[] password) { /** * Sets the username and password to use to authenticate Redis connections. *

- * This method effectively overwrites any existing {@link RedisCredentialsProvider} with a new one, containing the provided + * This method effectively overwrites any existing {@link CredentialsProvider} with a new one, containing the provided * username and password. * * @param username the username to use to authenticate Redis connections. * @param password the password to use to authenticate Redis connections. - * @see #setCredentialsProvider(RedisCredentialsProvider) + * @see #setCredentialsProvider(CredentialsProvider) * @since 7.0 */ public void setAuthentication(String username, CharSequence password) { @@ -542,26 +542,25 @@ public void setAuthentication(String username, CharSequence password) { } /** - * Returns the {@link RedisCredentialsProvider} to use to authenticate Redis connections. Returns a static credentials - * provider no explicit {@link RedisCredentialsProvider} was configured. + * Returns the {@link CredentialsProvider} to use to authenticate Redis connections. Returns a static credentials provider + * no explicit {@link CredentialsProvider} was configured. * - * @return the {@link RedisCredentialsProvider} to use to authenticate Redis connections + * @return the {@link CredentialsProvider} to use to authenticate Redis connections * @since 6.2 */ - public RedisCredentialsProvider getCredentialsProvider() { + public CredentialsProvider getCredentialsProvider() { return this.credentialsProvider; } /** - * Sets the {@link RedisCredentialsProvider}. Configuring a credentials provider resets the configured static - * username/password. + * Sets the {@link CredentialsProvider}. Configuring a credentials provider resets the configured static username/password. * * @param credentialsProvider the credentials provider to use when authenticating a Redis connection. * @since 6.2 */ - public void setCredentialsProvider(RedisCredentialsProvider credentialsProvider) { + public void setCredentialsProvider(CredentialsProvider credentialsProvider) { - LettuceAssert.notNull(credentialsProvider, "RedisCredentialsProvider must not be null"); + LettuceAssert.notNull(credentialsProvider, "CredentialsProvider must not be null"); this.credentialsProvider = credentialsProvider; } @@ -1361,7 +1360,7 @@ public static class Builder { private DriverInfo driverInfo = DriverInfo.builder().build(); - private RedisCredentialsProvider credentialsProvider; + private CredentialsProvider credentialsProvider; private boolean ssl = false; @@ -1795,7 +1794,7 @@ public Builder withAuthentication(String username, char[] password) { * @param credentialsProvider the credentials provider to use * @since 6.2 */ - public Builder withAuthentication(RedisCredentialsProvider credentialsProvider) { + public Builder withAuthentication(CredentialsProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return this; } diff --git a/src/main/java/io/lettuce/core/StaticCredentialsProvider.java b/src/main/java/io/lettuce/core/StaticCredentialsProvider.java index 931eab2f36..e06267be60 100644 --- a/src/main/java/io/lettuce/core/StaticCredentialsProvider.java +++ b/src/main/java/io/lettuce/core/StaticCredentialsProvider.java @@ -6,13 +6,12 @@ import io.lettuce.core.internal.LettuceAssert; /** - * Static implementation of {@link RedisCredentialsProvider}. + * Static implementation of {@link CredentialsProvider}. * * @author Mark Paluch * @since 6.2 */ -public class StaticCredentialsProvider - implements RedisCredentialsProvider, RedisCredentialsProvider.ImmediateRedisCredentialsProvider { +public class StaticCredentialsProvider implements CredentialsProvider, CredentialsProvider.ImmediateRedisCredentialsProvider { private final RedisCredentials credentials; diff --git a/src/main/java/io/lettuce/core/Subscription.java b/src/main/java/io/lettuce/core/Subscription.java index 6f84990d93..b5cb80fe33 100644 --- a/src/main/java/io/lettuce/core/Subscription.java +++ b/src/main/java/io/lettuce/core/Subscription.java @@ -8,7 +8,7 @@ /** * Handle to a callback subscription on a Lettuce streaming SPI, such as - * {@link io.lettuce.core.RedisCredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)} + * {@link io.lettuce.core.CredentialsProvider#subscribeToCredentials(java.util.function.Consumer, java.util.function.Consumer)} * or {@link io.lettuce.core.event.EventBus}. Closing the subscription stops delivery of further values to the registered * callback. *

diff --git a/src/main/java/io/lettuce/core/event/connection/ReauthenticationEvent.java b/src/main/java/io/lettuce/core/event/connection/ReauthenticationEvent.java index bb9ab0bc07..82d5519121 100644 --- a/src/main/java/io/lettuce/core/event/connection/ReauthenticationEvent.java +++ b/src/main/java/io/lettuce/core/event/connection/ReauthenticationEvent.java @@ -11,7 +11,7 @@ * * @author Ivo Gaydajiev * @since 6.6.0 - * @see io.lettuce.core.RedisCredentialsProvider + * @see io.lettuce.core.CredentialsProvider */ public class ReauthenticationEvent implements AuthenticationEvent { diff --git a/src/main/java/io/lettuce/core/event/connection/ReauthenticationFailedEvent.java b/src/main/java/io/lettuce/core/event/connection/ReauthenticationFailedEvent.java index 79164aa965..0a7cde070d 100644 --- a/src/main/java/io/lettuce/core/event/connection/ReauthenticationFailedEvent.java +++ b/src/main/java/io/lettuce/core/event/connection/ReauthenticationFailedEvent.java @@ -11,7 +11,7 @@ * * @author Ivo Gaydajiev * @since 6.6.0 - * @see io.lettuce.core.RedisCredentialsProvider + * @see io.lettuce.core.CredentialsProvider */ public class ReauthenticationFailedEvent implements AuthenticationEvent { diff --git a/src/main/java/io/lettuce/core/failover/api/ImmutableRedisURI.java b/src/main/java/io/lettuce/core/failover/api/ImmutableRedisURI.java index 61a4629ac6..631dc232e5 100644 --- a/src/main/java/io/lettuce/core/failover/api/ImmutableRedisURI.java +++ b/src/main/java/io/lettuce/core/failover/api/ImmutableRedisURI.java @@ -6,7 +6,7 @@ import java.util.stream.Collectors; import io.lettuce.core.DriverInfo; -import io.lettuce.core.RedisCredentialsProvider; +import io.lettuce.core.CredentialsProvider; import io.lettuce.core.RedisURI; import io.lettuce.core.SslVerifyMode; import io.lettuce.core.annotations.Experimental; @@ -72,7 +72,7 @@ public void setAuthentication(String username, CharSequence password) { } @Override - public void setCredentialsProvider(RedisCredentialsProvider credentialsProvider) { + public void setCredentialsProvider(CredentialsProvider credentialsProvider) { throw new UnsupportedOperationException("ImmutableRedisURI cannot be modified"); } diff --git a/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java b/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java index 1146bd7678..b952a22142 100644 --- a/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/ConnectionCommandIntegrationTests.java @@ -157,8 +157,8 @@ void changeAclPasswordDuringDisconnect() { AtomicReference passwd = new AtomicReference<>(TestSettings.aclPassword()); - RedisCredentialsProvider.ImmediateRedisCredentialsProvider rcp = () -> RedisCredentials - .just(TestSettings.aclUsername(), passwd.get()); + CredentialsProvider.ImmediateRedisCredentialsProvider rcp = () -> RedisCredentials.just(TestSettings.aclUsername(), + passwd.get()); RedisURI redisURI = RedisURI.Builder.redis(host, port).withDatabase(2).withAuthentication(rcp).build(); try (StatefulRedisConnection connection = client.connect(redisURI)) { diff --git a/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java b/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java index 48988e00a8..d3ac6181cb 100644 --- a/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java +++ b/src/test/java/io/lettuce/core/MyStreamingRedisCredentialsProvider.java @@ -15,7 +15,7 @@ * @author Ivo Gaydajiev * @since 6.6.0 */ -public class MyStreamingRedisCredentialsProvider implements RedisCredentialsProvider { +public class MyStreamingRedisCredentialsProvider implements CredentialsProvider { private final Object lock = new Object(); diff --git a/src/test/java/io/lettuce/core/RedisAuthenticationHandlerUnitTests.java b/src/test/java/io/lettuce/core/RedisAuthenticationHandlerUnitTests.java index 07cea7a15e..3fb46b84b8 100644 --- a/src/test/java/io/lettuce/core/RedisAuthenticationHandlerUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisAuthenticationHandlerUnitTests.java @@ -121,8 +121,8 @@ void testIsSupportedConnectionWithRESP2ProtocolOnPubSubConnection() { when(connectionState.getNegotiatedProtocolVersion()).thenReturn(ProtocolVersion.RESP2); - RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, - mock(RedisCredentialsProvider.class), true); + RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, mock(CredentialsProvider.class), + true); assertFalse(handler.isSupportedConnection()); } @@ -132,8 +132,8 @@ void testIsSupportedConnectionWithNonPubSubConnection() { when(connectionState.getNegotiatedProtocolVersion()).thenReturn(ProtocolVersion.RESP2); - RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, - mock(RedisCredentialsProvider.class), false); + RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, mock(CredentialsProvider.class), + false); assertTrue(handler.isSupportedConnection()); } @@ -143,16 +143,16 @@ void testIsSupportedConnectionWithRESP3ProtocolOnPubSubConnection() { when(connectionState.getNegotiatedProtocolVersion()).thenReturn(ProtocolVersion.RESP3); - RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, - mock(RedisCredentialsProvider.class), true); + RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, mock(CredentialsProvider.class), + true); assertTrue(handler.isSupportedConnection()); } @Test public void testSetCredentialsWhenCredentialsAreNull() { - RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, - mock(RedisCredentialsProvider.class), false); + RedisAuthenticationHandler handler = new RedisAuthenticationHandler<>(connection, mock(CredentialsProvider.class), + false); handler.setCredentials(null); diff --git a/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java b/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java index dbd128a852..2415693c33 100644 --- a/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisHandshakeUnitTests.java @@ -132,7 +132,7 @@ void handshakeWithInvalidResponseShouldPropagateException() { void handshakeDelayedCredentialProvider() { DelayedRedisCredentialsProvider cp = new DelayedRedisCredentialsProvider(); - // RedisCredentialsProvider cp = () -> Mono.just(RedisCredentials.just("foo", + // CredentialsProvider cp = () -> Mono.just(RedisCredentials.just("foo", // "bar")).delayElement(Duration.ofMillis(3)); EmbeddedChannel channel = new EmbeddedChannel(true, false); @@ -354,7 +354,7 @@ private static void helloStringIdResponse(CommandOutput credentialsSink = Sinks.one(); diff --git a/src/test/java/io/lettuce/core/RedisURIUnitTests.java b/src/test/java/io/lettuce/core/RedisURIUnitTests.java index 8c5aa2b3f5..7d2eb1383c 100644 --- a/src/test/java/io/lettuce/core/RedisURIUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisURIUnitTests.java @@ -90,7 +90,7 @@ void toStringTest() { void toStringShouldUnwrapCredentialsProviderFailure() { RedisException cause = new RedisException("auth failed"); - RedisCredentialsProvider failing = () -> { + CredentialsProvider failing = () -> { CompletableFuture f = new CompletableFuture<>(); f.completeExceptionally(cause); return f; @@ -106,7 +106,7 @@ void toStringShouldUnwrapCredentialsProviderFailure() { void toStringShouldUnwrapCredentialsProviderRuntimeFailure() { IllegalStateException cause = new IllegalStateException("boom"); - RedisCredentialsProvider failing = () -> { + CredentialsProvider failing = () -> { CompletableFuture f = new CompletableFuture<>(); f.completeExceptionally(cause); return f; @@ -442,7 +442,7 @@ void shouldApplyAuthentication() { assertThat(credentials.getPassword()).isEqualTo("bar".toCharArray()); }).verifyComplete(); - RedisCredentialsProvider provider = () -> CompletableFuture + CredentialsProvider provider = () -> CompletableFuture .completedFuture(RedisCredentials.just("suppliedUsername", "suppliedPassword".toCharArray())); RedisURI sourceCp = new RedisURI();