Skip to content

Commit 0b5afb2

Browse files
committed
Decode and document URL-encoded passwords
1 parent 41bda5e commit 0b5afb2

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,13 @@ $factory->createClient('redis://localhost:6379');
134134

135135
Redis supports password-based authentication (`AUTH` command). Note that Redis'
136136
authentication mechanism does not employ a username, so you can pass the
137-
password "secret" as part of the URI like this:
137+
password `h@llo` URL-encoded (percent-encoded) as part of the URI like this:
138138

139139
```php
140-
// both forms are equivalent
141-
$factory->createClient('redis://ignored:secret@localhost');
142-
$factory->createClient('redis://localhost?password=secret');
140+
// all forms are equivalent
141+
$factory->createClient('redis://:h%40llo@localhost');
142+
$factory->createClient('redis://ignored:h%40llo@localhost');
143+
$factory->createClient('redis://localhost?password=h%40llo');
143144
```
144145

145146
> Legacy notice: The `redis://` scheme is defined and preferred as of `v1.2.0`.

src/Factory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ private function parseUrl($target)
123123

124124
$auth = null;
125125
if (isset($parts['user']) && $parts['scheme'] === 'tcp') {
126-
$auth = $parts['user'];
126+
$auth = rawurldecode($parts['user']);
127127
}
128128
if (isset($parts['pass'])) {
129-
$auth .= ($parts['scheme'] === 'tcp' ? ':' : '') . $parts['pass'];
129+
$auth .= ($parts['scheme'] === 'tcp' ? ':' : '') . rawurldecode($parts['pass']);
130130
}
131131
if ($auth !== null) {
132132
$parts['auth'] = $auth;

tests/FactoryTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ public function testWillWriteAuthCommandIfRedisUriContainsUserInfo()
8686
$this->factory->createClient('redis://hello:[email protected]');
8787
}
8888

89+
public function testWillWriteAuthCommandIfRedisUriContainsEncodedUserInfo()
90+
{
91+
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
92+
$stream->expects($this->once())->method('write')->with("*2\r\n$4\r\nauth\r\n$5\r\nh@llo\r\n");
93+
94+
$this->connector->expects($this->once())->method('connect')->with('example.com:6379')->willReturn(Promise\resolve($stream));
95+
$this->factory->createClient('redis://:h%[email protected]');
96+
}
97+
8998
public function testWillWriteAuthCommandIfTargetContainsPasswordQueryParameter()
9099
{
91100
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
@@ -95,6 +104,15 @@ public function testWillWriteAuthCommandIfTargetContainsPasswordQueryParameter()
95104
$this->factory->createClient('redis://example.com?password=secret');
96105
}
97106

107+
public function testWillWriteAuthCommandIfTargetContainsEncodedPasswordQueryParameter()
108+
{
109+
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
110+
$stream->expects($this->once())->method('write')->with("*2\r\n$4\r\nauth\r\n$5\r\nh@llo\r\n");
111+
112+
$this->connector->expects($this->once())->method('connect')->with('example.com:6379')->willReturn(Promise\resolve($stream));
113+
$this->factory->createClient('redis://example.com?password=h%40llo');
114+
}
115+
98116
public function testWillWriteAuthCommandIfRedissUriContainsUserInfo()
99117
{
100118
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();

0 commit comments

Comments
 (0)