Skip to content

Commit 37b7d2a

Browse files
nerdrewbyroot
authored andcommitted
Close connection when authentication fails
1 parent 7655bb8 commit 37b7d2a

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- Entirely close the connection on authentication failures.
4+
35
# 0.26.2
46

57
- Fix compatibility with `connection_pool` version 3+.

lib/redis_client.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,13 +843,16 @@ def connect
843843
end
844844
end
845845
rescue FailoverError, CannotConnectError => error
846+
@raw_connection&.close
846847
error._set_config(config)
847848
raise error
848849
rescue ConnectionError => error
850+
@raw_connection&.close
849851
connect_error = CannotConnectError.with_config(error.message, config)
850852
connect_error.set_backtrace(error.backtrace)
851853
raise connect_error
852854
rescue CommandError => error
855+
@raw_connection&.close
853856
if error.message.match?(/ERR unknown command ['`]HELLO['`]/)
854857
raise UnsupportedServer,
855858
"redis-client requires Redis 6+ with HELLO command available (#{config.server_url})"

test/shared/redis_client_tests.rb

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,12 @@ def test_command_missing
328328
end
329329

330330
def test_authentication
331-
@redis.call("ACL", "SETUSER", "AzureDiamond", ">hunter2", "on", "+PING")
331+
@redis.call("ACL", "DELUSER", "AzureDiamond")
332+
@redis.call("ACL", "SETUSER", "AzureDiamond", ">hunter2", "on", "+PING", "+CLIENT")
333+
@redis.call("ACL", "DELUSER", "backup_admin")
334+
@redis.call("ACL", "SETUSER", "backup_admin", ">hunter2", "on", "~*", "&*", "+@all")
335+
backup = new_client(username: "backup_admin", password: "hunter2")
336+
backup.call("ACL", "SETUSER", "default", "off")
332337

333338
client = new_client(username: "AzureDiamond", password: "hunter2")
334339
assert_equal "PONG", client.call("PING")
@@ -337,10 +342,72 @@ def test_authentication
337342
client.call("GET", "foo")
338343
end
339344

345+
# Wrong password
340346
client = new_client(username: "AzureDiamond", password: "trolilol")
341-
assert_raises RedisClient::AuthenticationError do
347+
error = assert_raises RedisClient::AuthenticationError do
342348
client.call("PING")
343349
end
350+
assert_match(/WRONGPASS invalid username-password pair/, error.message)
351+
352+
# The same error is raised, this shows that the client retried AUTH and didn't fall back to the default user
353+
error = assert_raises RedisClient::AuthenticationError do
354+
client.call("PING")
355+
end
356+
assert_match(/WRONGPASS invalid username-password pair/, error.message)
357+
358+
# Correct password, but user disabled
359+
@redis.call("ACL", "DELUSER", "AnotherUser")
360+
backup.call("ACL", "SETUSER", "AnotherUser", ">boom", "off", "+PING", "+CLIENT")
361+
client = new_client(username: "AnotherUser", password: "boom")
362+
error = assert_raises RedisClient::AuthenticationError do
363+
client.call_once("PING")
364+
end
365+
assert_match(/WRONGPASS invalid username-password pair/, error.message)
366+
367+
# Correct password, user enabled
368+
backup.call("ACL", "SETUSER", "AnotherUser", "on")
369+
assert_equal "PONG", client.call_once("PING")
370+
assert_match(/user=AnotherUser/, client.call("CLIENT", "INFO"))
371+
372+
# Wrong username
373+
client = new_client(username: "GreenOpal", password: "boom")
374+
error = assert_raises RedisClient::AuthenticationError do
375+
client.call("PING")
376+
end
377+
assert_match(/WRONGPASS invalid username-password pair/, error.message)
378+
ensure
379+
backup.call("ACL", "SETUSER", "default", "on")
380+
end
381+
382+
def test_prelude_failure
383+
client = new_client(db: 100)
384+
error = assert_raises RedisClient::CommandError do
385+
client.call("PING")
386+
end
387+
assert_match(/ERR DB index is out of range/, error.message)
388+
389+
error = assert_raises RedisClient::CommandError do
390+
client.call("PING")
391+
end
392+
assert_match(/ERR DB index is out of range/, error.message)
393+
end
394+
395+
def test_noauth
396+
@redis.call("ACL", "DELUSER", "AzureDiamond")
397+
@redis.call("ACL", "SETUSER", "AzureDiamond", ">hunter2", "on", "~*", "&*", "+@all")
398+
backup = new_client(username: "AzureDiamond", password: "hunter2")
399+
backup.call("ACL", "SETUSER", "default", "off")
400+
401+
client = new_client(protocol: 2)
402+
error = assert_raises RedisClient::CommandError do
403+
client.call("PING")
404+
end
405+
assert_match(/NOAUTH Authentication required/, error.message)
406+
407+
backup.call("ACL", "SETUSER", "default", "on")
408+
client.call("PING")
409+
ensure
410+
backup.call("ACL", "SETUSER", "default", "on")
344411
end
345412

346413
def test_transaction

0 commit comments

Comments
 (0)