From 2537b2ac7ee99560315fd61f66bc97f209f4433f Mon Sep 17 00:00:00 2001
From: fengtan <fengtan@847318.no-reply.drupal.org>
Date: Thu, 30 Jun 2022 12:32:11 -0400
Subject: [PATCH] Support ACL's when connecting to Redis store.

---
 config-templates/config.php                   | 13 +++++++++++--
 docs/simplesamlphp-maintenance.md             |  6 +++++-
 src/SimpleSAML/Store/RedisStore.php           |  5 ++++-
 tests/src/SimpleSAML/Store/RedisStoreTest.php | 15 +++++++++++++++
 4 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/config-templates/config.php b/config-templates/config.php
index 9c1e7cf9f..8b0cf240d 100644
--- a/config-templates/config.php
+++ b/config-templates/config.php
@@ -1204,9 +1204,18 @@ $config = [
     'store.redis.port' => 6379,
 
     /*
-     * The password to use when connecting to a password-protected Redis instance.
+     * The credentials to use when connecting to Redis.
+     *
+     * If your Redis server is using the legacy password protection (config
+     * directive "requirepass" in redis.conf) then you should only provide
+     * a password.
+     *
+     * If your Redis server is using ACL's (which are recommended as of
+     * Redis 6+) then you should provide both a username and a password.
+     * See https://redis.io/docs/manual/security/acl/
      */
-    'store.redis.password' => null,
+    'store.redis.username' => '',
+    'store.redis.password' => '',
 
     /*
      * The prefix we should use on our Redis datastore.
diff --git a/docs/simplesamlphp-maintenance.md b/docs/simplesamlphp-maintenance.md
index 5e4be54d6..3dc861731 100644
--- a/docs/simplesamlphp-maintenance.md
+++ b/docs/simplesamlphp-maintenance.md
@@ -161,7 +161,11 @@ The required tables are created automatically. If you are storing data from mult
 
 To store sessions in Redis, set the `store.type` option to `redis`.
 
-By default SimpleSAMLphp will attempt to connect to Redis on the `localhost` at port `6379`. These can be configured via the `store.redis.host` and `store.redis.port` options, respectively. You may also set a key prefix with the `store.redis.prefix` option. For Redis instances that [require authentication](https://redis.io/commands/auth), use the `store.redis.password` option.
+By default SimpleSAMLphp will attempt to connect to Redis on the `localhost` at port `6379`. These can be configured via the `store.redis.host` and `store.redis.port` options, respectively. You may also set a key prefix with the `store.redis.prefix` option.
+
+For Redis instances that [require authentication](https://redis.io/commands/auth):
+* If authentication is managed with the `requirepass` directive (legacy password protection): use the `store.redis.password` option
+* If authentication is managed with [ACL's](https://redis.io/docs/manual/security/acl/) (which are recommended as of Redis 6): use the `store.redis.password` and `store.redis.username` options
 
 ## Metadata storage
 
diff --git a/src/SimpleSAML/Store/RedisStore.php b/src/SimpleSAML/Store/RedisStore.php
index 7781d3c10..0bee896de 100644
--- a/src/SimpleSAML/Store/RedisStore.php
+++ b/src/SimpleSAML/Store/RedisStore.php
@@ -39,6 +39,7 @@ class RedisStore implements StoreInterface
             $port = $config->getOptionalInteger('store.redis.port', 6379);
             $prefix = $config->getOptionalString('store.redis.prefix', 'SimpleSAMLphp');
             $password = $config->getOptionalString('store.redis.password', null);
+            $username = $config->getOptionalString('store.redis.username', null);
             $database = $config->getOptionalInteger('store.redis.database', 0);
 
             $redis = new Client(
@@ -47,7 +48,9 @@ class RedisStore implements StoreInterface
                     'host' => $host,
                     'port' => $port,
                     'database' => $database,
-                ] + (!empty($password) ? ['password' => $password] : []),
+                ]
+                + (!empty($password) ? ['password' => $password] : [])
+                + (!empty($username) ? ['username' => $username] : []),
                 [
                     'prefix' => $prefix,
                 ]
diff --git a/tests/src/SimpleSAML/Store/RedisStoreTest.php b/tests/src/SimpleSAML/Store/RedisStoreTest.php
index 7bc70076f..0f2336e58 100644
--- a/tests/src/SimpleSAML/Store/RedisStoreTest.php
+++ b/tests/src/SimpleSAML/Store/RedisStoreTest.php
@@ -128,6 +128,21 @@ class RedisStoreTest extends TestCase
         $this->assertInstanceOf(Store\RedisStore::class, $this->store);
     }
 
+    /**
+     * @test
+     */
+    public function testRedisInstanceWithPasswordAndUsername(): void
+    {
+        $config = Configuration::loadFromArray([
+            'store.type' => 'redis',
+            'store.redis.prefix' => 'phpunit_',
+            'store.redis.password' => 'password',
+            'store.redis.username' => 'username',
+        ], '[ARRAY]', 'simplesaml');
+
+        $this->assertInstanceOf(Store\RedisStore::class, $this->store);
+    }
+
 
     /**
      * @test
-- 
GitLab