summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES9
-rw-r--r--redis/__init__.py2
-rwxr-xr-xredis/connection.py16
-rw-r--r--redis/exceptions.py8
4 files changed, 34 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index b0641e9..bbf51e8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+* 3.4.1 (in development)
+ * Prior to ACL support, redis-py ignored the username component of
+ Connection URLs. With ACL support, usernames are no longer ignored and
+ are used to authenticate against an ACL rule. Some cloud vendors with
+ managed Redis instances (like Heroku) provide connection URLs with a
+ username component pre-ACL that is not intended to be used. Sending that
+ username to Redis servers < 6.0.0 results in an error. Attempt to detect
+ this condition and retry the AUTH command with only the password such
+ that authentication continues to work for these users. #1274
* 3.4.0
* Allow empty pipelines to be executed if there are WATCHed keys.
This is a convenient way to test if any of the watched keys changed
diff --git a/redis/__init__.py b/redis/__init__.py
index 369d39e..57deb86 100644
--- a/redis/__init__.py
+++ b/redis/__init__.py
@@ -9,6 +9,7 @@ from redis.connection import (
from redis.utils import from_url
from redis.exceptions import (
AuthenticationError,
+ AuthenticationWrongNumberOfArgsError,
BusyLoadingError,
ChildDeadlockedError,
ConnectionError,
@@ -35,6 +36,7 @@ VERSION = tuple(map(int_or_str, __version__.split('.')))
__all__ = [
'AuthenticationError',
+ 'AuthenticationWrongNumberOfArgsError',
'BlockingConnectionPool',
'BusyLoadingError',
'ChildDeadlockedError',
diff --git a/redis/connection.py b/redis/connection.py
index 7efb0a2..a013145 100755
--- a/redis/connection.py
+++ b/redis/connection.py
@@ -17,6 +17,7 @@ from redis._compat import (xrange, imap, byte_to_chr, unicode, long,
sendall, shutdown, ssl_wrap_socket)
from redis.exceptions import (
AuthenticationError,
+ AuthenticationWrongNumberOfArgsError,
BusyLoadingError,
ChildDeadlockedError,
ConnectionError,
@@ -135,6 +136,8 @@ class BaseParser(object):
'max number of clients reached': ConnectionError,
'Client sent AUTH, but no password is set': AuthenticationError,
'invalid password': AuthenticationError,
+ 'wrong number of arguments for \'auth\' command':
+ AuthenticationWrongNumberOfArgsError,
},
'EXECABORT': ExecAbortError,
'LOADING': BusyLoadingError,
@@ -630,7 +633,18 @@ class Connection(object):
# avoid checking health here -- PING will fail if we try
# to check the health prior to the AUTH
self.send_command('AUTH', *auth_args, check_health=False)
- if nativestr(self.read_response()) != 'OK':
+
+ try:
+ auth_response = self.read_response()
+ except AuthenticationWrongNumberOfArgsError:
+ # a username and password were specified but the Redis
+ # server seems to be < 6.0.0 which expects a single password
+ # arg. retry auth with just the password.
+ # https://github.com/andymccurdy/redis-py/issues/1274
+ self.send_command('AUTH', self.password, check_health=False)
+ auth_response = self.read_response()
+
+ if nativestr(auth_response) != 'OK':
raise AuthenticationError('Invalid Username or Password')
# if a client_name is given, set it
diff --git a/redis/exceptions.py b/redis/exceptions.py
index 6f47024..760af66 100644
--- a/redis/exceptions.py
+++ b/redis/exceptions.py
@@ -72,3 +72,11 @@ class LockNotOwnedError(LockError):
class ChildDeadlockedError(Exception):
"Error indicating that a child process is deadlocked after a fork()"
pass
+
+
+class AuthenticationWrongNumberOfArgsError(ResponseError):
+ """
+ An error to indicate that the wrong number of args
+ were sent to the AUTH command
+ """
+ pass