From f9d1a3394b075361f32a00a24dd10710643e5967 Mon Sep 17 00:00:00 2001 From: Stonex <43725202+sheny1xuan@users.noreply.github.com> Date: Sun, 21 Nov 2021 22:05:33 +0800 Subject: [PATCH] feat: add abac with rule and test. (#170) Signed-off-by: stonex <1479765922@qq.com> --- casbin/enforcer.cpp | 26 ++++++++++++++++- casbin/util/eval.cpp | 19 ++++++++++++ casbin/util/util.h | 2 ++ include/casbin/casbin_helpers.h | 3 ++ tests/config_path.h | 2 ++ tests/model_enforcer_test.cpp | 52 +++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 1 deletion(-) diff --git a/casbin/enforcer.cpp b/casbin/enforcer.cpp index 1b133bbb..8e93d1b9 100644 --- a/casbin/enforcer.cpp +++ b/casbin/enforcer.cpp @@ -74,6 +74,8 @@ bool Enforcer::m_enforce(const std::string& matcher, Scope scope) { for(auto func : m_user_func_list) m_func_map.AddFunction(std::get<0>(func), std::get<1>(func), std::get<2>(func)); + bool hasEval = HasEval(exp_string); + std::unordered_map p_int_tokens; std::vector& p_tokens = m_model->m["p"].assertion_map["p"]->tokens; p_int_tokens.reserve(p_tokens.size()); @@ -105,7 +107,29 @@ bool Enforcer::m_enforce(const std::string& matcher, Scope scope) { PushStringPropToObject(m_func_map.scope, "p", p_vals[j], token); } - m_func_map.Evaluate(exp_string); + if(hasEval) { + auto ruleNames = GetEvalValue(exp_string); + std::unordered_map replacements; + for(auto& ruleName: ruleNames) { + auto ruleNameCpy = EscapeAssertion(ruleName); + + bool ok = p_int_tokens.find(ruleNameCpy) != p_int_tokens.end(); + if (ok) { + int idx = p_int_tokens[ruleNameCpy]; + replacements[ruleName] = p_vals[idx]; + } else { + m_log.LogPrint("please make sure rule exists in policy when using eval() in matcher"); + return false; + } + } + + auto expWithRule = ReplaceEvalWithMap(exp_string, replacements); + m_func_map.Evaluate(expWithRule); + + } else { + + m_func_map.Evaluate(exp_string); + } //TODO // log.LogPrint("Result: ", result) diff --git a/casbin/util/eval.cpp b/casbin/util/eval.cpp index 3311ed7f..456a07c6 100644 --- a/casbin/util/eval.cpp +++ b/casbin/util/eval.cpp @@ -60,6 +60,25 @@ std::string ReplaceEvalWithMap(const std::string& src, std::unordered_map GetEvalValue(std::string s) { + std::vector rules; + rules.reserve(10); + std::smatch m; + + while (std::regex_search(s, m, evalReg)) { + if (m.empty()) { + return rules; + } + std::string rule = m[1]; + + rules.push_back(rule); + s = m.suffix(); + } + + return rules; +} + } // namespace casbin #endif // EVAL_CPP diff --git a/casbin/util/util.h b/casbin/util/util.h index 5e9e1641..47f9f9e6 100644 --- a/casbin/util/util.h +++ b/casbin/util/util.h @@ -71,6 +71,8 @@ bool HasEval(const std::string& s); // ReplaceEvalWithMap replace function eval with the value of its parameters via given sets. std::string ReplaceEvalWithMap(const std::string& src, std::unordered_map& sets); +// GetEvalValue returns the parameters of function eval +std::vector GetEvalValue(std::string s); } // namespace casbin #endif \ No newline at end of file diff --git a/include/casbin/casbin_helpers.h b/include/casbin/casbin_helpers.h index af7a12a5..c7e779b6 100644 --- a/include/casbin/casbin_helpers.h +++ b/include/casbin/casbin_helpers.h @@ -640,6 +640,9 @@ namespace casbin { // ReplaceEvalWithMap replace function eval with the value of its parameters via given sets. std::string ReplaceEvalWithMap(const std::string& src, std::unordered_map& sets); + + // GetEvalValue returns the parameters of function eval + std::vector GetEvalValue(std::string s); // Exception class for Casbin Adapter Exception. class CasbinAdapterException : std::logic_error { diff --git a/tests/config_path.h b/tests/config_path.h index abc44cb6..c743240c 100644 --- a/tests/config_path.h +++ b/tests/config_path.h @@ -53,3 +53,5 @@ static const std::string priority_model_path = relative_path + "/examples/priori static const std::string priority_policy_path = relative_path + "/examples/priority_policy.csv"; static const std::string abac_model_path = relative_path + "/examples/abac_model.conf"; +static const std::string abac_rule_model_path = relative_path + "/examples/abac_rule_model.conf"; +static const std::string abac_rule_policy_path = relative_path + "/examples/abac_rule_policy.csv"; diff --git a/tests/model_enforcer_test.cpp b/tests/model_enforcer_test.cpp index cdbc5361..b6f9fdf4 100644 --- a/tests/model_enforcer_test.cpp +++ b/tests/model_enforcer_test.cpp @@ -59,6 +59,20 @@ casbin::Scope InitializeParamsWithDomains(const std::string& sub, const std::str return scope; } +casbin::Scope InitializeParamsWithJson(std::shared_ptr sub, std::string obj, std::string act) { + casbin::Scope scope = casbin::InitializeScope(); + casbin::PushObject(scope, "r"); + + casbin::PushStringPropToObject(scope, "r", obj, "obj"); + casbin::PushStringPropToObject(scope, "r", act, "act"); + + casbin::PushObject(scope, "sub"); + casbin::PushObjectPropFromJson(scope, *sub, "sub"); + casbin::PushObjectPropToObject(scope, "r", "sub"); + + return scope; +} + void TestEnforce(casbin::Enforcer& e, casbin::Scope& scope, bool res) { ASSERT_EQ(res, e.Enforce(scope)); } @@ -523,6 +537,44 @@ TEST(TestModelEnforcer, TestABACModelWithJson) { ASSERT_TRUE(e.Enforce(listParams)); ASSERT_TRUE(e.Enforce(vectorParams)); } + +std::shared_ptr newTestSubject(std::string name, int age) { + nlohmann::json sub = {{"Name", name}, {"Age", age}}; + return std::make_shared(sub); +} + +TEST(TestModelEnforcer, TestABACPolicyWithJson) { + casbin::Enforcer e(abac_rule_model_path, abac_rule_policy_path); + + auto sub1 = newTestSubject("alice", 16); + auto sub2 = newTestSubject("alice", 20); + auto sub3 = newTestSubject("alice", 65); + + auto scope = InitializeParamsWithJson(sub1, "/data1", "read"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub1, "/data2", "read"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub1, "/data1", "write"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub1, "/data2", "write"); + TestEnforce(e, scope, true); + scope = InitializeParamsWithJson(sub2, "/data1", "read"); + TestEnforce(e, scope, true); + scope = InitializeParamsWithJson(sub2, "/data2", "read"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub2, "/data1", "write"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub2, "/data2", "write"); + TestEnforce(e, scope, true); + scope = InitializeParamsWithJson(sub3, "/data1", "read"); + TestEnforce(e, scope, true); + scope = InitializeParamsWithJson(sub3, "/data2", "read"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub3, "/data1", "write"); + TestEnforce(e, scope, false); + scope = InitializeParamsWithJson(sub3, "/data2", "write"); + TestEnforce(e, scope, false); +} /* type testCustomRoleManager struct {}