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(Ranger): refactor the logic when ranger performs ACL #1518

Merged
merged 7 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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 src/runtime/ranger/access_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <cstdint>
#include <type_traits>

#include "utils/enum_helper.h"

namespace dsn {
namespace ranger {

Expand All @@ -35,6 +37,15 @@ enum class access_type : uint8_t
kMetadata = 1 << 5,
kControl = 1 << 6
};
ENUM_BEGIN(access_type, access_type::kInvalid)
ENUM_REG(access_type::kRead)
ENUM_REG(access_type::kWrite)
ENUM_REG(access_type::kCreate)
ENUM_REG(access_type::kDrop)
ENUM_REG(access_type::kList)
ENUM_REG(access_type::kMetadata)
ENUM_REG(access_type::kControl)
ENUM_END(access_type)

using act = std::underlying_type<access_type>::type;

Expand Down
252 changes: 226 additions & 26 deletions src/runtime/ranger/ranger_resource_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "ranger_resource_policy.h"

#include "runtime/ranger/access_type.h"
#include "utils/fmt_logging.h"

namespace dsn {
namespace ranger {
Expand All @@ -27,45 +28,244 @@ bool policy_item::match(const access_type &ac_type, const std::string &user_name
return static_cast<bool>(access_types & ac_type) && users.count(user_name) != 0;
}

bool acl_policies::allowed(const access_type &ac_type, const std::string &user_name) const
template <>
policy_check_status
acl_policies::policies_check<policy_check_type::kAllow>(const access_type &ac_type,
const std::string &user_name) const
{
// 1. Check if it is not allowed.
for (const auto &deny_policy : deny_policies) {
// 1.1. In 'deny_policies'.
if (!deny_policy.match(ac_type, user_name)) {
return do_policies_check<policy_check_type::kAllow, policy_check_status::kAllowed>(ac_type,
user_name);
}

template <>
policy_check_status
acl_policies::policies_check<policy_check_type::kDeny>(const access_type &ac_type,
const std::string &user_name) const
{
return do_policies_check<policy_check_type::kDeny, policy_check_status::kDenied>(ac_type,
user_name);
}

template <>
policy_check_status
acl_policies::do_policies_check<policy_check_type::kAllow, policy_check_status::kAllowed>(
const access_type &ac_type, const std::string &user_name) const
{
for (const auto &policy : allow_policies) {
// 1. Doesn't match an allow_policies.
if (!policy.match(ac_type, user_name)) {
continue;
}
bool in_deny_policies_exclude = false;
for (const auto &deny_policy_exclude : deny_policies_exclude) {
if (deny_policy_exclude.match(ac_type, user_name)) {
in_deny_policies_exclude = true;
break;
// 2. Matches a policy.
for (const auto &exclude_policy : allow_policies_exclude) {
if (exclude_policy.match(ac_type, user_name)) {
// 2.1. Matches an allow_policies_exclude.
return policy_check_status::kPending;
}
}
// 1.2. Not in any 'deny_policies_exclude', it's not allowed.
if (!in_deny_policies_exclude) {
return false;
}
// 2.2. Doesn't match any allow_exclude_policies.
return policy_check_status::kAllowed;
}
// 3. Doesn't match any policy.
return policy_check_status::kNotMatched;
}

// 2. Check if it is allowed.
for (const auto &allow_policy : allow_policies) {
// 2.1. In 'allow_policies'.
if (!allow_policy.match(ac_type, user_name)) {
template <>
policy_check_status
acl_policies::do_policies_check<policy_check_type::kDeny, policy_check_status::kDenied>(
const access_type &ac_type, const std::string &user_name) const
{
for (const auto &policy : deny_policies) {
// 1. Doesn't match a deny_policies.
if (!policy.match(ac_type, user_name)) {
continue;
}
for (const auto &allow_policy_exclude : allow_policies_exclude) {
// 2.2. In some 'allow_policies_exclude', it's not allowed.
if (allow_policy_exclude.match(ac_type, user_name)) {
return false;
// 2. Matches a policy.
for (const auto &exclude_policy : deny_policies_exclude) {
if (exclude_policy.match(ac_type, user_name)) {
// 2.1. Matches a deny_policies_exclude.
return policy_check_status::kPending;
}
}
// 2.2. Doesn't match any deny_exclude_policies.
return policy_check_status::kDenied;
}
// 3. Doesn't match any policy.
return policy_check_status::kNotMatched;
}

access_control_result
check_ranger_resource_policy_allowed(const std::vector<ranger_resource_policy> &policies,
const access_type &ac_type,
const std::string &user_name,
const match_database_type &md_type,
const std::string &database_name,
const std::string &default_database_name)
{
// Check if it is denied by any policy in current resource.
auto check_res = do_check_ranger_resource_policy<policy_check_type::kDeny>(
policies, ac_type, user_name, md_type, database_name, default_database_name);
if (access_control_result::kDenied == check_res) {
return access_control_result::kDenied;
}
CHECK(access_control_result::kPending == check_res, "the access control result must kPending.");

// Check if it is allowed by any policy in current resource.
check_res = do_check_ranger_resource_policy<policy_check_type::kAllow>(
policies, ac_type, user_name, md_type, database_name, default_database_name);
if (access_control_result::kAllowed == check_res) {
return access_control_result::kAllowed;
}
CHECK(access_control_result::kPending == check_res, "the access control result must kPending.");

// The check that does not match any policy in current reosource returns false.
return access_control_result::kDenied;
}

template <>
access_control_result do_check_ranger_resource_policy<policy_check_type::kAllow>(
const std::vector<ranger_resource_policy> &policies,
const access_type &ac_type,
const std::string &user_name,
const match_database_type &md_type,
const std::string &database_name,
const std::string &default_database_name)
{
for (const auto &policy : policies) {
if (match_database_type::kNeed == md_type) {
// Lagacy table not match any database.
if (database_name.empty() && policy.database_names.count("*") == 0 &&
policy.database_names.count(default_database_name) == 0) {
continue;
}
// New table not match any database.
if (!database_name.empty() && policy.database_names.count("*") == 0 &&
policy.database_names.count(database_name) == 0) {
continue;
}
}
// 2.3. Not in any 'allow_policies_exclude', it's allowed.
return true;
auto check_status =
policy.policies.policies_check<policy_check_type::kAllow>(ac_type, user_name);
// When policy_check_type is 'kAllow' and in a 'allow_policies' and not in any
// 'allow_policies_exclude'.
if (policy_check_status::kAllowed == check_status) {
return access_control_result::kAllowed;
}

// In a 'policies' and in a 'policies_exclude' or not match.
CHECK(policy_check_status::kPending == check_status ||
policy_check_status::kNotMatched == check_status,
"the policy check status must be kPending or kNotMatched");
}
return access_control_result::kPending;
}

// 3. Otherwise, it's not allowed.
return false;
template <>
access_control_result do_check_ranger_resource_policy<policy_check_type::kDeny>(
const std::vector<ranger_resource_policy> &policies,
const access_type &ac_type,
const std::string &user_name,
const match_database_type &md_type,
const std::string &database_name,
const std::string &default_database_name)
{
for (const auto &policy : policies) {
if (match_database_type::kNeed == md_type) {
// Lagacy table not match any database.
if (database_name.empty() && policy.database_names.count("*") == 0 &&
policy.database_names.count(default_database_name) == 0) {
continue;
}
// New table not match any database.
if (!database_name.empty() && policy.database_names.count("*") == 0 &&
policy.database_names.count(database_name) == 0) {
continue;
}
}
auto check_status =
policy.policies.policies_check<policy_check_type::kDeny>(ac_type, user_name);
// When policy_check_type is 'kDeny' and in a 'deny_policies' and not in any
// 'deny_policies_exclude'.
if (policy_check_status::kDenied == check_status) {
return access_control_result::kDenied;
}

// In a 'policies' and in a 'policies_exclude' or not match.
CHECK(policy_check_status::kPending == check_status ||
policy_check_status::kNotMatched == check_status,
"the policy check status must be kPending or kNotMatched");
}
return access_control_result::kPending;
}

access_control_result check_ranger_database_table_policy_allowed(
const std::vector<matched_database_table_policy> &policies,
const access_type &ac_type,
const std::string &user_name)
{
// Check if it is denied by any DATABASE_TABLE policy.
auto check_res = do_check_ranger_database_table_policy<policy_check_type::kDeny>(
policies, ac_type, user_name);
if (access_control_result::kDenied == check_res) {
return access_control_result::kDenied;
}
CHECK(access_control_result::kPending == check_res, "the access control result must kPending.");

// Check if it is allowed by any DATABASE_TABLE policy.
check_res = do_check_ranger_database_table_policy<policy_check_type::kAllow>(
policies, ac_type, user_name);
if (access_control_result::kAllowed == check_res) {
return access_control_result::kAllowed;
}
CHECK(access_control_result::kPending == check_res, "the access control result must kPending.");

// The check that does not match any DATABASE_TABLE policy returns false.
return access_control_result::kDenied;
}

template <>
access_control_result do_check_ranger_database_table_policy<policy_check_type::kDeny>(
const std::vector<matched_database_table_policy> &policies,
const access_type &ac_type,
const std::string &user_name)
{
for (const auto &policy : policies) {
auto check_status =
policy.policies.policies_check<policy_check_type::kDeny>(ac_type, user_name);
// When policy_check_type is 'kDeny' and in a 'deny_policies' and not in any
// 'deny_policies_exclude'.
if (policy_check_status::kDenied == check_status) {
return access_control_result::kDenied;
}

// In a 'policies' and in a 'policies_exclude' or not match.
CHECK(policy_check_status::kPending == check_status ||
policy_check_status::kNotMatched == check_status,
"the policy check status must be kPending or kNotMatched");
}
return access_control_result::kPending;
}

template <>
access_control_result do_check_ranger_database_table_policy<policy_check_type::kAllow>(
const std::vector<matched_database_table_policy> &policies,
const access_type &ac_type,
const std::string &user_name)
{
for (const auto &policy : policies) {
auto check_status =
policy.policies.policies_check<policy_check_type::kAllow>(ac_type, user_name);
// When policy_check_type is 'kAllow' and in a 'allow_policies' and not in any
// 'allow_policies_exclude'.
if (policy_check_status::kAllowed == check_status) {
return access_control_result::kAllowed;
}
// In a 'policies' and in a 'policies_exclude' or not match.
CHECK(policy_check_status::kPending == check_status ||
policy_check_status::kNotMatched == check_status,
"the policy check status must be kPending or kNotMatched");
}
return access_control_result::kPending;
}

} // namespace ranger
Expand Down
Loading