+ * Redis 6.0+ supports Access Control Lists (ACL) with username/password authentication. + * It is also possible to include a username in the Redis URI, in the form {@code redis://USERNAME:PASSWORD@host:port}. + * Any username that you set with {@link #username(String)} will override the URI. + *
+ * Note: Using this feature requires Jedis 3.6.0 or later.
+ *
+ * @param username the username for ACL authentication
+ * @return the builder
+ * @since 2.2.0
+ */
+ public RedisStoreBuilder
- * It is also possible to include a password in the Redis URI, in the form {@code redis://:PASSWORD@host:port}. Any
- * password that you set with {@link #password(String)} will override the URI.
+ * It is also possible to include a password in the Redis URI, in the form {@code redis://:PASSWORD@host:port}
+ * or {@code redis://USERNAME:PASSWORD@host:port} for ACL authentication. Any password that you set with
+ * {@link #password(String)} will override the URI.
*
* @param password the password
* @return the builder
diff --git a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java
index fa1ff5c..2241675 100644
--- a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java
+++ b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java
@@ -21,11 +21,15 @@ protected RedisStoreImplBase(RedisStoreBuilder> builder, LDLogger logger) {
// to decompose the URI.
String host = builder.uri.getHost();
int port = builder.uri.getPort();
+ String username = builder.username == null ? RedisURIComponents.getUsername(builder.uri) : builder.username;
String password = builder.password == null ? RedisURIComponents.getPassword(builder.uri) : builder.password;
int database = builder.database == null ? RedisURIComponents.getDBIndex(builder.uri) : builder.database;
boolean tls = builder.tls || builder.uri.getScheme().equals("rediss");
String extra = tls ? " with TLS" : "";
+ if (username != null) {
+ extra = extra + (extra.isEmpty() ? " with" : " and") + " username";
+ }
if (password != null) {
extra = extra + (extra.isEmpty() ? " with" : " and") + " password";
}
@@ -41,6 +45,7 @@ protected RedisStoreImplBase(RedisStoreBuilder> builder, LDLogger logger) {
port,
(int) builder.connectTimeout.toMillis(),
(int) builder.socketTimeout.toMillis(),
+ username,
password,
database,
null, // clientName
diff --git a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisURIComponents.java b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisURIComponents.java
index 3c39ccc..3c44a74 100644
--- a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisURIComponents.java
+++ b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisURIComponents.java
@@ -8,6 +8,39 @@
* that class doesn't exist in the same location in both versions.
*/
abstract class RedisURIComponents {
+ /**
+ * Extracts the username from a Redis URI.
+ *
+ * Supports both formats:
+ *
+ * Supports both formats:
+ *
+ *
+ *
+ * @param uri the Redis URI
+ * @return the username, or null if not specified or empty
+ */
+ static String getUsername(URI uri) {
+ if (uri.getUserInfo() == null) {
+ return null;
+ }
+ String[] parts = uri.getUserInfo().split(":", 2);
+ // If the username part is empty (e.g., ":password"), return null
+ return (parts.length > 0 && !parts[0].isEmpty()) ? parts[0] : null;
+ }
+
+ /**
+ * Extracts the password from a Redis URI.
+ *
+ *
+ *
+ * @param uri the Redis URI
+ * @return the password, or null if not specified
+ */
static String getPassword(URI uri) {
if (uri.getUserInfo() == null) {
return null;
@@ -16,6 +49,12 @@ static String getPassword(URI uri) {
return parts.length < 2 ? null : parts[1];
}
+ /**
+ * Extracts the database index from a Redis URI.
+ *
+ * @param uri the Redis URI (e.g., {@code redis://host:port/2})
+ * @return the database index, or 0 if not specified
+ */
static int getDBIndex(URI uri) {
String[] parts = uri.getPath().split("/", 2);
if (parts.length < 2 || parts[1].isEmpty()) {