From ee56982176ebcb8ad6acd51b7cddbc6b0a9de1dd Mon Sep 17 00:00:00 2001 From: Lorenzo Nicoletti Date: Fri, 25 Oct 2019 21:28:45 +0200 Subject: [PATCH] Enable encrypted connections with TLS (#129) * Enable encrypted connections with TLS Use standalone PHP driver because PHP Redis extension doesn't work with TLS. Syntax `$redis = new Credis_Client('tls://host[:port][/persistence_identifier]')` * Enable encrypted connections with TLS --- Client.php | 27 ++++++++++++++++++++++----- README.markdown | 33 +++++++++++++++++++++++++++++++++ tests/CredisTest.php | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/Client.php b/Client.php index 9ee63e0..b814753 100755 --- a/Client.php +++ b/Client.php @@ -189,6 +189,12 @@ class Credis_Client { */ protected $host; + /** + * Scheme of the Redis server (tcp, tls, unix) + * @var string + */ + protected $scheme; + /** * Port on which the Redis server is running * @var integer @@ -310,12 +316,17 @@ public function __construct($host = '127.0.0.1', $port = 6379, $timeout = null, { $this->host = (string) $host; $this->port = (int) $port; + $this->scheme = null; $this->timeout = $timeout; $this->persistent = (string) $persistent; $this->standalone = ! extension_loaded('redis'); $this->authPassword = $password; $this->selectedDb = (int)$db; $this->convertHost(); + if ($this->scheme == 'tls') { + // PHP Redis extension doesn't work with TLS + $this->standalone = true; + } } public function __destruct() @@ -402,10 +413,11 @@ public function setCloseOnDestruct($flag) } protected function convertHost() { - if (preg_match('#^(tcp|unix)://(.*)$#', $this->host, $matches)) { - if($matches[1] == 'tcp') { + if (preg_match('#^(tcp|tls|unix)://(.*)$#', $this->host, $matches)) { + if($matches[1] == 'tcp' || $matches[1] == 'tls') { + $this->scheme = $matches[1]; if ( ! preg_match('#^([^:]+)(:([0-9]+))?(/(.+))?$#', $matches[2], $matches)) { - throw new CredisException('Invalid host format; expected tcp://host[:port][/persistence_identifier]'); + throw new CredisException('Invalid host format; expected '.$this->scheme.'://host[:port][/persistence_identifier]'); } $this->host = $matches[1]; $this->port = (int) (isset($matches[3]) ? $matches[3] : 6379); @@ -413,6 +425,7 @@ protected function convertHost() } else { $this->host = $matches[2]; $this->port = NULL; + $this->scheme = 'unix'; if (substr($this->host,0,1) != '/') { throw new CredisException('Invalid unix socket format; expected unix:///path/to/redis.sock'); } @@ -420,6 +433,10 @@ protected function convertHost() } if ($this->port !== NULL && substr($this->host,0,1) == '/') { $this->port = NULL; + $this->scheme = 'unix'; + } + if (!$this->scheme) { + $this->scheme = 'tcp'; } } /** @@ -436,8 +453,8 @@ public function connect() if ($this->standalone) { $flags = STREAM_CLIENT_CONNECT; $remote_socket = $this->port === NULL - ? 'unix://'.$this->host - : 'tcp://'.$this->host.':'.$this->port; + ? $this->scheme.'://'.$this->host + : $this->scheme.'://'.$this->host.':'.$this->port; if ($this->persistent && $this->port !== NULL) { // Persistent connections to UNIX sockets are not supported $remote_socket .= '/'.$this->persistent; diff --git a/README.markdown b/README.markdown index 3c727c4..2e3bdc1 100644 --- a/README.markdown +++ b/README.markdown @@ -26,6 +26,39 @@ Credis_Client also supports transparent command renaming. Write code using the o client will send the aliased commands to the server transparently. Specify the renamed commands using a prefix for md5, a callable function, individual aliases, or an array map of aliases. See "Redis Security":http://redis.io/topics/security for more info. +## Supported connection string formats + +```php +$redis = new Credis_Client(/* connection string */); +``` + +### Unix socket connection string + +`unix:///path/to/redis.sock` + +### TCP connection string + +`tcp://host[:port][/persistence_identifier]` + +### TLS connection string + +`tls://host[:port][/persistence_identifier]` + +#### Enable transport level security (TLS) + +Use TLS connection string `tls://127.0.0.1:6379` instead of TCP connection `tcp://127.0.0.1:6379` string in order to enable transport level security. + +```php +require 'Credis/Client.php'; +$redis = new Credis_Client('tls://127.0.0.1:6379'); +$redis->set('awesome', 'absolutely'); +echo sprintf('Is Credis awesome? %s.\n', $redis->get('awesome')); + +// When arrays are given as arguments they are flattened automatically +$redis->rpush('particles', array('proton','electron','neutron')); +$particles = $redis->lrange('particles', 0, -1); +``` + ## Clustering your servers Credis also includes a way for developers to fully utilize the scalability of Redis with multiple servers and [consistent hashing](http://en.wikipedia.org/wiki/Consistent_hashing). diff --git a/tests/CredisTest.php b/tests/CredisTest.php index b502692..7169769 100644 --- a/tests/CredisTest.php +++ b/tests/CredisTest.php @@ -651,6 +651,27 @@ public function testConnectionStrings() $this->assertEquals('abc123',$this->credis->getPersistence()); } + public function testConnectionStringsTls() + { + $this->credis->close(); + $this->credis = new Credis_Client('tls://'.$this->redisConfig[0]['host'] . ':' . $this->redisConfig[0]['port']); + if ($this->useStandalone) { + $this->credis->forceStandalone(); + } + $this->assertEquals($this->credis->getHost(),$this->redisConfig[0]['host']); + $this->assertEquals($this->credis->getPort(),$this->redisConfig[0]['port']); + $this->credis = new Credis_Client('tls://'.$this->redisConfig[0]['host']); + if ($this->useStandalone) { + $this->credis->forceStandalone(); + } + $this->assertEquals($this->credis->getPort(),$this->redisConfig[0]['port']); + $this->credis = new Credis_Client('tls://'.$this->redisConfig[0]['host'] . ':' . $this->redisConfig[0]['port'] . '/abc123'); + if ($this->useStandalone) { + $this->credis->forceStandalone(); + } + $this->assertEquals('abc123',$this->credis->getPersistence()); + } + /** * @group UnixSocket */ @@ -665,7 +686,7 @@ public function testConnectionStringsSocket() $this->assertEquals('value',$this->credis->get('key')); } - public function testInvalidTcpConnectionstring() + public function testInvalidTcpConnectionString() { $this->credis->close(); $this->setExpectedExceptionShim('CredisException','Invalid host format; expected tcp://host[:port][/persistence_identifier]'); @@ -675,7 +696,17 @@ public function testInvalidTcpConnectionstring() } } - public function testInvalidUnixSocketConnectionstring() + public function testInvalidTlsConnectionString() + { + $this->credis->close(); + $this->setExpectedExceptionShim('CredisException','Invalid host format; expected tls://host[:port][/persistence_identifier]'); + $this->credis = new Credis_Client('tls://'.$this->redisConfig[0]['host'] . ':abc'); + if ($this->useStandalone) { + $this->credis->forceStandalone(); + } + } + + public function testInvalidUnixSocketConnectionString() { $this->credis->close(); $this->setExpectedExceptionShim('CredisException','Invalid unix socket format; expected unix:///path/to/redis.sock');