Skip to content

Commit f9d1a33

Browse files
authored
feat: add abac with rule and test. (#170)
Signed-off-by: stonex <[email protected]>
1 parent 64fc8dd commit f9d1a33

File tree

6 files changed

+103
-1
lines changed

6 files changed

+103
-1
lines changed

casbin/enforcer.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ bool Enforcer::m_enforce(const std::string& matcher, Scope scope) {
7474
for(auto func : m_user_func_list)
7575
m_func_map.AddFunction(std::get<0>(func), std::get<1>(func), std::get<2>(func));
7676

77+
bool hasEval = HasEval(exp_string);
78+
7779
std::unordered_map<std::string, int> p_int_tokens;
7880
std::vector<std::string>& p_tokens = m_model->m["p"].assertion_map["p"]->tokens;
7981
p_int_tokens.reserve(p_tokens.size());
@@ -105,7 +107,29 @@ bool Enforcer::m_enforce(const std::string& matcher, Scope scope) {
105107
PushStringPropToObject(m_func_map.scope, "p", p_vals[j], token);
106108
}
107109

108-
m_func_map.Evaluate(exp_string);
110+
if(hasEval) {
111+
auto ruleNames = GetEvalValue(exp_string);
112+
std::unordered_map<std::string, std::string> replacements;
113+
for(auto& ruleName: ruleNames) {
114+
auto ruleNameCpy = EscapeAssertion(ruleName);
115+
116+
bool ok = p_int_tokens.find(ruleNameCpy) != p_int_tokens.end();
117+
if (ok) {
118+
int idx = p_int_tokens[ruleNameCpy];
119+
replacements[ruleName] = p_vals[idx];
120+
} else {
121+
m_log.LogPrint("please make sure rule exists in policy when using eval() in matcher");
122+
return false;
123+
}
124+
}
125+
126+
auto expWithRule = ReplaceEvalWithMap(exp_string, replacements);
127+
m_func_map.Evaluate(expWithRule);
128+
129+
} else {
130+
131+
m_func_map.Evaluate(exp_string);
132+
}
109133

110134
//TODO
111135
// log.LogPrint("Result: ", result)

casbin/util/eval.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,25 @@ std::string ReplaceEvalWithMap(const std::string& src, std::unordered_map<std::s
6060
return replacedExp;
6161
}
6262

63+
// GetEvalValue returns the parameters of function eval
64+
std::vector<std::string> GetEvalValue(std::string s) {
65+
std::vector<std::string> rules;
66+
rules.reserve(10);
67+
std::smatch m;
68+
69+
while (std::regex_search(s, m, evalReg)) {
70+
if (m.empty()) {
71+
return rules;
72+
}
73+
std::string rule = m[1];
74+
75+
rules.push_back(rule);
76+
s = m.suffix();
77+
}
78+
79+
return rules;
80+
}
81+
6382
} // namespace casbin
6483

6584
#endif // EVAL_CPP

casbin/util/util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ bool HasEval(const std::string& s);
7171
// ReplaceEvalWithMap replace function eval with the value of its parameters via given sets.
7272
std::string ReplaceEvalWithMap(const std::string& src, std::unordered_map<std::string, std::string>& sets);
7373

74+
// GetEvalValue returns the parameters of function eval
75+
std::vector<std::string> GetEvalValue(std::string s);
7476
} // namespace casbin
7577

7678
#endif

include/casbin/casbin_helpers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,9 @@ namespace casbin {
640640

641641
// ReplaceEvalWithMap replace function eval with the value of its parameters via given sets.
642642
std::string ReplaceEvalWithMap(const std::string& src, std::unordered_map<std::string, std::string>& sets);
643+
644+
// GetEvalValue returns the parameters of function eval
645+
std::vector<std::string> GetEvalValue(std::string s);
643646

644647
// Exception class for Casbin Adapter Exception.
645648
class CasbinAdapterException : std::logic_error {

tests/config_path.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,5 @@ static const std::string priority_model_path = relative_path + "/examples/priori
5353
static const std::string priority_policy_path = relative_path + "/examples/priority_policy.csv";
5454

5555
static const std::string abac_model_path = relative_path + "/examples/abac_model.conf";
56+
static const std::string abac_rule_model_path = relative_path + "/examples/abac_rule_model.conf";
57+
static const std::string abac_rule_policy_path = relative_path + "/examples/abac_rule_policy.csv";

tests/model_enforcer_test.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ casbin::Scope InitializeParamsWithDomains(const std::string& sub, const std::str
5959
return scope;
6060
}
6161

62+
casbin::Scope InitializeParamsWithJson(std::shared_ptr<nlohmann::json> sub, std::string obj, std::string act) {
63+
casbin::Scope scope = casbin::InitializeScope();
64+
casbin::PushObject(scope, "r");
65+
66+
casbin::PushStringPropToObject(scope, "r", obj, "obj");
67+
casbin::PushStringPropToObject(scope, "r", act, "act");
68+
69+
casbin::PushObject(scope, "sub");
70+
casbin::PushObjectPropFromJson(scope, *sub, "sub");
71+
casbin::PushObjectPropToObject(scope, "r", "sub");
72+
73+
return scope;
74+
}
75+
6276
void TestEnforce(casbin::Enforcer& e, casbin::Scope& scope, bool res) {
6377
ASSERT_EQ(res, e.Enforce(scope));
6478
}
@@ -523,6 +537,44 @@ TEST(TestModelEnforcer, TestABACModelWithJson) {
523537
ASSERT_TRUE(e.Enforce(listParams));
524538
ASSERT_TRUE(e.Enforce(vectorParams));
525539
}
540+
541+
std::shared_ptr<nlohmann::json> newTestSubject(std::string name, int age) {
542+
nlohmann::json sub = {{"Name", name}, {"Age", age}};
543+
return std::make_shared<nlohmann::json>(sub);
544+
}
545+
546+
TEST(TestModelEnforcer, TestABACPolicyWithJson) {
547+
casbin::Enforcer e(abac_rule_model_path, abac_rule_policy_path);
548+
549+
auto sub1 = newTestSubject("alice", 16);
550+
auto sub2 = newTestSubject("alice", 20);
551+
auto sub3 = newTestSubject("alice", 65);
552+
553+
auto scope = InitializeParamsWithJson(sub1, "/data1", "read");
554+
TestEnforce(e, scope, false);
555+
scope = InitializeParamsWithJson(sub1, "/data2", "read");
556+
TestEnforce(e, scope, false);
557+
scope = InitializeParamsWithJson(sub1, "/data1", "write");
558+
TestEnforce(e, scope, false);
559+
scope = InitializeParamsWithJson(sub1, "/data2", "write");
560+
TestEnforce(e, scope, true);
561+
scope = InitializeParamsWithJson(sub2, "/data1", "read");
562+
TestEnforce(e, scope, true);
563+
scope = InitializeParamsWithJson(sub2, "/data2", "read");
564+
TestEnforce(e, scope, false);
565+
scope = InitializeParamsWithJson(sub2, "/data1", "write");
566+
TestEnforce(e, scope, false);
567+
scope = InitializeParamsWithJson(sub2, "/data2", "write");
568+
TestEnforce(e, scope, true);
569+
scope = InitializeParamsWithJson(sub3, "/data1", "read");
570+
TestEnforce(e, scope, true);
571+
scope = InitializeParamsWithJson(sub3, "/data2", "read");
572+
TestEnforce(e, scope, false);
573+
scope = InitializeParamsWithJson(sub3, "/data1", "write");
574+
TestEnforce(e, scope, false);
575+
scope = InitializeParamsWithJson(sub3, "/data2", "write");
576+
TestEnforce(e, scope, false);
577+
}
526578
/*
527579
type testCustomRoleManager struct {}
528580

0 commit comments

Comments
 (0)