Skip to content

Commit 73db1b6

Browse files
committed
add support for TLS configuration for Redis Store
generate selected SSL context options for the Predis client. see https://www.php.net/manual/en/context.ssl.php closes #1804
1 parent d81adb9 commit 73db1b6

3 files changed

Lines changed: 86 additions & 2 deletions

File tree

config/config.php.dist

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,28 @@ $config = [
12261226
'store.redis.username' => '',
12271227
'store.redis.password' => '',
12281228

1229+
/*
1230+
* Communicate with Redis over a secure connection instead of plain TCP.
1231+
*
1232+
* This setting affects both single host connections as
1233+
* well as Sentinel mode.
1234+
*/
1235+
'store.redis.tls' => false,
1236+
1237+
/*
1238+
* Verify the Redis server certificate.
1239+
*/
1240+
'store.redis.insecure' => false,
1241+
1242+
/*
1243+
* Files related to secure communication with Redis.
1244+
*
1245+
* Files are searched in the 'certdir' when using relative paths.
1246+
*/
1247+
'store.redis.ca_certificate' => null,
1248+
'store.redis.certificate' => null,
1249+
'store.redis.privatekey' => null,
1250+
12291251
/*
12301252
* The prefix we should use on our Redis datastore.
12311253
*/
@@ -1244,6 +1266,9 @@ $config = [
12441266
* 'tcp://[yoursentinel2]:[port]',
12451267
* 'tcp://[yoursentinel3]:[port]
12461268
* ],
1269+
*
1270+
* Use 'tls' instead of 'tcp' in order to make use of the additional
1271+
* TLS settings.
12471272
*/
12481273
'store.redis.sentinels' => [],
12491274

src/SimpleSAML/Store/RedisStore.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Predis\Client;
88
use SimpleSAML\Assert\Assert;
9-
use SimpleSAML\{Configuration, Error};
9+
use SimpleSAML\{Configuration, Error, Utils};
1010

1111
use function class_exists;
1212
use function serialize;
@@ -45,17 +45,44 @@ public function __construct(Client $redis = null)
4545
$password = $config->getOptionalString('store.redis.password', null);
4646
$username = $config->getOptionalString('store.redis.username', null);
4747
$database = $config->getOptionalInteger('store.redis.database', 0);
48+
$tls = $config->getOptionalBoolean('store.redis.tls', false);
49+
$scheme = $tls ? 'tls' : 'tcp';
50+
$ssl = [];
4851

4952
$sentinels = $config->getOptionalArray('store.redis.sentinels', []);
5053

54+
if ($tls) {
55+
$configUtils = new Utils\Config();
56+
57+
if ($config->getOptionalBoolean('store.redis.insecure', false)) {
58+
$ssl['verify_peer'] = false;
59+
$ssl['verify_peer_name'] = false;
60+
} else {
61+
$ca = $config->getOptionalString('store.redis.ca_certificate', null);
62+
63+
if ($ca !== null) {
64+
$ssl['cafile'] = $configUtils->getCertPath($ca);
65+
}
66+
}
67+
68+
$cert = $config->getOptionalString('store.redis.certificate', null);
69+
$key = $config->getOptionalString('store.redis.privatekey', null);
70+
71+
if ($cert !== null && $key !== null) {
72+
$ssl['local_cert'] = $configUtils->getCertPath($cert);
73+
$ssl['local_pk'] = $configUtils->getCertPath($key);
74+
}
75+
}
76+
5177
if (empty($sentinels)) {
5278
$redis = new Client(
5379
[
54-
'scheme' => 'tcp',
80+
'scheme' => $scheme,
5581
'host' => $host,
5682
'port' => $port,
5783
'database' => $database,
5884
]
85+
+ (!empty($ssl) ? ['ssl' => $ssl] : [])
5986
+ (!empty($username) ? ['username' => $username] : [])
6087
+ (!empty($password) ? ['password' => $password] : []),
6188
[
@@ -73,6 +100,7 @@ public function __construct(Client $redis = null)
73100
'parameters' => [
74101
'database' => $database,
75102
]
103+
+ (!empty($ssl) ? ['ssl' => $ssl] : [])
76104
+ (!empty($username) ? ['username' => $username] : [])
77105
+ (!empty($password) ? ['password' => $password] : []),
78106
]

tests/src/SimpleSAML/Store/RedisStoreTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,37 @@ public function testRedisInstance(): void
113113
$this->assertInstanceOf(Store\RedisStore::class, $this->store);
114114
}
115115

116+
/**
117+
* @test
118+
*/
119+
public function testRedisInstanceWithInsecureTLS(): void
120+
{
121+
$config = Configuration::loadFromArray([
122+
'store.type' => 'redis',
123+
'store.redis.prefix' => 'phpunit_',
124+
'store.redis.tls' => true,
125+
'store.redis.insecure' => true,
126+
], '[ARRAY]', 'simplesaml');
127+
128+
$this->assertInstanceOf(Store\RedisStore::class, $this->store);
129+
}
130+
131+
/**
132+
* @test
133+
*/
134+
public function testRedisInstanceWithSecureTLS(): void
135+
{
136+
$config = Configuration::loadFromArray([
137+
'store.type' => 'redis',
138+
'store.redis.prefix' => 'phpunit_',
139+
'store.redis.tls' => true,
140+
'store.redis.ca_certificate' => '/tmp/ssl/pki_roots.crt.pem',
141+
'store.redis.certificate' => '/tmp/ssl/phpunit.crt.pem',
142+
'store.redis.privatekey' => '/tmp/ssl/phpunit.key.pem',
143+
], '[ARRAY]', 'simplesaml');
144+
145+
$this->assertInstanceOf(Store\RedisStore::class, $this->store);
146+
}
116147

117148
/**
118149
* @test

0 commit comments

Comments
 (0)