aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@users.noreply.github.com>2021-07-22 12:47:26 +0200
committerGitHub <noreply@github.com>2021-07-22 12:47:26 +0200
commitf14b8aa34bfb9f7af7b23cfecc09e2fb8f604c1b (patch)
tree7f02c9fcb169d6b091e39b5db65599a098822c54 /lib
parentdd4668f935f59cdb21deea38cfd16e6226798da0 (diff)
parent6e00fe8c26c8d1cd68497911371c3b4b785d903c (diff)
downloadnextcloud-server-f14b8aa34bfb9f7af7b23cfecc09e2fb8f604c1b.tar.gz
nextcloud-server-f14b8aa34bfb9f7af7b23cfecc09e2fb8f604c1b.zip
Merge pull request #27888 from nextcloud/fix/redis-auth
Diffstat (limited to 'lib')
-rw-r--r--lib/private/RedisFactory.php116
1 files changed, 92 insertions, 24 deletions
diff --git a/lib/private/RedisFactory.php b/lib/private/RedisFactory.php
index 61168c3dd86..7609a75d52d 100644
--- a/lib/private/RedisFactory.php
+++ b/lib/private/RedisFactory.php
@@ -27,7 +27,10 @@
namespace OC;
class RedisFactory {
- /** @var \Redis */
+ public const REDIS_MINIMAL_VERSION = '2.2.5';
+ public const REDIS_EXTRA_PARAMETERS_MINIMAL_VERSION = '5.3.0';
+
+ /** @var \Redis|\RedisCluster */
private $instance;
/** @var SystemConfig */
@@ -43,25 +46,51 @@ class RedisFactory {
}
private function create() {
- if ($config = $this->config->getValue('redis.cluster', [])) {
- if (!class_exists('RedisCluster')) {
- throw new \Exception('Redis Cluster support is not available');
- }
- // cluster config
- if (isset($config['timeout'])) {
- $timeout = $config['timeout'];
- } else {
- $timeout = null;
- }
- if (isset($config['read_timeout'])) {
- $readTimeout = $config['read_timeout'];
+ $isCluster = in_array('redis.cluster', $this->config->getKeys());
+ $config = $isCluster
+ ? $this->config->getValue('redis.cluster', [])
+ : $this->config->getValue('redis', []);
+
+ if (empty($config)) {
+ throw new \Exception('Redis config is empty');
+ }
+
+ if ($isCluster && !class_exists('RedisCluster')) {
+ throw new \Exception('Redis Cluster support is not available');
+ }
+
+ if (isset($config['timeout'])) {
+ $timeout = $config['timeout'];
+ } else {
+ $timeout = 0.0;
+ }
+
+ if (isset($config['read_timeout'])) {
+ $readTimeout = $config['read_timeout'];
+ } else {
+ $readTimeout = 0.0;
+ }
+
+ $auth = null;
+ if (isset($config['password']) && $config['password'] !== '') {
+ if (isset($config['user']) && $config['user'] !== '') {
+ $auth = [$config['user'], $config['password']];
} else {
- $readTimeout = null;
+ $auth = $config['password'];
}
- if (isset($config['password']) && $config['password'] !== '') {
- $this->instance = new \RedisCluster(null, $config['seeds'], $timeout, $readTimeout, false, $config['password']);
+ }
+
+ // # TLS support
+ // # https://github.com/phpredis/phpredis/issues/1600
+ $connectionParameters = $this->getSslContext($config);
+
+ // cluster config
+ if ($isCluster) {
+ // Support for older phpredis versions not supporting connectionParameters
+ if ($connectionParameters !== null) {
+ $this->instance = new \RedisCluster(null, $config['seeds'], $timeout, $readTimeout, false, $auth, $connectionParameters);
} else {
- $this->instance = new \RedisCluster(null, $config['seeds'], $timeout, $readTimeout);
+ $this->instance = new \RedisCluster(null, $config['seeds'], $timeout, $readTimeout, false, $auth);
}
if (isset($config['failover_mode'])) {
@@ -69,12 +98,13 @@ class RedisFactory {
}
} else {
$this->instance = new \Redis();
- $config = $this->config->getValue('redis', []);
+
if (isset($config['host'])) {
$host = $config['host'];
} else {
$host = '127.0.0.1';
}
+
if (isset($config['port'])) {
$port = $config['port'];
} elseif ($host[0] !== '/') {
@@ -82,15 +112,22 @@ class RedisFactory {
} else {
$port = null;
}
- if (isset($config['timeout'])) {
- $timeout = $config['timeout'];
+
+ // Support for older phpredis versions not supporting connectionParameters
+ if ($connectionParameters !== null) {
+ // Non-clustered redis requires connection parameters to be wrapped inside `stream`
+ $connectionParameters = [
+ 'stream' => $this->getSslContext($config)
+ ];
+ $this->instance->connect($host, $port, $timeout, null, 0, $readTimeout, $connectionParameters);
} else {
- $timeout = 0.0; // unlimited
+ $this->instance->connect($host, $port, $timeout, null, 0, $readTimeout);
}
- $this->instance->connect($host, $port, $timeout);
- if (isset($config['password']) && $config['password'] !== '') {
- $this->instance->auth($config['password']);
+
+ // Auth if configured
+ if ($auth !== null) {
+ $this->instance->auth($auth);
}
if (isset($config['dbindex'])) {
@@ -99,6 +136,26 @@ class RedisFactory {
}
}
+ /**
+ * Get the ssl context config
+ *
+ * @param Array $config the current config
+ * @return Array|null
+ * @throws \UnexpectedValueException
+ */
+ private function getSslContext($config) {
+ if (isset($config['ssl_context'])) {
+ if (!$this->isConnectionParametersSupported()) {
+ throw new \UnexpectedValueException(\sprintf(
+ 'php-redis extension must be version %s or higher to support ssl context',
+ self::REDIS_EXTRA_PARAMETERS_MINIMAL_VERSION
+ ));
+ }
+ return $config['ssl_context'];
+ }
+ return null;
+ }
+
public function getInstance() {
if (!$this->isAvailable()) {
throw new \Exception('Redis support is not available');
@@ -114,4 +171,15 @@ class RedisFactory {
return extension_loaded('redis')
&& version_compare(phpversion('redis'), '2.2.5', '>=');
}
+
+ /**
+ * Php redis does support configurable extra parameters since version 5.3.0, see: https://github.com/phpredis/phpredis#connect-open.
+ * We need to check if the current version supports extra connection parameters, otherwise the connect method will throw an exception
+ *
+ * @return boolean
+ */
+ private function isConnectionParametersSupported(): bool {
+ return \extension_loaded('redis') &&
+ \version_compare(\phpversion('redis'), self::REDIS_EXTRA_PARAMETERS_MINIMAL_VERSION, '>=');
+ }
}