From be82c0b2fa1df75a5361ed677e91fc532b2395f9 Mon Sep 17 00:00:00 2001 From: Kurdakov Alexander <kusancho12@gmail.com> Date: Thu, 12 Sep 2024 21:46:26 +0300 Subject: [PATCH] fix: do not ban admin console Do not ban admin console via unix socket after several failed attempts via `picodata connect`. --- CHANGELOG.md | 2 ++ src/lib.rs | 10 +++++++- test/int/test_cli_ux.py | 56 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a12449521..5c93ed5148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,8 @@ which improves perfomance - Fix error "Read access to space '_raft_state' is denied" when executing a DML query on global tables +- Fix error "Maximum number of login attempts exceeded" in picodata admin + ### Compatibility - The current version is NOT compatible with prior releases. It cannot diff --git a/src/lib.rs b/src/lib.rs index 3604cc3e43..cb2e810bca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -453,7 +453,15 @@ fn set_login_check(storage: Clusterwide) { let lua = ::tarantool::lua_state(); lua.exec_with( - "box.session.on_auth(...)", + " + local rust_on_auth = ... + local function on_auth(user, status) + if box.session.type() ~= 'console' then + rust_on_auth(user, status) + end + end + + box.session.on_auth(on_auth)", tlua::function3(move |user: String, status: bool, lua: tlua::LuaState| { match compute_auth_verdict(user.clone(), status) { Verdict::AuthOk => { diff --git a/test/int/test_cli_ux.py b/test/int/test_cli_ux.py index f632c8700e..ab8c94f899 100644 --- a/test/int/test_cli_ux.py +++ b/test/int/test_cli_ux.py @@ -1,7 +1,12 @@ import pexpect # type: ignore +import os +import pytest import sys import subprocess -from conftest import Cluster +from conftest import Cluster, log_crawler +from tarantool.error import ( # type: ignore + NetworkError, +) def test_connect_ux(cluster: Cluster): @@ -459,3 +464,52 @@ Delimiter changed to ';' Bye """.encode() ) + + +def test_do_not_ban_admin_via_unix_socket(cluster: Cluster): + password_file = f"{cluster.data_dir}/service-password.txt" + with open(password_file, "w") as f: + print("secret", file=f) + + os.chmod(password_file, 0o600) + + i1 = cluster.add_instance(wait_online=False) + i1.service_password_file = password_file + + admin_banned_lc = log_crawler( + i1, "Maximum number of login attempts exceeded; user blocked" + ) + i1.start() + i1.wait_online() + + # auth via pico_service many times + for _ in range(100): + with pytest.raises(NetworkError): + i1.sql("try to auth", user="pico_service", password="wrong_password") + + # pico_service is not banned + data = i1.sql( + "SELECT name FROM _pico_tier ", user="pico_service", password="secret" + ) + + assert data[0][0] == "default" + + # auth via admin until ban + for _ in range(5): + with pytest.raises(NetworkError): + i1.sql("try to auth", user="admin", password="wrong_password") + + admin_banned_lc.wait_matched() + + cli = pexpect.spawn( + cwd=i1.data_dir, + command=i1.binary_path, + args=["admin", "./admin.sock"], + encoding="utf-8", + timeout=1, + ) + + cli.logfile = sys.stdout + cli.expect_exact('Connected to admin console by socket path "./admin.sock"') + cli.expect_exact("type '\\help' for interactive help") + cli.expect_exact("picodata> ") -- GitLab