summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Cillario <luca.cillario.95@gmail.com>2022-08-30 01:07:28 +0200
committerGitHub <noreply@github.com>2022-08-30 02:07:28 +0300
commitbd0e8f26d8af5722a8b040bed6a75831bade81df (patch)
tree080326627cbf210ffb779a8420646074c6bb6d2a
parentfb54bddae9d460e227bfff77724e066b4a0ca522 (diff)
downloadredis-py-bd0e8f26d8af5722a8b040bed6a75831bade81df.tar.gz
Handle auth errors for newer versions of Redis. (#2325) (#2329)
-rw-r--r--redis/asyncio/connection.py11
-rwxr-xr-xredis/connection.py12
-rw-r--r--tests/test_commands.py26
-rw-r--r--tests/test_connection_pool.py28
4 files changed, 67 insertions, 10 deletions
diff --git a/redis/asyncio/connection.py b/redis/asyncio/connection.py
index 6823dcb..db8c240 100644
--- a/redis/asyncio/connection.py
+++ b/redis/asyncio/connection.py
@@ -87,6 +87,15 @@ MODULE_EXPORTS_DATA_TYPES_ERROR = (
"exports one or more module-side data "
"types, can't unload"
)
+# user send an AUTH cmd to a server without authorization configured
+NO_AUTH_SET_ERROR = {
+ # Redis >= 6.0
+ "AUTH <password> called without any password "
+ "configured for the default user. Are you sure "
+ "your configuration is correct?": AuthenticationError,
+ # Redis < 6.0
+ "Client sent AUTH, but no password is set": AuthenticationError,
+}
class _HiredisReaderArgs(TypedDict, total=False):
@@ -160,7 +169,9 @@ class BaseParser:
MODULE_EXPORTS_DATA_TYPES_ERROR: ModuleError,
NO_SUCH_MODULE_ERROR: ModuleError,
MODULE_UNLOAD_NOT_POSSIBLE_ERROR: ModuleError,
+ **NO_AUTH_SET_ERROR,
},
+ "WRONGPASS": AuthenticationError,
"EXECABORT": ExecAbortError,
"LOADING": BusyLoadingError,
"NOSCRIPT": NoScriptError,
diff --git a/redis/connection.py b/redis/connection.py
index 96645ba..3281b14 100755
--- a/redis/connection.py
+++ b/redis/connection.py
@@ -80,6 +80,15 @@ MODULE_EXPORTS_DATA_TYPES_ERROR = (
"exports one or more module-side data "
"types, can't unload"
)
+# user send an AUTH cmd to a server without authorization configured
+NO_AUTH_SET_ERROR = {
+ # Redis >= 6.0
+ "AUTH <password> called without any password "
+ "configured for the default user. Are you sure "
+ "your configuration is correct?": AuthenticationError,
+ # Redis < 6.0
+ "Client sent AUTH, but no password is set": AuthenticationError,
+}
class Encoder:
@@ -127,7 +136,6 @@ class BaseParser:
EXCEPTION_CLASSES = {
"ERR": {
"max number of clients reached": ConnectionError,
- "Client sent AUTH, but no password is set": AuthenticationError,
"invalid password": AuthenticationError,
# some Redis server versions report invalid command syntax
# in lowercase
@@ -141,7 +149,9 @@ class BaseParser:
MODULE_EXPORTS_DATA_TYPES_ERROR: ModuleError,
NO_SUCH_MODULE_ERROR: ModuleError,
MODULE_UNLOAD_NOT_POSSIBLE_ERROR: ModuleError,
+ **NO_AUTH_SET_ERROR,
},
+ "WRONGPASS": AuthenticationError,
"EXECABORT": ExecAbortError,
"LOADING": BusyLoadingError,
"NOSCRIPT": NoScriptError,
diff --git a/tests/test_commands.py b/tests/test_commands.py
index de8020c..1c9a5c2 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -68,6 +68,14 @@ class TestResponseCallbacks:
class TestRedisCommands:
@skip_if_redis_enterprise()
def test_auth(self, r, request):
+ # sending an AUTH command before setting a user/password on the
+ # server should return an AuthenticationError
+ with pytest.raises(exceptions.AuthenticationError):
+ r.auth("some_password")
+
+ with pytest.raises(exceptions.AuthenticationError):
+ r.auth("some_password", "some_user")
+
# first, test for default user (`username` is supposed to be optional)
default_username = "default"
temp_pass = "temp_pass"
@@ -81,9 +89,19 @@ class TestRedisCommands:
def teardown():
try:
- r.auth(temp_pass)
- except exceptions.ResponseError:
- r.auth("default", "")
+ # this is needed because after an AuthenticationError the connection
+ # is closed, and if we send an AUTH command a new connection is
+ # created, but in this case we'd get an "Authentication required"
+ # error when switching to the db 9 because we're not authenticated yet
+ # setting the password on the connection itself triggers the
+ # authentication in the connection's `on_connect` method
+ r.connection.password = temp_pass
+ except AttributeError:
+ # connection field is not set in Redis Cluster, but that's ok
+ # because the problem discussed above does not apply to Redis Cluster
+ pass
+
+ r.auth(temp_pass)
r.config_set("requirepass", "")
r.acl_deluser(username)
@@ -95,7 +113,7 @@ class TestRedisCommands:
assert r.auth(username=username, password="strong_password") is True
- with pytest.raises(exceptions.ResponseError):
+ with pytest.raises(exceptions.AuthenticationError):
r.auth(username=username, password="wrong_password")
def test_command_on_invalid_key_type(self, r):
diff --git a/tests/test_connection_pool.py b/tests/test_connection_pool.py
index 636b04e..73eb6e1 100644
--- a/tests/test_connection_pool.py
+++ b/tests/test_connection_pool.py
@@ -553,22 +553,40 @@ class TestConnection:
)
@skip_if_redis_enterprise()
- def test_connect_no_auth_supplied_when_required(self, r):
+ def test_connect_no_auth_configured(self, r):
"""
- AuthenticationError should be raised when the server requires a
- password but one isn't supplied.
+ AuthenticationError should be raised when the server is not configured with auth
+ but credentials are supplied by the user.
"""
+ # Redis < 6
with pytest.raises(redis.AuthenticationError):
r.execute_command(
"DEBUG", "ERROR", "ERR Client sent AUTH, but no password is set"
)
+ # Redis >= 6
+ with pytest.raises(redis.AuthenticationError):
+ r.execute_command(
+ "DEBUG",
+ "ERROR",
+ "ERR AUTH <password> called without any password "
+ "configured for the default user. Are you sure "
+ "your configuration is correct?",
+ )
+
@skip_if_redis_enterprise()
- def test_connect_invalid_password_supplied(self, r):
- "AuthenticationError should be raised when sending the wrong password"
+ def test_connect_invalid_auth_credentials_supplied(self, r):
+ """
+ AuthenticationError should be raised when sending invalid username/password
+ """
+ # Redis < 6
with pytest.raises(redis.AuthenticationError):
r.execute_command("DEBUG", "ERROR", "ERR invalid password")
+ # Redis >= 6
+ with pytest.raises(redis.AuthenticationError):
+ r.execute_command("DEBUG", "ERROR", "WRONGPASS")
+
@pytest.mark.onlynoncluster
class TestMultiConnectionClient: