Skip to content

WRONGPASS response doesn't raise AuthenticationError exception #2329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions redis/asyncio/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ class _Sentinel(enum.Enum):
"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):
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 11 additions & 1 deletion redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@
"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:
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
26 changes: 22 additions & 4 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ def test_case_insensitive_command_names(self, r):
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"
Expand All @@ -81,9 +89,19 @@ def test_auth(self, r, request):

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)

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

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):
Expand Down
28 changes: 23 additions & 5 deletions tests/test_connection_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,22 +545,40 @@ def test_connect_from_url_unix(self):
)

@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:
Expand Down