Skip to content

Commit bd0e8f2

Browse files
authored
Handle auth errors for newer versions of Redis. (#2325) (#2329)
1 parent fb54bdd commit bd0e8f2

File tree

4 files changed

+67
-10
lines changed

4 files changed

+67
-10
lines changed

redis/asyncio/connection.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ class _Sentinel(enum.Enum):
8787
"exports one or more module-side data "
8888
"types, can't unload"
8989
)
90+
# user send an AUTH cmd to a server without authorization configured
91+
NO_AUTH_SET_ERROR = {
92+
# Redis >= 6.0
93+
"AUTH <password> called without any password "
94+
"configured for the default user. Are you sure "
95+
"your configuration is correct?": AuthenticationError,
96+
# Redis < 6.0
97+
"Client sent AUTH, but no password is set": AuthenticationError,
98+
}
9099

91100

92101
class _HiredisReaderArgs(TypedDict, total=False):
@@ -160,7 +169,9 @@ class BaseParser:
160169
MODULE_EXPORTS_DATA_TYPES_ERROR: ModuleError,
161170
NO_SUCH_MODULE_ERROR: ModuleError,
162171
MODULE_UNLOAD_NOT_POSSIBLE_ERROR: ModuleError,
172+
**NO_AUTH_SET_ERROR,
163173
},
174+
"WRONGPASS": AuthenticationError,
164175
"EXECABORT": ExecAbortError,
165176
"LOADING": BusyLoadingError,
166177
"NOSCRIPT": NoScriptError,

redis/connection.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@
8080
"exports one or more module-side data "
8181
"types, can't unload"
8282
)
83+
# user send an AUTH cmd to a server without authorization configured
84+
NO_AUTH_SET_ERROR = {
85+
# Redis >= 6.0
86+
"AUTH <password> called without any password "
87+
"configured for the default user. Are you sure "
88+
"your configuration is correct?": AuthenticationError,
89+
# Redis < 6.0
90+
"Client sent AUTH, but no password is set": AuthenticationError,
91+
}
8392

8493

8594
class Encoder:
@@ -127,7 +136,6 @@ class BaseParser:
127136
EXCEPTION_CLASSES = {
128137
"ERR": {
129138
"max number of clients reached": ConnectionError,
130-
"Client sent AUTH, but no password is set": AuthenticationError,
131139
"invalid password": AuthenticationError,
132140
# some Redis server versions report invalid command syntax
133141
# in lowercase
@@ -141,7 +149,9 @@ class BaseParser:
141149
MODULE_EXPORTS_DATA_TYPES_ERROR: ModuleError,
142150
NO_SUCH_MODULE_ERROR: ModuleError,
143151
MODULE_UNLOAD_NOT_POSSIBLE_ERROR: ModuleError,
152+
**NO_AUTH_SET_ERROR,
144153
},
154+
"WRONGPASS": AuthenticationError,
145155
"EXECABORT": ExecAbortError,
146156
"LOADING": BusyLoadingError,
147157
"NOSCRIPT": NoScriptError,

tests/test_commands.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ def test_case_insensitive_command_names(self, r):
6868
class TestRedisCommands:
6969
@skip_if_redis_enterprise()
7070
def test_auth(self, r, request):
71+
# sending an AUTH command before setting a user/password on the
72+
# server should return an AuthenticationError
73+
with pytest.raises(exceptions.AuthenticationError):
74+
r.auth("some_password")
75+
76+
with pytest.raises(exceptions.AuthenticationError):
77+
r.auth("some_password", "some_user")
78+
7179
# first, test for default user (`username` is supposed to be optional)
7280
default_username = "default"
7381
temp_pass = "temp_pass"
@@ -81,9 +89,19 @@ def test_auth(self, r, request):
8189

8290
def teardown():
8391
try:
84-
r.auth(temp_pass)
85-
except exceptions.ResponseError:
86-
r.auth("default", "")
92+
# this is needed because after an AuthenticationError the connection
93+
# is closed, and if we send an AUTH command a new connection is
94+
# created, but in this case we'd get an "Authentication required"
95+
# error when switching to the db 9 because we're not authenticated yet
96+
# setting the password on the connection itself triggers the
97+
# authentication in the connection's `on_connect` method
98+
r.connection.password = temp_pass
99+
except AttributeError:
100+
# connection field is not set in Redis Cluster, but that's ok
101+
# because the problem discussed above does not apply to Redis Cluster
102+
pass
103+
104+
r.auth(temp_pass)
87105
r.config_set("requirepass", "")
88106
r.acl_deluser(username)
89107

@@ -95,7 +113,7 @@ def teardown():
95113

96114
assert r.auth(username=username, password="strong_password") is True
97115

98-
with pytest.raises(exceptions.ResponseError):
116+
with pytest.raises(exceptions.AuthenticationError):
99117
r.auth(username=username, password="wrong_password")
100118

101119
def test_command_on_invalid_key_type(self, r):

tests/test_connection_pool.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -553,22 +553,40 @@ def test_connect_from_url_unix(self):
553553
)
554554

555555
@skip_if_redis_enterprise()
556-
def test_connect_no_auth_supplied_when_required(self, r):
556+
def test_connect_no_auth_configured(self, r):
557557
"""
558-
AuthenticationError should be raised when the server requires a
559-
password but one isn't supplied.
558+
AuthenticationError should be raised when the server is not configured with auth
559+
but credentials are supplied by the user.
560560
"""
561+
# Redis < 6
561562
with pytest.raises(redis.AuthenticationError):
562563
r.execute_command(
563564
"DEBUG", "ERROR", "ERR Client sent AUTH, but no password is set"
564565
)
565566

567+
# Redis >= 6
568+
with pytest.raises(redis.AuthenticationError):
569+
r.execute_command(
570+
"DEBUG",
571+
"ERROR",
572+
"ERR AUTH <password> called without any password "
573+
"configured for the default user. Are you sure "
574+
"your configuration is correct?",
575+
)
576+
566577
@skip_if_redis_enterprise()
567-
def test_connect_invalid_password_supplied(self, r):
568-
"AuthenticationError should be raised when sending the wrong password"
578+
def test_connect_invalid_auth_credentials_supplied(self, r):
579+
"""
580+
AuthenticationError should be raised when sending invalid username/password
581+
"""
582+
# Redis < 6
569583
with pytest.raises(redis.AuthenticationError):
570584
r.execute_command("DEBUG", "ERROR", "ERR invalid password")
571585

586+
# Redis >= 6
587+
with pytest.raises(redis.AuthenticationError):
588+
r.execute_command("DEBUG", "ERROR", "WRONGPASS")
589+
572590

573591
@pytest.mark.onlynoncluster
574592
class TestMultiConnectionClient:

0 commit comments

Comments
 (0)