Skip to content

Commit

Permalink
[SKV-670] feat(Ranger): refactor the logic when ranger performs ACL (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
王浩 authored and acelyc111 committed Jun 15, 2023
1 parent 3fb6364 commit 842cd40
Show file tree
Hide file tree
Showing 10 changed files with 844 additions and 158 deletions.
11 changes: 11 additions & 0 deletions src/rdsn/include/dsn/cpp/access_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include <cstdint>

#include <dsn/utility/enum_helper.h>

namespace dsn {
namespace ranger {

Expand All @@ -34,6 +36,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
254 changes: 228 additions & 26 deletions src/rdsn/src/runtime/ranger/ranger_resource_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
// specific language governing permissions and limitations
// under the License.

#include <dsn/cpp/access_type.h>
#include <dsn/dist/fmt_logging.h>

#include "ranger_resource_policy.h"

namespace dsn {
Expand All @@ -25,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
{
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
{
// 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)) {
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;
}
dassert(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;
}
dassert(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;
}
}
auto check_status =
policy.policies.policies_check<policy_check_type::kAllow>(ac_type, user_name);
if (policy_check_status::kAllowed == check_status) {
return access_control_result::kAllowed;
}

// In a 'allow_policies' and in a 'allow_policies_exclude' or not match.
dassert(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_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;
}
}
// 2.3. Not in any 'allow_policies_exclude', it's allowed.
return true;
auto check_status =
policy.policies.policies_check<policy_check_type::kDeny>(ac_type, user_name);
if (policy_check_status::kDenied == check_status) {
return access_control_result::kDenied;
}

// In a 'deny_policies' and in a 'deny_policies_exclude' or not match.
dassert(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;
}
dassert(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;
}
dassert(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.
dassert(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_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.
dassert(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

0 comments on commit 842cd40

Please sign in to comment.