Skip to content

Commit 1fba9ea

Browse files
feat: exprtk evalutor support RBAC model and test (#187)
* chore: separate source and header file Signed-off-by: stonex <[email protected]> * feat: exprtk evalutor support g_function and test Signed-off-by: stonex <[email protected]> Co-authored-by: Yash Pandey (YP) <[email protected]>
1 parent 9c0c829 commit 1fba9ea

File tree

5 files changed

+207
-7
lines changed

5 files changed

+207
-7
lines changed

casbin/enforcer.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,18 @@ bool Enforcer::m_enforce(const std::string& matcher, std::shared_ptr<IEvaluator>
5959
for (auto [assertion_name, assertion] : m_model->m["g"].assertion_map) {
6060
std::shared_ptr<RoleManager>& rm = assertion->rm;
6161

62-
int char_count = static_cast<int>(std::count(assertion->value.begin(), assertion->value.end(), '_'));
63-
size_t index = exp_string.find(assertion_name + "(");
62+
if (dynamic_cast<DuktapeEvaluator*>(m_func_map.evalator.get()) != nullptr) {
63+
int char_count = static_cast<int>(std::count(assertion->value.begin(), assertion->value.end(), '_'));
64+
size_t index = exp_string.find(assertion_name + "(");
6465

65-
if (index != std::string::npos)
66-
exp_string.insert(index + assertion_name.length() + 1, "rm, ");
66+
if (index != std::string::npos)
67+
exp_string.insert(index + assertion_name.length() + 1, "rm, ");
68+
69+
m_func_map.evalator->LoadGFunction(rm, assertion_name, char_count + 1);
70+
} else {
71+
m_func_map.evalator->LoadGFunction(rm, assertion_name, 0);
72+
}
6773

68-
m_func_map.evalator->LoadGFunction(rm, assertion_name, char_count + 1);
6974
}
7075
}
7176

casbin/model/evaluator.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <regex>
1717

1818
#include "casbin/model/evaluator.h"
19+
#include "casbin/model/exprtk_config.h"
1920
#include "casbin/util/util.h"
2021

2122
namespace casbin {
@@ -45,11 +46,12 @@ namespace casbin {
4546
}
4647

4748
void ExprtkEvaluator::LoadFunctions() {
48-
49+
4950
}
5051

5152
void ExprtkEvaluator::LoadGFunction(std::shared_ptr<RoleManager> rm, const std::string& name, int narg) {
52-
53+
std::shared_ptr<exprtk_func_t> func = std::make_shared<ExprtkGFunction<numerical_type>>(rm);
54+
this->AddFunction(name, func);
5355
}
5456

5557
void ExprtkEvaluator::ProcessFunctions(const std::string& expression) {
@@ -87,6 +89,11 @@ namespace casbin {
8789
}
8890
}
8991

92+
void ExprtkEvaluator::AddFunction(const std::string& func_name, std::shared_ptr<exprtk_func_t> func) {
93+
this->Functions.push_back(func);
94+
symbol_table.add_function(func_name, *func);
95+
}
96+
9097
void ExprtkEvaluator::PrintSymbol() {
9198
std::vector<std::string> var_list;
9299
symbol_table.get_stringvar_list(var_list);

include/casbin/model/evaluator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define CASBIN_CPP_MODEL_EVALATOR_CONFIG
2020

2121
#include <string>
22+
#include <vector>
2223
#include <nlohmann/json.hpp>
2324

2425
#include "../exprtk/exprtk.hpp"
@@ -32,6 +33,7 @@ namespace casbin {
3233
using symbol_table_t = exprtk::symbol_table<numerical_type>;
3334
using expression_t = exprtk::expression<numerical_type>;
3435
using parser_t = exprtk::parser<numerical_type>;
36+
using exprtk_func_t = exprtk::igeneric_function<numerical_type>;
3537

3638
class IEvaluator {
3739
public:
@@ -64,6 +66,7 @@ namespace casbin {
6466
symbol_table_t symbol_table;
6567
expression_t expression;
6668
parser_t parser;
69+
std::vector<std::shared_ptr<exprtk_func_t>> Functions;
6770
public:
6871
bool Eval(const std::string& expression);
6972

@@ -88,6 +91,8 @@ namespace casbin {
8891
void Clean(AssertionMap& section);
8992

9093
void PrintSymbol();
94+
95+
void AddFunction(const std::string& func_name, std::shared_ptr<exprtk_func_t> func);
9196
};
9297

9398
class DuktapeEvaluator : public IEvaluator {
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2020 The casbin Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef CASBIN_CPP_MODEL_EXPRTK_CONFIG
18+
#define CASBIN_CPP_MODEL_EXPRTK_CONFIG
19+
20+
#include <memory>
21+
22+
#include "casbin/exprtk/exprtk.hpp"
23+
#include "casbin/rbac/role_manager.h"
24+
25+
namespace casbin {
26+
27+
template <typename T>
28+
struct ExprtkGFunction : public exprtk::igeneric_function<T>
29+
{
30+
typedef typename exprtk::igeneric_function<T>::generic_type
31+
generic_type;
32+
33+
typedef typename generic_type::scalar_view scalar_t;
34+
typedef typename generic_type::vector_view vector_t;
35+
typedef typename generic_type::string_view string_t;
36+
37+
typedef typename exprtk::igeneric_function<T>::parameter_list_t
38+
parameter_list_t;
39+
private:
40+
std::shared_ptr<casbin::RoleManager> rm_;
41+
public:
42+
ExprtkGFunction()
43+
: exprtk::igeneric_function<T>("SS"), rm_(nullptr)
44+
{}
45+
46+
ExprtkGFunction(std::shared_ptr<RoleManager> rm)
47+
: exprtk::igeneric_function<T>("SS"), rm_(rm)
48+
{}
49+
50+
bool UpdateRoleManager(std::shared_ptr<RoleManager> rm) {
51+
this->rm_ = rm;
52+
53+
return true;
54+
}
55+
56+
inline T operator()(parameter_list_t parameters) {
57+
bool res = false;
58+
59+
// check value cnt
60+
if (parameters.size() < 2 || parameters.size() > 3) {
61+
return T(res);
62+
}
63+
64+
// check value type
65+
for (std::size_t i = 0; i < parameters.size(); ++i) {
66+
generic_type& gt = parameters[i];
67+
68+
if (generic_type::e_scalar == gt.type) {
69+
return T(res);
70+
}
71+
else if (generic_type::e_vector == gt.type) {
72+
return T(res);
73+
}
74+
}
75+
76+
std::string name1 = exprtk::to_str(string_t(parameters[0]));
77+
std::string name2 = exprtk::to_str(string_t(parameters[1]));
78+
std::string domain;
79+
std::vector<std::string> domains;
80+
81+
if (parameters.size() == 3) {
82+
domain = exprtk::to_str(string_t(parameters[2]));
83+
domains.push_back(domain);
84+
}
85+
86+
if(this->rm_ == nullptr)
87+
res = name1 == name2;
88+
else {
89+
res = rm_->HasLink(name1, name2, domains);
90+
}
91+
92+
return T(res);
93+
}
94+
};
95+
}
96+
97+
98+
#endif

tests/model_enforcer_test.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,23 @@ TEST(TestModelEnforcer, TestRBACModel) {
374374
TestEnforce(e, evaluator, false);
375375
evaluator = InitializeParams<casbin::DuktapeEvaluator>("bob", "data2", "write");
376376
TestEnforce(e, evaluator, true);
377+
378+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "read");
379+
TestEnforce(e, evaluator, true);
380+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "write");
381+
TestEnforce(e, evaluator, false);
382+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "read");
383+
TestEnforce(e, evaluator, true);
384+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "write");
385+
TestEnforce(e, evaluator, true);
386+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "read");
387+
TestEnforce(e, evaluator, false);
388+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "write");
389+
TestEnforce(e, evaluator, false);
390+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "read");
391+
TestEnforce(e, evaluator, false);
392+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "write");
393+
TestEnforce(e, evaluator, true);
377394
}
378395

379396
TEST(TestModelEnforcer, TestRBACModelWithResourceRoles) {
@@ -397,6 +414,23 @@ TEST(TestModelEnforcer, TestRBACModelWithResourceRoles) {
397414
TestEnforce(e, evaluator, false);
398415
evaluator = InitializeParams<casbin::DuktapeEvaluator>("bob", "data2", "write");
399416
TestEnforce(e, evaluator, true);
417+
418+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "read");
419+
TestEnforce(e, evaluator, true);
420+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "write");
421+
TestEnforce(e, evaluator, true);
422+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "read");
423+
TestEnforce(e, evaluator, false);
424+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "write");
425+
TestEnforce(e, evaluator, true);
426+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "read");
427+
TestEnforce(e, evaluator, false);
428+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "write");
429+
TestEnforce(e, evaluator, false);
430+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "read");
431+
TestEnforce(e, evaluator, false);
432+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "write");
433+
TestEnforce(e, evaluator, true);
400434
}
401435

402436
TEST(TestModelEnforcer, TestRBACModelWithDomains) {
@@ -545,6 +579,23 @@ TEST(TestModelEnforcer, TestRBACModelWithDeny) {
545579
TestEnforce(e, evaluator, false);
546580
evaluator = InitializeParams<casbin::DuktapeEvaluator>("bob", "data2", "write");
547581
TestEnforce(e, evaluator, true);
582+
583+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "read");
584+
TestEnforce(e, evaluator, true);
585+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "write");
586+
TestEnforce(e, evaluator, false);
587+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "read");
588+
TestEnforce(e, evaluator, true);
589+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "write");
590+
TestEnforce(e, evaluator, false);
591+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "read");
592+
TestEnforce(e, evaluator, false);
593+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "write");
594+
TestEnforce(e, evaluator, false);
595+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "read");
596+
TestEnforce(e, evaluator, false);
597+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "write");
598+
TestEnforce(e, evaluator, true);
548599
}
549600

550601
TEST(TestModelEnforcer, TestRBACModelWithOnlyDeny) {
@@ -580,6 +631,23 @@ TEST(TestModelEnforcer, TestRBACModelWithCustomData) {
580631
evaluator = InitializeParams<casbin::DuktapeEvaluator>("bob", "data2", "write");
581632
TestEnforce(e, evaluator, true);
582633

634+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "read");
635+
TestEnforce(e, evaluator, true);
636+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "write");
637+
TestEnforce(e, evaluator, false);
638+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "read");
639+
TestEnforce(e, evaluator, true);
640+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "write");
641+
TestEnforce(e, evaluator, true);
642+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "read");
643+
TestEnforce(e, evaluator, false);
644+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "write");
645+
TestEnforce(e, evaluator, false);
646+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "read");
647+
TestEnforce(e, evaluator, true);
648+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "write");
649+
TestEnforce(e, evaluator, true);
650+
583651
// You should also take the custom data as a parameter when deleting a grouping policy.
584652
// e.RemoveGroupingPolicy("bob", "data2_admin") won't work.
585653
// Or you can remove it by using RemoveFilteredGroupingPolicy().
@@ -602,6 +670,23 @@ TEST(TestModelEnforcer, TestRBACModelWithCustomData) {
602670
TestEnforce(e, evaluator, false);
603671
evaluator = InitializeParams<casbin::DuktapeEvaluator>("bob", "data2", "write");
604672
TestEnforce(e, evaluator, true);
673+
674+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "read");
675+
TestEnforce(e, evaluator, true);
676+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data1", "write");
677+
TestEnforce(e, evaluator, false);
678+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "read");
679+
TestEnforce(e, evaluator, true);
680+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("alice", "data2", "write");
681+
TestEnforce(e, evaluator, true);
682+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "read");
683+
TestEnforce(e, evaluator, false);
684+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data1", "write");
685+
TestEnforce(e, evaluator, false);
686+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "read");
687+
TestEnforce(e, evaluator, false);
688+
evaluator = InitializeParams<casbin::ExprtkEvaluator>("bob", "data2", "write");
689+
TestEnforce(e, evaluator, true);
605690
}
606691

607692
TEST(TestModelEnforcer, TestRBACModelWithPattern) {

0 commit comments

Comments
 (0)