1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00

feat(acl): add acl keys to acl log command (#2274)

* add acl keys to acl log command
* add tests
This commit is contained in:
Kostas Kyrimis 2023-12-12 17:00:41 +02:00 committed by GitHub
parent d88b2422de
commit 8640edad71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 19 deletions

View file

@ -359,13 +359,22 @@ void AclFamily::Log(CmdArgList args, ConnectionContext* cntx) {
rb->StartArray(12);
rb->SendSimpleString("reason");
using Reason = AclLog::Reason;
std::string_view reason = entry.reason == Reason::COMMAND ? "COMMAND" : "AUTH";
std::string reason;
if (entry.reason == Reason::COMMAND) {
reason = "COMMAND";
} else if (entry.reason == Reason::KEY) {
reason = "KEY";
} else {
reason = "AUTH";
}
rb->SendSimpleString(reason);
rb->SendSimpleString("object");
rb->SendSimpleString(entry.object);
rb->SendSimpleString("username");
rb->SendSimpleString(entry.username);
rb->SendSimpleString("age-seconds");
auto now_diff = std::chrono::system_clock::now() - entry.entry_creation;
auto secs = std::chrono::duration_cast<std::chrono::seconds>(now_diff);
auto left_over = now_diff - std::chrono::duration_cast<std::chrono::microseconds>(secs);
@ -491,6 +500,7 @@ void AclFamily::GetUser(CmdArgList args, ConnectionContext* cntx) {
std::string acl = absl::StrCat(AclCatToString(user.AclCategory()), " ",
AclCommandToString(user.AclCommandsRef()));
rb->SendSimpleString(acl);
rb->SendSimpleString("keys");
@ -550,8 +560,10 @@ void AclFamily::DryRun(CmdArgList args, ConnectionContext* cntx) {
}
const auto& user = registry.find(username)->second;
if (IsUserAllowedToInvokeCommandGeneric(user.AclCategory(), user.AclCommandsRef(), {{}, true}, {},
*cid)) {
const bool is_allowed = IsUserAllowedToInvokeCommandGeneric(
user.AclCategory(), user.AclCommandsRef(), {{}, true}, {}, *cid)
.first;
if (is_allowed) {
cntx->SendOk();
return;
}

View file

@ -19,7 +19,7 @@ class AclLog {
public:
explicit AclLog();
enum class Reason { COMMAND, AUTH };
enum class Reason { COMMAND, AUTH, KEY };
struct LogEntry {
std::string username;

View file

@ -23,13 +23,12 @@ namespace dfly::acl {
return true;
}
const auto is_authed = IsUserAllowedToInvokeCommandGeneric(cntx.acl_categories, cntx.acl_commands,
cntx.keys, tail_args, id);
const auto [is_authed, reason] = IsUserAllowedToInvokeCommandGeneric(
cntx.acl_categories, cntx.acl_commands, cntx.keys, tail_args, id);
if (!is_authed) {
auto& log = ServerState::tlocal()->acl_log;
using Reason = acl::AclLog::Reason;
log.Add(cntx, std::string(id.name()), Reason::COMMAND);
log.Add(cntx, std::string(id.name()), reason);
}
return is_authed;
@ -39,10 +38,9 @@ namespace dfly::acl {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
[[nodiscard]] bool IsUserAllowedToInvokeCommandGeneric(uint32_t acl_cat,
const std::vector<uint64_t>& acl_commands,
const AclKeys& keys, CmdArgList tail_args,
const CommandId& id) {
[[nodiscard]] std::pair<bool, AclLog::Reason> IsUserAllowedToInvokeCommandGeneric(
uint32_t acl_cat, const std::vector<uint64_t>& acl_commands, const AclKeys& keys,
CmdArgList tail_args, const CommandId& id) {
const auto cat_credentials = id.acl_categories();
const size_t index = id.GetFamily();
const uint64_t command_mask = id.GetBitIndex();
@ -52,7 +50,7 @@ namespace dfly::acl {
(acl_cat & cat_credentials) != 0 || (acl_commands[index] & command_mask) != 0;
if (!command) {
return false;
return {false, AclLog::Reason::COMMAND};
}
auto match = [](const auto& pattern, const auto& target) {
@ -97,7 +95,7 @@ namespace dfly::acl {
}
}
return keys_allowed;
return {keys_allowed, AclLog::Reason::KEY};
}
#pragma GCC diagnostic pop

View file

@ -6,16 +6,15 @@
#include <utility>
#include "facade/command_id.h"
#include "server/acl/acl_log.h"
#include "server/command_registry.h"
#include "server/conn_context.h"
namespace dfly::acl {
bool IsUserAllowedToInvokeCommandGeneric(uint32_t acl_cat,
const std::vector<uint64_t>& acl_commands,
const AclKeys& keys, CmdArgList tail_args,
const CommandId& id);
std::pair<bool, AclLog::Reason> IsUserAllowedToInvokeCommandGeneric(
uint32_t acl_cat, const std::vector<uint64_t>& acl_commands, const AclKeys& keys,
CmdArgList tail_args, const CommandId& id);
bool IsUserAllowedToInvokeCommand(const ConnectionContext& cntx, const CommandId& id,
CmdArgList tail_args);

View file

@ -394,6 +394,18 @@ async def test_acl_log(async_client):
res = await async_client.execute_command("ACL LOG")
assert 2 == len(res)
res = await async_client.execute_command("ACL LOG RESET")
await async_client.execute_command("ACL SETUSER elon resetkeys ~foo")
with pytest.raises(redis.exceptions.ResponseError):
await async_client.execute_command("SET bar val")
res = await async_client.execute_command("ACL LOG")
assert 1 == len(res)
assert res[0]["reason"] == "KEY"
assert res[0]["object"] == "SET"
assert res[0]["username"] == "elon"
@pytest.mark.asyncio
@dfly_args({"port": 1111, "admin_port": 1112, "requirepass": "mypass"})