Skip to content
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

feat(acl): add validation for acl keys #2272

Merged
merged 10 commits into from
Dec 8, 2023
Merged

feat(acl): add validation for acl keys #2272

merged 10 commits into from
Dec 8, 2023

Conversation

kostasrim
Copy link
Contributor

PR5

  • add validation for acl keys
  • add tests

part of #2229

@kostasrim kostasrim changed the base branch from main to aclkeys4 December 7, 2023 17:36
@kostasrim kostasrim self-assigned this Dec 7, 2023
@kostasrim kostasrim requested a review from dranikpg December 7, 2023 17:40
Comment on lines 47 to 49
const size_t step = (id.opt_mask() & CO::CommandOpt::INTERLEAVED_KEYS) ? 2 : 1;
const bool var_keys = (id.opt_mask() & CO::CommandOpt::VARIADIC_KEYS);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use DetermineKeys() from transactio.h which gives you a key index

Comment on lines 56 to 57
const size_t end = var_keys ? tail_args.size() : id.last_key_pos() + 1;
for (size_t i = id.first_key_pos(); i < end; i += step) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is something called a bonus key, you'll see when you use DetermineKeys()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot about this and the bonus keys. Nice catch!

const bool var_keys = (id.opt_mask() & CO::CommandOpt::VARIADIC_KEYS);

auto match = [](const auto& pattern, const auto& target) {
return stringmatchlen(pattern.data(), pattern.size(), target.data(), target.size(), 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow wtf this is a built-in redis function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes!

#include "server/server_state.h"
extern "C" {
#include "redis/util.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add its for stringmatchlen because it's hard to find otherwise

return stringmatchlen(pattern.data(), pattern.size(), target.data(), target.size(), 0);
};

bool key_allowed = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key_allowed is a confusing name for a resulting variable, you probably had command_allowed in mind

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant keys_allowed, because this part of the code checks if the command key arguments are allowed by the authed user

Comment on lines 79 to 82
const bool command =
(acl_cat & cat_credentials) != 0 || (acl_commands[index] & command_mask) != 0;

return command && key_allowed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you probably want to check that first before you go over all the keys

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep +1

Comment on lines 45 to 46
const bool is_read_command = id.opt_mask() & CO::CommandOpt::READONLY;
const bool is_write_command = id.opt_mask() & CO::CommandOpt::WRITE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Didn't you add IsReadOnly/IsWriteOnly below for that?
  2. Why did you use ::CommandOpt::... I understand it's the full path, but first it's not easier to read, second it's harder to search. I always use CO::X to search for places in code that rely on some flag

(2) actually also applies to (1) 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uh I thought it was a scoped enum

Comment on lines +95 to +102
bool IsReadOnly() const {
return opt_mask_ & CO::CommandOpt::READONLY;
}

bool IsWriteOnly() const {
return opt_mask_ & CO::CommandOpt::WRITE;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that whenever we add a useful utility, let's replace old code with it, because otherwise we just spread non conformity and make it harder to search for uses

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep +100, done :)

Base automatically changed from aclkeys4 to main December 8, 2023 12:32
@kostasrim kostasrim requested a review from dranikpg December 8, 2023 13:21
@kostasrim kostasrim merged commit 2703d46 into main Dec 8, 2023
10 checks passed
@kostasrim kostasrim deleted the aclkeys5 branch December 8, 2023 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants