Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Add option to set username for RedisBackend #3393

Open
wants to merge 3 commits into
base: 8.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions Neos.Cache/Classes/Backend/RedisBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* - port: The TCP port of the redis server (will be ignored if connecting to a socket)
* - database: The database index that will be used. By default,
* Redis has 16 databases with index number 0 - 15
* - username: The username needed for the redis clients to connect to the server (hostname)
* - password: The password needed for redis clients to connect to the server (hostname)
* - batchSize: Maximum number of parameters per query for batch operations
*
Expand Down Expand Up @@ -69,6 +70,8 @@ class RedisBackend extends IndependentAbstractBackend implements TaggableBackend

protected int $database = 0;

protected string $username = '';

protected string $password = '';

protected int $compressionLevel = 0;
Expand Down Expand Up @@ -192,8 +195,8 @@ public function has(string $entryIdentifier): bool
* old entries for the identifier still exist, they are removed as well.
*
* @param string $entryIdentifier Specifies the cache entry to remove
* @throws \RuntimeException
* @return boolean true if (at least) an entry could be removed or false if no entry was found
* @throws \RuntimeException
* @api
*/
public function remove(string $entryIdentifier): bool
Expand Down Expand Up @@ -257,8 +260,8 @@ public function collectGarbage(): void
* Removes all cache entries of this cache which are tagged by the specified tag.
*
* @param string $tag The tag the entries must have
* @throws \RuntimeException
* @return integer The number of entries which have been affected by this flush
* @throws \RuntimeException
* @api
*/
public function flushByTag(string $tag): int
Expand Down Expand Up @@ -290,8 +293,8 @@ public function flushByTag(string $tag): int
* Removes all cache entries of this cache which are tagged by the specified tags.
*
* @param array<string> $tags The tag the entries must have
* @throws \RuntimeException
* @return integer The number of entries which have been affected by this flush
* @throws \RuntimeException
* @api
*/
public function flushByTags(array $tags): int
Expand Down Expand Up @@ -468,6 +471,11 @@ public function setDatabase(int|string $database): void
$this->database = (int)$database;
}

public function setUsername(string $username): void
{
$this->username = $username;
}

public function setPassword(string $password): void
{
$this->password = $password;
Expand Down Expand Up @@ -500,7 +508,7 @@ private function uncompress(bool|string $value): bool|string
if (empty($value)) {
return $value;
}
return $this->useCompression() ? gzdecode((string) $value) : $value;
return $this->useCompression() ? gzdecode((string)$value) : $value;
}

private function compress(string $value): string
Expand Down Expand Up @@ -535,8 +543,16 @@ private function getRedisClient(): \Redis
}
}

if ($this->password !== '' && !$redis->auth($this->password)) {
throw new CacheException('Redis authentication failed.', 1502366200);
if ($this->username !== '' && $this->password !== '') {
$result = $redis->auth([$this->username, $this->password]);
if ($result === false) {
throw new CacheException(sprintf('Redis authentication failed, using username "%s" and a %s bytes long password.', $this->username, strlen($this->password)), 1725607160);
}
} elseif ($this->password !== '') {
$result = $redis->auth($this->password);
if ($result === false) {
throw new CacheException(sprintf('Redis authentication failed, using a %s bytes long password.', strlen($this->password)), 1502366200);
}
}
$redis->select($this->database);
return $redis;
Expand Down
111 changes: 111 additions & 0 deletions Neos.Cache/Tests/Functional/Backend/RedisBackendAuthenticationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

namespace Neos\Cache\Tests\Functional\Backend;

include_once(__DIR__ . '/../../BaseTestCase.php');

/*
* This file is part of the Neos.Cache package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Exception;
use Neos\Cache\Backend\RedisBackend;
use Neos\Cache\EnvironmentConfiguration;
use Neos\Cache\Tests\BaseTestCase;
use RedisException;

/**
* Testcase for the redis cache backend
*
* These tests use an actual Redis instance and will place and remove keys in db 0!
* Since all keys have the 'TestCache:' prefix, running the tests should have
* no side effects on non-related cache entries.
*
* Tests require Redis listening on 127.0.0.1:6379. Furthermore, the following users are required
* default:<no_password>
* test_no_password:<no_password>
* test_password:<secret_password>
*
* The users can be added by:
* acl setuser test_no_password on > ~* &* +@all
* acl setuser test_password on >secret_password ~* &* +@all
*
* @requires extension redis
*/
class RedisBackendAuthenticationTest extends BaseTestCase
{
/**
* Set up test case
*
* @return void
*/
protected function setUp(): void
{
$phpredisVersion = phpversion('redis');
if (version_compare($phpredisVersion, '5.0.0', '<')) {
$this->markTestSkipped(sprintf('phpredis extension version %s is not supported. Please update to version 5.0.0+.', $phpredisVersion));
}
try {
if (!@fsockopen('127.0.0.1', 6379)) {
$this->markTestSkipped('redis server not reachable');
}
} catch (Exception $e) {
$this->markTestSkipped('redis server not reachable');
}
}


/**
* @test
*/
public function defaultUserNoPassword()
{
$backend = new RedisBackend(
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
['hostname' => '127.0.0.1', 'database' => 0]
);
$this->assertInstanceOf('Neos\Cache\Backend\RedisBackend', $backend);
}

/**
* @test
*/
public function usernameNoPassword()
{
$backend = new RedisBackend(
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
['hostname' => '127.0.0.1', 'database' => 0, 'username' => 'test_no_password']
);
$this->assertInstanceOf('Neos\Cache\Backend\RedisBackend', $backend);
}

/**
* @test
*/
public function usernamePassword()
{
$backend = new RedisBackend(
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
['hostname' => '127.0.0.1', 'database' => 0, 'username' => 'test_password', 'password' => 'secret_password']
);
$this->assertInstanceOf('Neos\Cache\Backend\RedisBackend', $backend);
}

/**
* @test
*/
public function incorrectUsernamePassword()
{
$this->expectException(RedisException::class);
$backend = new RedisBackend(
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
['hostname' => '127.0.0.1', 'database' => 0, 'username' => 'test_password', 'password' => 'incorrect_password']
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,9 @@ Options
| | unit tests and should not be | | | |
| | used if possible. | | | |
+------------------+---------------------------------+-----------+-----------+-----------+
| username | Username to use for the | No | string | |
| | database connection. | | | |
+------------------+---------------------------------+-----------+-----------+-----------+
| password | Password used to connect to the | No | string | |
| | redis instance if the redis | | | |
| | server needs authentication. | | | |
Expand All @@ -577,7 +580,7 @@ Options
| compressionLevel | Set gzip compression level to a | No | integer | 0 |
| | specific value. | | (0 to 9) | |
+------------------+---------------------------------+-----------+-----------+-----------+
| batchSize | Maximum number of parameters | No | int | 100000 |
| batchSize | Maximum number of parameters | No | integer | 100000 |
| | per query for batch operations. | | | |
| | | | | |
| | Redis supports up to | | | |
Expand Down
Loading