diff --git a/casbin/casbin.vcxproj b/casbin/casbin.vcxproj
index ac39d519..d7b92c3f 100644
--- a/casbin/casbin.vcxproj
+++ b/casbin/casbin.vcxproj
@@ -196,7 +196,7 @@
-
+
@@ -267,14 +267,14 @@
-
-
+
+
diff --git a/casbin/casbin.vcxproj.filters b/casbin/casbin.vcxproj.filters
index 65149081..a3936ced 100644
--- a/casbin/casbin.vcxproj.filters
+++ b/casbin/casbin.vcxproj.filters
@@ -222,9 +222,6 @@
Source Files\persist\file_adapter
-
- Source Files\persist\file_adapter
-
Source Files\persist
@@ -255,6 +252,9 @@
Source Files\ip_parser\parser
+
+ Source Files\persist\file_adapter
+
@@ -272,9 +272,6 @@
Header Files\persist
-
- Header Files\persist
-
Header Files\persist
@@ -416,9 +413,6 @@
Header Files\duktape
-
- Header Files\persist\file_adapter
-
Header Files\effect
@@ -467,5 +461,11 @@
Header Files\model
+
+ Header Files\persist
+
+
+ Header Files\persist\file_adapter
+
\ No newline at end of file
diff --git a/casbin/config/config.cpp b/casbin/config/config.cpp
index 02ac90be..8ed2fe69 100644
--- a/casbin/config/config.cpp
+++ b/casbin/config/config.cpp
@@ -156,9 +156,10 @@ void Config :: Set(string key, string value) {
if (keys.size() >= 2) {
section = keys[0];
option = keys[1];
- } else {
- option = keys[0];
}
+ else
+ option = keys[0];
+
AddConfig(section, option, value);
mtx_lock.unlock();
}
diff --git a/casbin/effect/default_effector.cpp b/casbin/effect/default_effector.cpp
index 8bff2093..eb99fb8d 100644
--- a/casbin/effect/default_effector.cpp
+++ b/casbin/effect/default_effector.cpp
@@ -33,27 +33,25 @@ DefaultEffector* DefaultEffector :: NewDefaultEffector(){
bool DefaultEffector :: MergeEffects(string expr, vector effects, vector results) {
bool result;
- unsigned int number_of_effects = sizeof(effects) / sizeof(effects[0]);
-
- if (!expr.compare("some(where (p_eft == allow))")) {
+ if (!expr.compare("some(where (p.eft == allow))")) {
result = false;
- for(unsigned int index = 0 ; index < number_of_effects ; index++){
+ for(unsigned int index = 0 ; index < effects.size() ; index++){
if (effects[index] == Effect::Allow) {
result = true;
break;
}
}
- } else if (!expr.compare("!some(where (p_eft == deny))")) {
+ } else if (!expr.compare("!some(where (p.eft == deny))")) {
result = true;
- for(unsigned int index = 0 ; index < number_of_effects ; index++){
+ for(unsigned int index = 0 ; index < effects.size(); index++){
if (effects[index] == Effect::Deny) {
result = false;
break;
}
}
- } else if (!expr.compare("some(where (p_eft == allow)) && !some(where (p_eft == deny))")) {
+ } else if (!expr.compare("some(where (p.eft == allow)) && !some(where (p.eft == deny))")) {
result = false;
- for(unsigned int index = 0 ; index < number_of_effects ; index++){
+ for(unsigned int index = 0 ; index < effects.size(); index++){
if (effects[index] == Effect::Allow) {
result = true;
} else if (effects[index] == Effect::Deny) {
@@ -61,9 +59,9 @@ bool DefaultEffector :: MergeEffects(string expr, vector effects, vector
break;
}
}
- } else if (!expr.compare("priority(p_eft) || deny")) {
+ } else if (!expr.compare("priority(p.eft) || deny")) {
result = false;
- for(unsigned int index = 0 ; index < number_of_effects ; index++){
+ for(unsigned int index = 0 ; index < effects.size(); index++){
if (effects[index] != Effect::Indeterminate) {
if (effects[index] == Effect::Allow) {
result = true;
diff --git a/casbin/enforcer.cpp b/casbin/enforcer.cpp
index 7c514b23..105934c3 100644
--- a/casbin/enforcer.cpp
+++ b/casbin/enforcer.cpp
@@ -18,6 +18,8 @@
#include "pch.h"
+#include
+
#include "./enforcer.h"
#include "./persist/watcher_ex.h"
#include "./persist/file_adapter/file_adapter.h"
@@ -37,117 +39,123 @@ bool Enforcer :: enforce(string matcher, Scope scope) {
// }()
this->func_map.scope = scope;
+ this->func_map.LoadFunctionMap();
- if(this->enabled)
+ if(!this->enabled)
return true;
// for(unordered_map :: iterator it = this->fm.fmap.begin() ; it != this->fm.fmap.end() ; it++)
// this->fm.AddFunction(it->first, it->second);
- string expString;
+ string exp_string;
if(matcher == "")
- expString = this->model->m["m"].assertion_map["m"]->value;
+ exp_string = this->model->m["m"].assertion_map["m"]->value;
else
- expString = matcher;
+ exp_string = matcher;
+
unordered_map rm_map;
bool ok = this->model->m.find("g") != this->model->m.end();
+
if(ok) {
for(unordered_map :: iterator it = this->model->m["g"].assertion_map.begin() ; it != this->model->m["g"].assertion_map.end() ; it++){
RoleManager* rm = it->second->rm;
- int index = int(expString.find((it->first)+"("));
+ int char_count = int(count(it->second->value.begin(), it->second->value.end(), '_'));
+ int index = int(exp_string.find((it->first)+"("));
if(index != string::npos)
- expString.insert(index+(it->first+"(").length()-1, (it->first)+"_rm");
- PushPointer(this->func_map.scope, (void *)rm, (it->first)+"_rm");
- this->func_map.AddFunction(it->first, GFunction);
+ exp_string.insert(index+(it->first+"(").length(), "rm, ");
+ PushPointer(this->func_map.scope, (void *)rm, "rm");
+ this->func_map.AddFunction(it->first, GFunction, char_count + 1);
}
}
- unordered_map pIntTokens;
+ unordered_map p_int_tokens;
for(int i = 0 ; i < this->model->m["p"].assertion_map["p"]->tokens.size() ; i++)
- pIntTokens[this->model->m["p"].assertion_map["p"]->tokens[i]] = i;
+ p_int_tokens[this->model->m["p"].assertion_map["p"]->tokens[i]] = i;
- vector pTokens = this->model->m["p"].assertion_map["p"]->tokens;
+ vector p_tokens = this->model->m["p"].assertion_map["p"]->tokens;
- vector policyEffects;
- vector matcherResults;
+ int policy_len = int(this->model->m["p"].assertion_map["p"]->policy.size());
- int policyLen = int(this->model->m["p"].assertion_map["p"]->policy.size());
+ vector policy_effects(policy_len, Effect :: Indeterminate);
+ vector matcher_results;
- if(policyLen != 0) {
+ if(policy_len != 0) {
if(this->model->m["r"].assertion_map["r"]->tokens.size() != this->func_map.GetRLen())
return false;
//TODO
- for( int i = 0 ; i < this->model->m["p"].assertion_map["p"]->policy.size() ; i++){
+ for( int i = 0 ; i < policy_len ; i++){
// log.LogPrint("Policy Rule: ", pvals)
- vector pVals = this->model->m["p"].assertion_map["p"]->policy[i];
- if(this->model->m["p"].assertion_map["p"]->tokens.size() != pVals.size())
+ vector p_vals = this->model->m["p"].assertion_map["p"]->policy[i];
+ if(this->model->m["p"].assertion_map["p"]->tokens.size() != p_vals.size())
return false;
PushObject(this->func_map.scope, "p");
- for(int j = 0 ; j < pTokens.size() ; j++){
- int index = int(pTokens[j].find("_"));
- string token = pTokens[j].substr(index+1);
- PushStringPropToObject(this->func_map.scope, "p", pVals[j], token);
+ for(int j = 0 ; j < p_tokens.size() ; j++){
+ int index = int(p_tokens[j].find("_"));
+ string token = p_tokens[j].substr(index+1);
+ PushStringPropToObject(this->func_map.scope, "p", p_vals[j], token);
}
- this->func_map.Eval(expString);
+ this->func_map.Evaluate(exp_string);
+
//TODO
// log.LogPrint("Result: ", result)
-
if(CheckType(this->func_map.scope) == Type :: Bool){
bool result = GetBoolean(this->func_map.scope);
if(!result) {
- policyEffects[i] = Effect :: Indeterminate;
+ policy_effects[i] = Effect :: Indeterminate;
continue;
}
}
else if(CheckType(this->func_map.scope) == Type :: Float){
bool result = GetFloat(this->func_map.scope);
if(result == 0) {
- policyEffects[i] = Effect :: Indeterminate;
+ policy_effects[i] = Effect :: Indeterminate;
continue;
} else
- matcherResults[i] = result;
+ matcher_results[i] = result;
}
else
return false;
- bool ok = pIntTokens.find("p_eft") != pIntTokens.end();
- if(ok) {
- int j = pIntTokens["p_eft"];
- string eft = pVals[j];
+ bool is_p_eft = p_int_tokens.find("p_eft") != p_int_tokens.end();
+ if(is_p_eft) {
+ int j = p_int_tokens["p_eft"];
+ string eft = p_vals[j];
if(eft == "allow")
- policyEffects[i] = Effect :: Allow;
+ policy_effects[i] = Effect :: Allow;
else if(eft == "deny")
- policyEffects[i] = Effect :: Deny;
+ policy_effects[i] = Effect :: Deny;
else
- policyEffects[i] = Effect :: Indeterminate;
+ policy_effects[i] = Effect :: Indeterminate;
}
else
- policyEffects[i] = Effect :: Allow;
+ policy_effects[i] = Effect :: Allow;
if(this->model->m["e"].assertion_map["e"]->value == "priority(p_eft) || deny")
break;
}
} else {
- this->func_map.Eval(expString);
+ bool isValid = this->func_map.Evaluate(exp_string);
+ if(!isValid)
+ return false;
bool result = this->func_map.GetBooleanResult();
+
//TODO
// log.LogPrint("Result: ", result)
-
if(result)
- policyEffects[0] = Effect::Allow;
+ policy_effects.push_back(Effect::Allow);
else
- policyEffects[0] = Effect::Indeterminate;
+ policy_effects.push_back(Effect::Indeterminate);
}
//TODO
// log.LogPrint("Rule Results: ", policyEffects)
- bool result = this->eft->MergeEffects(this->model->m["e"].assertion_map["e"]->value, policyEffects, matcherResults);
-
+ bool result = this->eft->MergeEffects(this->model->m["e"].assertion_map["e"]->value, policy_effects, matcher_results);
+
return result;
}
@@ -198,7 +206,7 @@ Enforcer* Enforcer :: NewEnforcer(Model* m, Adapter* adapter) {
e->Initialize();
- if (e->adapter != NULL) {
+ if (e->adapter->file_path != "") {
e->LoadPolicy();
}
return e;
@@ -344,7 +352,6 @@ void Enforcer :: ClearPolicy() {
void Enforcer :: LoadPolicy() {
this->model->ClearPolicy();
this->adapter->LoadPolicy(this->model);
-
this->model->PrintPolicy();
if(this->auto_build_role_links) {
diff --git a/casbin/enforcer.h b/casbin/enforcer.h
index 7234622a..9f3ef161 100644
--- a/casbin/enforcer.h
+++ b/casbin/enforcer.h
@@ -20,7 +20,7 @@
#include "./rbac/role_manager.h"
#include "./model/function.h"
#include "./enforcer_interface.h"
-#include "./persist/adapter_filtered.h"
+#include "./persist/filtered_adapter.h"
// Enforcer is the main interface for authorization enforcement and policy management.
class Enforcer : public IEnforcer{
@@ -33,7 +33,6 @@ class Enforcer : public IEnforcer{
Adapter* adapter;
Watcher* watcher;
- RoleManager* rm;
bool enabled;
bool auto_save;
@@ -45,6 +44,8 @@ class Enforcer : public IEnforcer{
public:
+ RoleManager* rm;
+
/**
* Enforcer is the default constructor.
*/
@@ -190,7 +191,7 @@ class Enforcer : public IEnforcer{
bool RemoveNamedGroupingPolicy(string ptype, vector params);
bool RemoveNamedGroupingPolicies(string p_type, vector> rules);
bool RemoveFilteredNamedGroupingPolicy(string ptype, int field_index, vector field_values);
- void AddFunction(string name, Function);
+ void AddFunction(string name, Function function, Index nargs);
/*RBAC API member functions.*/
vector GetRolesForUser(string name);
diff --git a/casbin/enforcer_interface.h b/casbin/enforcer_interface.h
index 7b1424fe..0175a6ba 100644
--- a/casbin/enforcer_interface.h
+++ b/casbin/enforcer_interface.h
@@ -119,7 +119,7 @@ class IEnforcer {
virtual bool RemoveNamedGroupingPolicy(string ptype, vector params) = 0;
virtual bool RemoveNamedGroupingPolicies(string p_type, vector> rules) = 0;
virtual bool RemoveFilteredNamedGroupingPolicy(string ptype, int fieldIndex, vector fieldValues) = 0;
- virtual void AddFunction(string name, Function) = 0;
+ virtual void AddFunction(string name, Function function, Index nargs) = 0;
/* Internal API member functions */
virtual bool addPolicy(string sec, string ptype, vector rule) = 0;
diff --git a/casbin/internal_api.cpp b/casbin/internal_api.cpp
index 33597955..efb67b44 100644
--- a/casbin/internal_api.cpp
+++ b/casbin/internal_api.cpp
@@ -22,6 +22,7 @@
#include "./persist/batch_adapter.h"
#include "./util/util.h"
#include "./persist/watcher_ex.h"
+#include "./exception/unsupported_operation_exception.h"
// addPolicy adds a rule to the current policy.
bool Enforcer :: addPolicy(string sec, string p_type, vector rule) {
@@ -34,8 +35,13 @@ bool Enforcer :: addPolicy(string sec, string p_type, vector rule) {
this->BuildIncrementalRoleLinks(policy_add, p_type, rules);
}
- if (this->adapter != NULL && this->auto_save)
- this->adapter->AddPolicy(sec, p_type, rule);
+ if (this->adapter != NULL && this->auto_save) {
+ try {
+ this->adapter->AddPolicy(sec, p_type, rule);
+ }
+ catch(UnsupportedOperationException e) {
+ }
+ }
if (this->watcher != NULL && this->auto_notify_watcher) {
if (IsInstanceOf(this->watcher)) {
@@ -79,9 +85,14 @@ bool Enforcer :: removePolicy(string sec, string p_type, vector rule) {
vector> rules{rule};
this->BuildIncrementalRoleLinks(policy_add, p_type, rules);
}
-
- if(this->adapter != NULL && this->auto_save)
- this->adapter->RemovePolicy(sec, p_type, rule);
+
+ if (this->adapter != NULL && this->auto_save) {
+ try {
+ this->adapter->RemovePolicy(sec, p_type, rule);
+ }
+ catch (UnsupportedOperationException e) {
+ }
+ }
if(this->watcher !=NULL && this->auto_notify_watcher){
if (IsInstanceOf(this->watcher)) {
@@ -127,8 +138,13 @@ bool Enforcer :: removeFilteredPolicy(string sec, string p_type, int field_index
if (sec == "g")
this->BuildIncrementalRoleLinks(policy_remove, p_type, effects);
- if(this->adapter != NULL && this->auto_save)
- this->adapter->RemoveFilteredPolicy(sec, p_type, field_index, field_values);
+ if (this->adapter != NULL && this->auto_save) {
+ try {
+ this->adapter->RemoveFilteredPolicy(sec, p_type, field_index, field_values); \
+ }
+ catch (UnsupportedOperationException e) {
+ }
+ }
if (this->watcher !=NULL && this->auto_notify_watcher) {
if (IsInstanceOf(this->watcher)) {
diff --git a/casbin/management_api.cpp b/casbin/management_api.cpp
index f2dae877..00833475 100644
--- a/casbin/management_api.cpp
+++ b/casbin/management_api.cpp
@@ -304,6 +304,6 @@ bool Enforcer :: RemoveFilteredNamedGroupingPolicy(string p_type, int field_inde
}
// AddFunction adds a customized function.
-void Enforcer :: AddFunction(string name, Function function) {
- this->func_map.AddFunction(name, function);
+void Enforcer :: AddFunction(string name, Function function, Index nargs) {
+ this->func_map.AddFunction(name, function, nargs);
}
\ No newline at end of file
diff --git a/casbin/model/Function.h b/casbin/model/Function.h
index 6a80fcb8..1903a646 100644
--- a/casbin/model/Function.h
+++ b/casbin/model/Function.h
@@ -30,16 +30,18 @@ class FunctionMap {
FunctionMap();
+ void ProcessFunctions(string expression);
+
int GetRLen();
- void Eval(string expression);
+ bool Evaluate(string expression);
bool GetBooleanResult();
// AddFunction adds an expression function.
- void AddFunction(string func_name, Function f, Index nargs = VARARGS);
+ void AddFunction(string func_name, Function f, Index nargs);
- void AddFunctionPropToR(string identifier, Function func, unsigned int nargs = VARARGS);
+ void AddFunctionPropToR(string identifier, Function func, Index nargs);
void AddBooleanPropToR(string identifier, bool val);
@@ -60,7 +62,7 @@ class FunctionMap {
void AddObjectPropToR(string identifier);
// LoadFunctionMap loads an initial function map.
- static FunctionMap LoadFunctionMap();
+ void LoadFunctionMap();
};
diff --git a/casbin/model/function.cpp b/casbin/model/function.cpp
index 606652d8..55856fb5 100644
--- a/casbin/model/function.cpp
+++ b/casbin/model/function.cpp
@@ -19,9 +19,37 @@
#include "pch.h"
#include "./function.h"
+#include "../util/util.h"
FunctionMap :: FunctionMap(){
- scope = duk_create_heap_default();
+ scope = InitializeScope();
+}
+
+void FunctionMap :: ProcessFunctions(string expression){
+ for(unordered_map :: iterator it = this->func_map.begin() ; it != this->func_map.end() ; it++){
+ int index = int(expression.find((it->first)+"("));
+
+ if(index != string::npos){
+ int close_index = int(expression.find(")", index));
+ int start = index + int(((it->first)+"(").length());
+
+ string function_params = expression.substr(start, close_index-start);
+ FetchIdentifier(this->scope, it->first);
+ vector params = Split(function_params, ",");
+
+ for(int i=0;iscope, Trim(params[i]));
+ else{
+ params[i] = params[i].replace(quote_index, 1, "'");
+ int second_quote_index = int(params[i].find("\"", quote_index+1));
+ params[i] = params[i].replace(second_quote_index, 1, "'");
+ Get(this->scope, Trim(params[i]));
+ }
+ }
+ }
+ }
}
int FunctionMap :: GetRLen(){
@@ -31,8 +59,9 @@ int FunctionMap :: GetRLen(){
return -1;
}
-void FunctionMap :: Eval(string expression){
- duk_eval_string(scope, expression.c_str());
+bool FunctionMap :: Evaluate(string expression){
+ ProcessFunctions(expression);
+ return Eval(scope, expression);
}
bool FunctionMap :: GetBooleanResult(){
@@ -42,11 +71,11 @@ bool FunctionMap :: GetBooleanResult(){
// AddFunction adds an expression function.
void FunctionMap :: AddFunction(string func_name, Function f, Index nargs) {
func_map[func_name] = f;
- PushFunction(this->scope, f, nargs, func_name);
+ PushFunction(this->scope, f, func_name, nargs);
}
-void FunctionMap :: AddFunctionPropToR(string identifier, Function func, unsigned int nargs){
- PushFunctionPropToObject(scope, "r", func, nargs, identifier);
+void FunctionMap :: AddFunctionPropToR(string identifier, Function func, Index nargs){
+ PushFunctionPropToObject(scope, "r", func, identifier, nargs);
}
void FunctionMap :: AddBooleanPropToR(string identifier, bool val){
@@ -86,14 +115,10 @@ void FunctionMap :: AddObjectPropToR(string identifier){
}
// LoadFunctionMap loads an initial function map.
-FunctionMap FunctionMap :: LoadFunctionMap() {
- FunctionMap func_map;
-
- func_map.AddFunction("keyMatch", KeyMatch);
- func_map.AddFunction("keyMatch2", KeyMatch2);
- func_map.AddFunction("keyMatch3", KeyMatch3);
- func_map.AddFunction("regexMatch", RegexMatch);
- func_map.AddFunction("ipMatch", IPMatch);
-
- return func_map;
+void FunctionMap :: LoadFunctionMap() {
+ AddFunction("keyMatch", KeyMatch, 2);
+ AddFunction("keyMatch2", KeyMatch2, 2);
+ AddFunction("keyMatch3", KeyMatch3, 2);
+ AddFunction("regexMatch", RegexMatch, 2);
+ AddFunction("ipMatch", IPMatch, 2);
}
\ No newline at end of file
diff --git a/casbin/model/model.cpp b/casbin/model/model.cpp
index 080111a9..e2c8e604 100644
--- a/casbin/model/model.cpp
+++ b/casbin/model/model.cpp
@@ -57,8 +57,9 @@ bool Model :: HasSection(string sec) {
void Model :: LoadSection(Model* model, ConfigInterface* cfg, string sec) {
int i = 1;
while(true) {
- if (!LoadAssertion(model, cfg, sec, sec+GetKeySuffix(i)))
+ if (!LoadAssertion(model, cfg, sec, sec+GetKeySuffix(i))){
break;
+ }
else
i++;
}
@@ -93,11 +94,12 @@ bool Model :: AddDef(string sec, string key, string value) {
ast->tokens[i] = key + "_" + Trim(ast->tokens[i]);
}
else
- ast->value = RemoveComments(EscapeAssertion(ast->value));
+ ast->value = RemoveComments(ast->value);
- if (m.find(sec) != m.end())
+ if (m.find(sec) == m.end())
m[sec] = AssertionMap();
ast->policy = vector>{};
+
m[sec].assertion_map[key] = ast;
return true;
@@ -160,9 +162,8 @@ void Model :: BuildIncrementalRoleLinks(RoleManager* rm, policy_op op, string se
// BuildRoleLinks initializes the roles in RBAC.
void Model :: BuildRoleLinks(RoleManager* rm) {
- for (unordered_map :: iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++) {
+ for (unordered_map :: iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++)
(it->second)->BuildRoleLinks(rm);
- }
}
// PrintPolicy prints the policy to log.
@@ -186,13 +187,15 @@ void Model :: PrintPolicy() {
// ClearPolicy clears all current policy.
void Model :: ClearPolicy() {
- for (unordered_map :: iterator it = this->m["p"].assertion_map.begin() ; it != this->m["p"].assertion_map.end() ; it++)
+ for (unordered_map :: iterator it = this->m["p"].assertion_map.begin() ; it != this->m["p"].assertion_map.end() ; it++){
if((it->second)->policy.size() > 0)
(it->second)->policy.clear();
+ }
- for (unordered_map :: iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++)
+ for (unordered_map :: iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++){
if((it->second)->policy.size() > 0)
(it->second)->policy.clear();
+ }
}
// GetPolicy gets all rules in a policy.
@@ -221,7 +224,7 @@ vector> Model :: GetFilteredPolicy(string sec, string p_type, int
// HasPolicy determines whether a model has the specified policy rule.
bool Model :: HasPolicy(string sec, string p_type, vector rule) {
- vector> policy(m[sec].assertion_map[p_type]->policy);
+ vector> policy = m[sec].assertion_map[p_type]->policy;
for(int i=0 ; i < policy.size() ; i++)
if (ArrayEquals(rule, policy[i]))
return true;
@@ -235,6 +238,7 @@ bool Model :: AddPolicy(string sec, string p_type, vector rule) {
m[sec].assertion_map[p_type]->policy.push_back(rule);
return true;
}
+
return false;
}
@@ -265,17 +269,19 @@ bool Model :: RemovePolicy(string sec, string p_type, vector rule) {
// RemovePolicies removes policy rules from the model.
bool Model :: RemovePolicies(string sec, string p_type, vector> rules) {
OUTER: for (int j = 0; j < rules.size(); j++) {
- for (int i = 0; i < this->m[sec].assertion_map[p_type]->policy.size(); i++)
- if (ArrayEquals(rules[j], this->m[sec].assertion_map[p_type]->policy[i])) {
+ for (int i = 0; i < this->m[sec].assertion_map[p_type]->policy.size(); i++){
+ if (ArrayEquals(rules[j], this->m[sec].assertion_map[p_type]->policy[i]))
goto OUTER;
}
return false;
}
- for (int j = 0; j < rules.size(); j++)
- for (int i = 0; i < this->m[sec].assertion_map[p_type]->policy.size(); i++)
+ for (int j = 0; j < rules.size(); j++){
+ for (int i = 0; i < this->m[sec].assertion_map[p_type]->policy.size(); i++){
if (ArrayEquals(rules[j], this->m[sec].assertion_map[p_type]->policy[i]))
this->m[sec].assertion_map[p_type]->policy.erase(this->m[sec].assertion_map[p_type]->policy.begin() + i);
+ }
+ }
return true;
}
@@ -288,8 +294,8 @@ pair>> Model :: RemoveFilteredPolicy(string sec, str
bool res = false;
for(int i = 0 ; i < policy.size() ; i++){
bool matched = true;
- for (int i = 0 ; i < field_values.size() ; i++) {
- if (field_values[i] != "" && (policy[i])[field_index+i] != field_values[i]) {
+ for (int j = 0 ; j < field_values.size() ; j++) {
+ if (field_values[j] != "" && (policy[i])[field_index+j] != field_values[j]) {
matched = false;
break;
}
diff --git a/casbin/model/scope_config.cpp b/casbin/model/scope_config.cpp
index 1df22cf7..712c99ac 100644
--- a/casbin/model/scope_config.cpp
+++ b/casbin/model/scope_config.cpp
@@ -64,7 +64,7 @@ void PushObjectValue(Scope scope){
duk_push_global_object(scope);
}
-void PushFunction(Scope scope, Function f, int nargs, string fname) {
+void PushFunction(Scope scope, Function f, string fname, int nargs) {
duk_push_c_function(scope, f, (Index)nargs);
duk_put_global_string(scope, fname.c_str());
}
@@ -110,13 +110,13 @@ void PushPointer(Scope scope, void * ptr, string identifier){
}
void PushObject(Scope scope, string identifier){
- duk_push_global_object(scope);
+ duk_push_object(scope);
duk_put_global_string(scope, identifier.c_str());
duk_push_int(scope, 0);
duk_put_global_string(scope, (identifier+"len").c_str());
}
-void PushFunctionPropToObject(Scope scope, string obj, Function f, int nargs, string fname) {
+void PushFunctionPropToObject(Scope scope, string obj, Function f, string fname, int nargs) {
duk_get_global_string(scope, obj.c_str());
duk_push_c_function(scope, f, nargs);
duk_put_prop_string(scope, -2, fname.c_str());
@@ -223,4 +223,17 @@ string GetString(Scope scope, int id){
void* GetPointer(Scope scope, int id){
return (void *)duk_to_pointer(scope, (Index)id);
+}
+
+void Get(Scope scope, string identifier){
+ Eval(scope, identifier);
+}
+
+bool Eval(Scope scope, string expression){
+ PushStringValue(scope, expression);
+ return duk_peval(scope)==0;
+}
+
+void EvalNoResult(Scope scope, string expression){
+ duk_eval_string_noresult(scope, expression.c_str());
}
\ No newline at end of file
diff --git a/casbin/model/scope_config.h b/casbin/model/scope_config.h
index 3ffd9a7b..7552f8e3 100644
--- a/casbin/model/scope_config.h
+++ b/casbin/model/scope_config.h
@@ -50,7 +50,7 @@ void PushDoubleValue(Scope scope, double d);
void PushStringValue(Scope scope, string s);
void PushPointerValue(Scope scope, void * ptr);
void PushObjectValue(Scope scope);
-void PushFunction(Scope scope, Function f, int nargs, string fname);
+void PushFunction(Scope scope, Function f, string fname, int nargs);
void PushBoolean(Scope scope, bool expression, string identifier);
void PushTrue(Scope scope, string identifier);
void PushFalse(Scope scope, string identifier);
@@ -60,7 +60,7 @@ void PushDouble(Scope scope, double d, string identifier);
void PushString(Scope scope, string s, string identifier);
void PushPointer(Scope scope, void * ptr, string identifier);
void PushObject(Scope scope, string identifier = "r");
-void PushFunctionPropToObject(Scope scope, string obj, Function f, int nargs, string fname);
+void PushFunctionPropToObject(Scope scope, string obj, Function f, string fname, int nargs);
void PushBooleanPropToObject(Scope scope, string obj, bool expression, string identifier);
void PushTruePropToObject(Scope scope, string obj, string identifier);
void PushFalsePropToObject(Scope scope, string obj, string identifier);
@@ -79,5 +79,8 @@ float GetFloat(Scope scope, int id = -1);
double GetDouble(Scope scope, int id = -1);
string GetString(Scope scope, int id = -1);
void* GetPointer(Scope scope, int id = -1);
+void Get(Scope scope, string identifier);
+bool Eval(Scope scope, string expression);
+void EvalNoResult(Scope scope, string expression);
#endif
\ No newline at end of file
diff --git a/casbin/persist.h b/casbin/persist.h
index 6f3bb043..1a6e8f97 100644
--- a/casbin/persist.h
+++ b/casbin/persist.h
@@ -18,7 +18,7 @@
#define CASBIN_CPP_PERSIST
#include "./persist/adapter.h"
-#include "./persist/adapter_filtered.h"
+#include "./persist/filtered_adapter.h"
#include "./persist/batch_adapter.h"
#include "./persist/default_watcher.h"
#include "./persist/default_watcher_ex.h"
@@ -27,6 +27,6 @@
#include "./persist/file_adapter/batch_file_adapter.h"
#include "./persist/file_adapter/file_adapter.h"
-#include "./persist/file_adapter/filtered_adapter.h"
+#include "./persist/file_adapter/filtered_file_adapter.h"
#endif
\ No newline at end of file
diff --git a/casbin/persist/adapter.cpp b/casbin/persist/adapter.cpp
index 9363572a..16c7e265 100644
--- a/casbin/persist/adapter.cpp
+++ b/casbin/persist/adapter.cpp
@@ -23,18 +23,19 @@
// LoadPolicyLine loads a text line as a policy rule to model.
void LoadPolicyLine(string line, Model* model) {
- if(line == "" || line.find("#")==0) {
+ if(line == "" || line.find("#")==0)
return;
- }
vector tokens = Split(line, ",", -1);
- for (int i = 0; i < tokens.size(); i++) {
+ for (int i = 0; i < tokens.size(); i++)
tokens[i] = Trim(tokens[i]);
- }
string key = tokens[0];
string sec = key.substr(0,1);
vector new_tokens(tokens.begin()+1, tokens.end());
-
+
+ if (model->m.find(sec) == model->m.end())
+ model->m[sec] = AssertionMap();
+
(model->m[sec].assertion_map[key]->policy).push_back(new_tokens);
}
\ No newline at end of file
diff --git a/casbin/persist/file_adapter/file_adapter.cpp b/casbin/persist/file_adapter/file_adapter.cpp
index b918d4be..21c4811f 100644
--- a/casbin/persist/file_adapter/file_adapter.cpp
+++ b/casbin/persist/file_adapter/file_adapter.cpp
@@ -20,9 +20,8 @@ FileAdapter* FileAdapter :: NewAdapter(string file_path) {
// LoadPolicy loads all policy rules from the storage.
void FileAdapter :: LoadPolicy(Model* model) {
- if (this->file_path == "") {
+ if (this->file_path == "")
throw CasbinAdapterException("Invalid file path, file path cannot be empty");
- }
this->LoadPolicyFile(model, LoadPolicyLine);
}
diff --git a/casbin/persist/file_adapter/filtered_adapter.cpp b/casbin/persist/file_adapter/filtered_file_adapter.cpp
similarity index 75%
rename from casbin/persist/file_adapter/filtered_adapter.cpp
rename to casbin/persist/file_adapter/filtered_file_adapter.cpp
index 65745327..8f123c68 100644
--- a/casbin/persist/file_adapter/filtered_adapter.cpp
+++ b/casbin/persist/file_adapter/filtered_file_adapter.cpp
@@ -4,14 +4,14 @@
#include
-#include "./filtered_adapter.h"
+#include "./filtered_file_adapter.h"
#include "../../exception/io_exception.h"
#include "../../exception/casbin_adapter_exception.h"
#include "../../util/util.h"
using namespace std;
-bool FilteredAdapter :: filterLine(string line, Filter* filter) {
+bool FilteredFileAdapter :: filterLine(string line, Filter* filter) {
if (filter == NULL)
return false;
@@ -29,7 +29,7 @@ bool FilteredAdapter :: filterLine(string line, Filter* filter) {
return filterWords(p, filter_slice);
}
-bool FilteredAdapter :: filterWords(vector line, vector filter) {
+bool FilteredFileAdapter :: filterWords(vector line, vector filter) {
if (line.size() < filter.size()+1)
return true;
@@ -44,7 +44,7 @@ bool FilteredAdapter :: filterWords(vector line, vector filter)
return skip_line;
}
-void FilteredAdapter :: loadFilteredPolicyFile(Model* model, Filter* filter, void (*handler)(string, Model*)) {
+void FilteredFileAdapter :: loadFilteredPolicyFile(Model* model, Filter* filter, void (*handler)(string, Model*)) {
ifstream out_file;
try {
out_file.open(this->file_path);
@@ -66,21 +66,21 @@ void FilteredAdapter :: loadFilteredPolicyFile(Model* model, Filter* filter, voi
}
// NewFilteredAdapter is the constructor for FilteredAdapter.
-FilteredAdapter* FilteredAdapter :: NewFilteredAdapter(string file_path) {
- FilteredAdapter* a = new FilteredAdapter;
+FilteredFileAdapter* FilteredFileAdapter :: NewFilteredAdapter(string file_path) {
+ FilteredFileAdapter* a = new FilteredFileAdapter;
a->filtered = true;
a->file_path = file_path;
return a;
}
// LoadPolicy loads all policy rules from the storage.
-void FilteredAdapter :: LoadPolicy(Model* model) {
+void FilteredFileAdapter :: LoadPolicy(Model* model) {
this->filtered = false;
this->FileAdapter::LoadPolicy(model);
}
// LoadFilteredPolicy loads only policy rules that match the filter.
-void FilteredAdapter :: LoadFilteredPolicy(Model* model, Filter* filter) {
+void FilteredFileAdapter :: LoadFilteredPolicy(Model* model, Filter* filter) {
if (filter == NULL) {
this->LoadPolicy(model);
}
@@ -94,12 +94,12 @@ void FilteredAdapter :: LoadFilteredPolicy(Model* model, Filter* filter) {
}
// IsFiltered returns true if the loaded policy has been filtered.
-bool FilteredAdapter :: IsFiltered() {
+bool FilteredFileAdapter :: IsFiltered() {
return this->filtered;
}
// SavePolicy saves all policy rules to the storage.
-void FilteredAdapter :: SavePolicy(Model* model) {
+void FilteredFileAdapter :: SavePolicy(Model* model) {
if (this->filtered) {
throw CasbinAdapterException("Cannot save a filtered policy");
}
diff --git a/casbin/persist/file_adapter/filtered_adapter.h b/casbin/persist/file_adapter/filtered_file_adapter.h
similarity index 73%
rename from casbin/persist/file_adapter/filtered_adapter.h
rename to casbin/persist/file_adapter/filtered_file_adapter.h
index a2e6d193..28f6487a 100644
--- a/casbin/persist/file_adapter/filtered_adapter.h
+++ b/casbin/persist/file_adapter/filtered_file_adapter.h
@@ -2,16 +2,9 @@
#define CASBIN_CPP_PERSIST_FILE_ADAPTER_FILTERED_ADAPTER
#include "file_adapter.h"
+#include "../filtered_adapter.h"
-// Filter defines the filtering rules for a FilteredAdapter's policy. Empty values
-// are ignored, but all others must match the filter.
-class Filter{
- public:
- vector P;
- vector G;
-};
-
-class FilteredAdapter : public FileAdapter {
+class FilteredFileAdapter : public FileAdapter, public FilteredAdapter {
private:
static bool filterLine(string line, Filter* filter);
@@ -23,7 +16,7 @@ class FilteredAdapter : public FileAdapter {
public:
// NewFilteredAdapter is the constructor for FilteredAdapter.
- static FilteredAdapter* NewFilteredAdapter(string file_path);
+ static FilteredFileAdapter* NewFilteredAdapter(string file_path);
// LoadPolicy loads all policy rules from the storage.
void LoadPolicy(Model* model);
diff --git a/casbin/persist/Adapter_Filtered.h b/casbin/persist/filtered_adapter.h
similarity index 75%
rename from casbin/persist/Adapter_Filtered.h
rename to casbin/persist/filtered_adapter.h
index 5d7023e7..70f29e18 100644
--- a/casbin/persist/Adapter_Filtered.h
+++ b/casbin/persist/filtered_adapter.h
@@ -19,13 +19,20 @@
#include "./adapter.h"
+// Filter defines the filtering rules for a FilteredAdapter's policy. Empty values
+// are ignored, but all others must match the filter.
+class Filter{
+ public:
+ vector P;
+ vector G;
+};
+
// FilteredAdapter is the interface for Casbin adapters supporting filtered policies.
-class FilteredAdapter : public Adapter {
+class FilteredAdapter : virtual public Adapter {
public:
// LoadFilteredPolicy loads only policy rules that match the filter.
- template
- void LoadFilteredPolicy(Model model, Filter filter);
+ void LoadFilteredPolicy(Model* model, Filter* filter);
// IsFiltered returns true if the loaded policy has been filtered.
virtual bool IsFiltered() = 0;
};
diff --git a/casbin/rbac/default_role_manager.cpp b/casbin/rbac/default_role_manager.cpp
index 029f4faf..6f09536d 100644
--- a/casbin/rbac/default_role_manager.cpp
+++ b/casbin/rbac/default_role_manager.cpp
@@ -38,13 +38,13 @@ void Role :: AddRole(Role* role) {
void Role :: DeleteRole(Role* role) {
for (int i = 0; i < roles.size();i++) {
- if (!roles[i]->name.compare(role->name))
+ if (roles[i]->name == role->name)
roles.erase(roles.begin()+i);
}
}
bool Role :: HasRole(string name, int hierarchy_level) {
- if (!this->name.compare(name))
+ if (this->name == name)
return true;
if (hierarchy_level <= 0)
@@ -60,7 +60,7 @@ bool Role :: HasRole(string name, int hierarchy_level) {
bool Role :: HasDirectRole(string name) {
for(int i = 0 ; i < roles.size() ; i++){
- if (!roles[i]->name.compare(name))
+ if (roles[i]->name == name)
return true;
}
@@ -68,15 +68,24 @@ bool Role :: HasDirectRole(string name) {
}
string Role :: ToString() {
+ if(this->roles.size()==0)
+ return "";
+
string names = "";
+ if(this->roles.size() != 1)
+ names += "(";
+
for (int i = 0; i < roles.size(); i ++) {
Role* role = roles[i];
- if (i == 0) {
- names.append(role->name);
- } else {
- names.append(", " + role->name);
- }
+ if (i == 0)
+ names += role->name;
+ else
+ names += ", " + role->name;
}
+
+ if(this->roles.size() != 1)
+ names += ")";
+
return name + " < " + names;
}
@@ -116,7 +125,7 @@ Role* DefaultRoleManager :: CreateRole(string name) {
if (this->matching_func(name, it->first) && name!=it->first) {
Role* role1;
bool ok1 = this->all_roles.find(it->first) != this->all_roles.end();
- if (!ok) {
+ if (!ok1) {
all_roles[it->first] = Role :: NewRole(it->first);
role1 = all_roles[it->first];
} else
@@ -145,12 +154,11 @@ DefaultRoleManager* DefaultRoleManager :: NewRoleManager(int max_hierarchy_level
// e.BuildRoleLinks must be called after AddMatchingFunc().
//
// example: e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc('matcher', util.KeyMatch)
-void DefaultRoleManager :: AddMatchingFunc(string name, MatchingFunc fn) {
+void DefaultRoleManager :: AddMatchingFunc(MatchingFunc fn) {
this->has_pattern = true;
this->matching_func = fn;
}
-
/**
* clear clears all stored data and resets the role manager to the initial state.
*/
@@ -208,7 +216,6 @@ bool DefaultRoleManager :: HasLink(string name1, string name2, vector do
if (!name1.compare(name2))
return true;
-
if (!HasRole(name1) || !HasRole(name2))
return false;
diff --git a/casbin/rbac/default_role_manager.h b/casbin/rbac/default_role_manager.h
index ecb0571b..b3c838c7 100644
--- a/casbin/rbac/default_role_manager.h
+++ b/casbin/rbac/default_role_manager.h
@@ -75,7 +75,7 @@ class DefaultRoleManager : public RoleManager {
// e.BuildRoleLinks must be called after AddMatchingFunc().
//
// example: e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc('matcher', util.KeyMatch)
- void AddMatchingFunc(string name, MatchingFunc fn);
+ void AddMatchingFunc(MatchingFunc fn);
/**
* clear clears all stored data and resets the role manager to the initial state.
diff --git a/casbin/util/built_in_functions.cpp b/casbin/util/built_in_functions.cpp
index 9cd05e05..82da4eb8 100644
--- a/casbin/util/built_in_functions.cpp
+++ b/casbin/util/built_in_functions.cpp
@@ -20,6 +20,7 @@
#include
+#include "../model/function.h"
#include "./built_in_functions.h"
#include "../rbac/role_manager.h"
#include "./util.h"
@@ -37,20 +38,20 @@ ReturnType KeyMatch(Scope scope) {
string key1 = GetString(scope, 0);
string key2 = GetString(scope, 1);
+ PushBooleanValue(scope, KeyMatch(key1, key2));
+ return RETURN_RESULT;
+}
+
+bool KeyMatch(string key1, string key2) {
size_t pos = key2.find("*");
- if (pos == string :: npos) {
- PushBooleanValue(scope, key1 == key2);
- return RETURN_RESULT;
- }
+ if (pos == string :: npos)
+ return key1 == key2;
- if (key1.length() > pos) {
- PushBooleanValue(scope, key1.substr(0, pos) == key2.substr(0, pos));
- return RETURN_RESULT;
- }
+ if (key1.length() > pos)
+ return key1.substr(0, pos) == key2.substr(0, pos);
- PushBooleanValue(scope, key1 == key2.substr(0, pos));
- return RETURN_RESULT;
+ return key1 == key2.substr(0, pos);
}
// KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
@@ -59,6 +60,11 @@ ReturnType KeyMatch2(Scope scope) {
string key1 = GetString(scope, 0);
string key2 = GetString(scope, 1);
+ PushBooleanValue(scope, KeyMatch2(key1, key2));
+ return RETURN_RESULT;
+}
+
+bool KeyMatch2(string key1, string key2) {
vector key1_arr = Split(key1, "/");
vector key2_arr = Split(key2, "/");
@@ -99,8 +105,7 @@ ReturnType KeyMatch2(Scope scope) {
if(key2_arr[key2_arr.size()-1] != "*")
res = false;
- PushBooleanValue(scope, res);
- return RETURN_RESULT;
+ return res;
}
// KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
@@ -109,6 +114,11 @@ ReturnType KeyMatch3(Scope scope) {
string key1 = GetString(scope, 0);
string key2 = GetString(scope, 1);
+ PushBooleanValue(scope, KeyMatch3(key1, key2));
+ return RETURN_RESULT;
+}
+
+bool KeyMatch3(string key1, string key2) {
vector key1_arr = Split(key1, "/");
vector key2_arr = Split(key2, "/");
@@ -150,8 +160,7 @@ ReturnType KeyMatch3(Scope scope) {
if(key2_arr[key2_arr.size()-1] != "*")
res = false;
- PushBooleanValue(scope, res);
- return RETURN_RESULT;
+ return res;
}
// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
@@ -159,17 +168,26 @@ ReturnType RegexMatch(Scope scope) {
string key1 = GetString(scope, 0);
string key2 = GetString(scope, 1);
- regex regex_s(key2);
- PushBooleanValue(scope, regex_match(key1, regex_s));
+ PushBooleanValue(scope, RegexMatch(key1, key2));
return RETURN_RESULT;
}
+bool RegexMatch(string key1, string key2) {
+ regex regex_s(key2);
+ return regex_match(key1, regex_s);
+}
+
// IPMatch determines whether IP address ip1 matches the pattern of IP address ip2, ip2 can be an IP address or a CIDR pattern.
// For example, "192.168.2.123" matches "192.168.2.0/24"
ReturnType IPMatch(Scope scope) {
string ip1 = GetString(scope, 0);
string ip2 = GetString(scope, 1);
+ PushBooleanValue(scope, IPMatch(ip1, ip2));
+ return RETURN_RESULT;
+}
+
+bool IPMatch(string ip1, string ip2) {
IP objIP1 = parseIP(ip1);
if (objIP1.isLegal == false)
throw IllegalArgumentException("invalid argument: ip1 in IPMatch() function is not an IP address.");
@@ -180,17 +198,15 @@ ReturnType IPMatch(Scope scope) {
if (objIP2.isLegal == false)
throw IllegalArgumentException("invalid argument: ip1 in IPMatch() function is not an IP address.");
- PushBooleanValue(scope, objIP1.Equal(objIP2));
- return RETURN_RESULT;
+ return objIP1.Equal(objIP2);
}
- PushBooleanValue(scope, objCIDR.net.contains(objIP1));
- return RETURN_RESULT;
+ return objCIDR.net.contains(objIP1);
}
// GFunction is the method of the g(_, _) function.
ReturnType GFunction(Scope scope) {
- RoleManager *rm;
+ RoleManager* rm;
rm = (RoleManager*)GetPointer(scope, 0);
string name1 = GetString(scope, 1);
string name2 = GetString(scope, 2);
@@ -199,12 +215,12 @@ ReturnType GFunction(Scope scope) {
if(rm == NULL)
PushBooleanValue(scope, name1 == name2);
- else if (len == 2) {
+ else if (len == 3) {
vector domain;
bool res = rm->HasLink(name1, name2, domain);
PushBooleanValue(scope, res);
} else {
- vector domain{GetString(scope, 2)};
+ vector domain{GetString(scope, 3)};
bool res = rm->HasLink(name1, name2, domain);
PushBooleanValue(scope, res);
}
diff --git a/casbin/util/built_in_functions.h b/casbin/util/built_in_functions.h
index c8fcbb1d..fc405b66 100644
--- a/casbin/util/built_in_functions.h
+++ b/casbin/util/built_in_functions.h
@@ -22,21 +22,26 @@
// KeyMatch determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
// For example, "/foo/bar" matches "/foo/*"
ReturnType KeyMatch(Scope scope);
+bool KeyMatch(string key1, string key2);
// KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource"
ReturnType KeyMatch2(Scope scope);
+bool KeyMatch2(string key1, string key2);
// KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}"
ReturnType KeyMatch3(Scope scope);
+bool KeyMatch3(string key1, string key2);
// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
ReturnType RegexMatch(Scope scope);
+bool RegexMatch(string key1, string key2);
// IPMatch determines whether IP address ip1 matches the pattern of IP address ip2, ip2 can be an IP address or a CIDR pattern.
// For example, "192.168.2.123" matches "192.168.2.0/24"
ReturnType IPMatch(Scope scope);
+bool IPMatch(string ip1, string ip2);
// GFunction is the method of the g(_, _) function.
ReturnType GFunction(Scope scope);
diff --git a/examples/abac_rule_model.conf b/examples/abac_rule_model.conf
new file mode 100644
index 00000000..591dd3a6
--- /dev/null
+++ b/examples/abac_rule_model.conf
@@ -0,0 +1,11 @@
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub_rule, obj, act
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = eval(p.sub_rule) && r.obj == p.obj && r.act == p.act
\ No newline at end of file
diff --git a/examples/abac_rule_policy.csv b/examples/abac_rule_policy.csv
new file mode 100644
index 00000000..e3dbc833
--- /dev/null
+++ b/examples/abac_rule_policy.csv
@@ -0,0 +1,2 @@
+p, r.sub.Age > 18, /data1, read
+p, r.sub.Age < 60, /data2, write
\ No newline at end of file
diff --git a/examples/basic_model_without_spaces.conf b/examples/basic_model_without_spaces.conf
new file mode 100644
index 00000000..5452f954
--- /dev/null
+++ b/examples/basic_model_without_spaces.conf
@@ -0,0 +1,11 @@
+[request_definition]
+r = sub,obj,act
+
+[policy_definition]
+p = sub,obj,act
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
\ No newline at end of file
diff --git a/examples/basic_with_root_model.conf b/examples/basic_with_root_model.conf
index 8f13907e..d3ec95b5 100644
--- a/examples/basic_with_root_model.conf
+++ b/examples/basic_with_root_model.conf
@@ -8,4 +8,4 @@ p = sub, obj, act
e = some(where (p.eft == allow))
[matchers]
-m = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"
\ No newline at end of file
+m = r.sub == "root" || r.sub == p.sub && r.obj == p.obj && r.act == p.act
\ No newline at end of file
diff --git a/examples/comment_model.conf b/examples/comment_model.conf
new file mode 100644
index 00000000..a4200ebf
--- /dev/null
+++ b/examples/comment_model.conf
@@ -0,0 +1,12 @@
+[request_definition]
+r = sub, obj, act ; Request definition
+
+[policy_definition]
+p = sub, obj, act
+
+[policy_effect]
+e = some(where (p.eft == allow)) # This is policy effect.
+
+# Matchers
+[matchers]
+m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
\ No newline at end of file
diff --git a/examples/glob_model.conf b/examples/glob_model.conf
new file mode 100644
index 00000000..b16cad49
--- /dev/null
+++ b/examples/glob_model.conf
@@ -0,0 +1,11 @@
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = r.sub == p.sub && globMatch(r.obj, p.obj) && r.act == p.act
\ No newline at end of file
diff --git a/examples/glob_policy.csv b/examples/glob_policy.csv
new file mode 100644
index 00000000..86c03b07
--- /dev/null
+++ b/examples/glob_policy.csv
@@ -0,0 +1,4 @@
+p, u1, /foo/*, read
+p, u2, /foo*, read
+p, u3, /*/foo/*, read
+p, u4, *, read
\ No newline at end of file
diff --git a/examples/rbac_with_all_pattern_model.conf b/examples/rbac_with_all_pattern_model.conf
new file mode 100644
index 00000000..045bfa57
--- /dev/null
+++ b/examples/rbac_with_all_pattern_model.conf
@@ -0,0 +1,14 @@
+[request_definition]
+r = sub, dom, obj, act
+
+[policy_definition]
+p = sub, dom, obj, act
+
+[role_definition]
+g = _, _, _
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = r.sub == p.sub && g(r.obj, p.obj, r.dom) && r.dom == p.dom && r.act == p.act
\ No newline at end of file
diff --git a/examples/rbac_with_all_pattern_policy.csv b/examples/rbac_with_all_pattern_policy.csv
new file mode 100644
index 00000000..8097be8a
--- /dev/null
+++ b/examples/rbac_with_all_pattern_policy.csv
@@ -0,0 +1,4 @@
+p, alice, domain1, book_group, read
+p, alice, domain2, book_group, write
+
+g, /book/:id, book_group, *
\ No newline at end of file
diff --git a/examples/rbac_with_domain_pattern_model.conf b/examples/rbac_with_domain_pattern_model.conf
new file mode 100644
index 00000000..774e4418
--- /dev/null
+++ b/examples/rbac_with_domain_pattern_model.conf
@@ -0,0 +1,14 @@
+[request_definition]
+r = sub, dom, obj, act
+
+[policy_definition]
+p = sub, dom, obj, act
+
+[role_definition]
+g = _, _, _
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
\ No newline at end of file
diff --git a/examples/rbac_with_domain_pattern_policy.csv b/examples/rbac_with_domain_pattern_policy.csv
new file mode 100644
index 00000000..c8abd35e
--- /dev/null
+++ b/examples/rbac_with_domain_pattern_policy.csv
@@ -0,0 +1,7 @@
+p, admin, domain1, data1, read
+p, admin, domain1, data1, write
+p, admin, domain2, data2, read
+p, admin, domain2, data2, write
+
+g, alice, admin, *
+g, bob, admin, domain2
\ No newline at end of file
diff --git a/examples/rbac_with_pattern_policy.csv b/examples/rbac_with_pattern_policy.csv
index a8c06c74..31316e90 100644
--- a/examples/rbac_with_pattern_policy.csv
+++ b/examples/rbac_with_pattern_policy.csv
@@ -6,10 +6,11 @@ p, pen_admin, pen_group, GET
g, alice, book_admin
g, bob, pen_admin
-g, /book/*, book_group
g, cathy, /book/1/2/3/4/5
g, cathy, pen_admin
+g2, /book/*, book_group
+
g2, /book/:id, book_group
g2, /pen/:id, pen_group
diff --git a/test/test.vcxproj b/test/test.vcxproj
index cd613c9b..e4b0b3f8 100644
--- a/test/test.vcxproj
+++ b/test/test.vcxproj
@@ -168,6 +168,7 @@
+
diff --git a/test/test.vcxproj.filters b/test/test.vcxproj.filters
index 01e9d08f..fc1fde8c 100644
--- a/test/test.vcxproj.filters
+++ b/test/test.vcxproj.filters
@@ -33,6 +33,9 @@
Source Files
+
+ Source Files
+
diff --git a/test/test_built_in_functions.cpp b/test/test_built_in_functions.cpp
index 32ead58e..5985d106 100644
--- a/test/test_built_in_functions.cpp
+++ b/test/test_built_in_functions.cpp
@@ -11,6 +11,7 @@ namespace test_built_in_functions
TEST_CLASS(TestBuiltInFunctions)
{
public:
+
void TestKeyMatch(string key1, string key2, bool res) {
Scope scope = InitializeScope();
PushStringValue(scope, key1);
diff --git a/test/test_model_enforcer.cpp b/test/test_model_enforcer.cpp
new file mode 100644
index 00000000..c280cbf7
--- /dev/null
+++ b/test/test_model_enforcer.cpp
@@ -0,0 +1,816 @@
+#pragma once
+
+#include "pch.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+namespace test_model_enforcer
+{
+ TEST_CLASS(TestModelEnforcer)
+ {
+ public:
+
+ string filePath(string filepath) {
+ char* root = _getcwd(NULL, 0);
+ string rootStr = string(root);
+
+ vector directories = Split(rootStr, "\\", -1);
+ vector::iterator it = find(directories.begin(), directories.end(), "x64");
+ vector left{ *(it - 1) };
+ it = find_end(directories.begin(), directories.end(), left.begin(), left.end());
+ int index = int(directories.size() + (it - directories.end()));
+
+ vector finalDirectories(directories.begin(), directories.begin() + index + 1);
+
+ vector userD = Split(filepath, "/", -1);
+ for (int i = 1; i < userD.size(); i++)
+ finalDirectories.push_back(userD[i]);
+
+ string filepath1 = finalDirectories[0];
+ for (int i = 1; i < finalDirectories.size(); i++)
+ filepath1 = filepath1 + "/" + finalDirectories[i];
+ return filepath1;
+ }
+
+ Scope InitializeParams(string sub, string obj, string act) {
+ Scope scope = InitializeScope();
+ PushObject(scope, "r");
+ PushStringPropToObject(scope, "r", sub, "sub");
+ PushStringPropToObject(scope, "r", obj, "obj");
+ PushStringPropToObject(scope, "r", act, "act");
+
+ return scope;
+ }
+
+ Scope InitializeParamsWithoutUsers(string obj, string act) {
+ Scope scope = InitializeScope();
+ PushObject(scope, "r");
+ PushStringPropToObject(scope, "r", obj, "obj");
+ PushStringPropToObject(scope, "r", act, "act");
+ return scope;
+ }
+
+ Scope InitializeParamsWithoutResources(string sub, string act) {
+ Scope scope = InitializeScope();
+ PushObject(scope, "r");
+ PushStringPropToObject(scope, "r", sub, "sub");
+ PushStringPropToObject(scope, "r", act, "act");
+
+ return scope;
+ }
+
+ Scope InitializeParamsWithDomains(string sub, string domain, string obj, string act) {
+ Scope scope = InitializeScope();
+ PushObject(scope, "r");
+ PushStringPropToObject(scope, "r", sub, "sub");
+ PushStringPropToObject(scope, "r", domain, "dom");
+ PushStringPropToObject(scope, "r", obj, "obj");
+ PushStringPropToObject(scope, "r", act, "act");
+
+ return scope;
+ }
+
+ void TestEnforce(Enforcer* e, Scope scope, bool res) {
+ Assert::AreEqual(res, e->Enforce(scope));
+ }
+
+ TEST_METHOD(TestBasicModel) {
+ string model = filePath("../examples/basic_model.conf");
+ string policy = filePath("../examples/basic_policy.csv");
+ Enforcer* e = Enforcer :: NewEnforcer(model, policy);
+
+ Scope scope;
+
+ scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestBasicModelWithoutSpaces) {
+ string model = filePath("../examples/basic_model_without_spaces.conf");
+ string policy = filePath("../examples/basic_policy.csv");
+ Enforcer* e = Enforcer :: NewEnforcer(model, policy);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestBasicModelNoPolicy) {
+ string model = filePath("../examples/basic_model.conf");
+ Enforcer* e = Enforcer :: NewEnforcer(model);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, false);
+ }
+
+ TEST_METHOD(TestBasicModelWithRoot) {
+ string model = filePath("../examples/basic_with_root_model.conf");
+ string policy = filePath("../examples/basic_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data1", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestBasicModelWithRootNoPolicy) {
+ string model = filePath("../examples/basic_with_root_model.conf");
+ Enforcer* e = Enforcer::NewEnforcer(model);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("root", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data1", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("root", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestBasicModelWithoutUsers) {
+ string model = filePath("../examples/basic_without_users_model.conf");
+ string policy = filePath("../examples/basic_without_users_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ Scope scope = InitializeParamsWithoutUsers("data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithoutUsers("data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithoutUsers("data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithoutUsers("data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestBasicModelWithoutResources) {
+ string model = filePath("../examples/basic_without_resources_model.conf");
+ string policy = filePath("../examples/basic_without_resources_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ Scope scope = InitializeParamsWithoutResources("alice", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithoutResources("alice", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithoutResources("bob", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithoutResources("bob", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModel) {
+ string model = filePath("../examples/rbac_model.conf");
+ string policy = filePath("../examples/rbac_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModelWithResourceRoles) {
+ string model = filePath("../examples/rbac_with_resource_roles_model.conf");
+ string policy = filePath("../examples/rbac_with_resource_roles_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModelWithDomains) {
+ string model = filePath("../examples/rbac_with_domains_model.conf");
+ string policy = filePath("../examples/rbac_with_domains_policy.csv");
+ Enforcer* e = Enforcer :: NewEnforcer(model, policy);
+
+ Scope scope = InitializeParamsWithDomains("alice", "domain1", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModelWithDomainsAtRuntime) {
+ string model = filePath("../examples/rbac_with_domains_model.conf");
+ Enforcer* e = Enforcer::NewEnforcer(model);
+
+ vector params{ "admin", "domain1", "data1", "read" };
+ e->AddPolicy(params);
+ params = vector{ "admin", "domain1", "data1", "write" };
+ e->AddPolicy(params);
+ params = vector{ "admin", "domain2", "data2", "read" };
+ e->AddPolicy(params);
+ params = vector{ "admin", "domain2", "data2", "write" };
+ e->AddPolicy(params);
+
+ params = vector{ "alice", "admin", "domain1" };
+ e->AddGroupingPolicy(params);
+ params = vector{ "bob", "admin", "domain2" };
+ e->AddGroupingPolicy(params);
+
+ Scope scope = InitializeParamsWithDomains("alice", "domain1", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "write");
+ TestEnforce(e, scope, true);
+
+ // Remove all policy rules related to domain1 and data1.
+ params = vector{ "domain1", "data1" };
+ e->RemoveFilteredPolicy(1, params);
+
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "write");
+ TestEnforce(e, scope, true);
+
+ // Remove the specified policy rule.
+ params = vector{ "admin", "domain2", "data2", "read" };
+ e->RemovePolicy(params);
+
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModelWithDomainsAtRuntimeMockAdapter) {
+ string model = filePath("../examples/rbac_with_domains_model.conf");
+ string policy = filePath("../examples/rbac_with_domains_policy.csv");
+ Adapter* adapter = FileAdapter :: NewAdapter(policy);
+ Enforcer* e = Enforcer :: NewEnforcer(model, adapter);
+
+ vector params{ "admin", "domain3", "data1", "read" };
+ e->AddPolicy(params);
+ params = vector{ "alice", "admin", "domain3" };
+ e->AddGroupingPolicy(params);
+
+ Scope scope = InitializeParamsWithDomains("alice", "domain3", "data1", "read");
+ TestEnforce(e, scope, true);
+
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "read");
+ TestEnforce(e, scope, true);
+ params = vector{ "domain1", "data1" };
+ e->RemoveFilteredPolicy(1, params);
+ scope = InitializeParamsWithDomains("alice", "domain1", "data1", "read");
+ TestEnforce(e, scope, false);
+
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "read");
+ TestEnforce(e, scope, true);
+ params = vector{ "admin", "domain2", "data2", "read" };
+ e->RemovePolicy(params);
+ scope = InitializeParamsWithDomains("bob", "domain2", "data2", "read");
+ TestEnforce(e, scope, false);
+ }
+
+ TEST_METHOD(TestRBACModelWithDeny) {
+ string model = filePath("../examples/rbac_with_deny_model.conf");
+ string policy = filePath("../examples/rbac_with_deny_policy.csv");
+ Enforcer* e = Enforcer :: NewEnforcer(model, policy);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModelWithOnlyDeny) {
+ string model = filePath("../examples/rbac_with_not_deny_model.conf");
+ string policy = filePath("../examples/rbac_with_deny_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ Scope scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, false);
+ }
+
+ TEST_METHOD(TestRBACModelWithCustomData) {
+ string model = filePath("../examples/rbac_model.conf");
+ string policy = filePath("../examples/rbac_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ // You can add custom data to a grouping policy, Casbin will ignore it. It is only meaningful to the caller.
+ // This feature can be used to store information like whether "bob" is an end user (so no subject will inherit "bob")
+ // For Casbin, it is equivalent to: e.AddGroupingPolicy("bob", "data2_admin")
+ vector params{ "bob", "data2_admin", "custom_data" };
+ e->AddGroupingPolicy(params);
+
+ Scope scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+
+ // You should also take the custom data as a parameter when deleting a grouping policy.
+ // e.RemoveGroupingPolicy("bob", "data2_admin") won't work.
+ // Or you can remove it by using RemoveFilteredGroupingPolicy().
+ params = vector{ "bob", "data2_admin", "custom_data" };
+ e->RemoveGroupingPolicy(params);
+
+ scope = InitializeParams("alice", "data1", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("alice", "data2", "read");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "data2", "write");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "data1", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data1", "write");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "read");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "data2", "write");
+ TestEnforce(e, scope, true);
+ }
+
+ TEST_METHOD(TestRBACModelWithPattern) {
+ string model = filePath("../examples/rbac_with_pattern_model.conf");
+ string policy = filePath("../examples/rbac_with_pattern_policy.csv");
+ Enforcer* e = Enforcer::NewEnforcer(model, policy);
+
+ // Here's a little confusing: the matching function here is not the custom function used in matcher.
+ // It is the matching function used by "g" (and "g2", "g3" if any..)
+ // You can see in policy that: "g2, /book/:id, book_group", so in "g2()" function in the matcher, instead
+ // of checking whether "/book/:id" equals the obj: "/book/1", it checks whether the pattern matches.
+ // You can see it as normal RBAC: "/book/:id" == "/book/1" becomes KeyMatch2("/book/:id", "/book/1")
+ DefaultRoleManager* rm_tmp = (DefaultRoleManager*)e->rm;
+ rm_tmp->AddMatchingFunc(KeyMatch2);
+ Scope scope = InitializeParams("alice", "/book/1", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "/book/2", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "/pen/1", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "/pen/2", "GET");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "/book/1", "GET");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "/book/2", "GET");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "/pen/1", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "/pen/2", "GET");
+ TestEnforce(e, scope, true);
+
+ // AddMatchingFunc() is actually setting a function because only one function is allowed,
+ // so when we set "KeyMatch3", we are actually replacing "KeyMatch2" with "KeyMatch3".
+ rm_tmp->AddMatchingFunc(KeyMatch3);
+ scope = InitializeParams("alice", "/book2/1", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "/book2/2", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "/pen2/1", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("alice", "/pen2/2", "GET");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "/book2/1", "GET");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "/book2/2", "GET");
+ TestEnforce(e, scope, false);
+ scope = InitializeParams("bob", "/pen2/1", "GET");
+ TestEnforce(e, scope, true);
+ scope = InitializeParams("bob", "/pen2/2", "GET");
+ TestEnforce(e, scope, true);
+ }
+ /*
+ type testCustomRoleManager struct {}
+
+ func NewRoleManager() rbac.RoleManager{
+ return &testCustomRoleManager{}
+ }
+ func(rm* testCustomRoleManager) Clear() error { return nil }
+ func(rm* testCustomRoleManager) AddLink(name1 string, name2 string, domain ...string) error {
+ return nil
+ }
+ func(rm* testCustomRoleManager) DeleteLink(name1 string, name2 string, domain ...string) error {
+ return nil
+ }
+ func(rm* testCustomRoleManager) HasLink(name1 string, name2 string, domain ...string) (bool, error) {
+ if name1 == "alice" && name2 == "alice" {
+ return true, nil
+ }
+ else if name1 == "alice" && name2 == "data2_admin" {
+ return true, nil
+ }
+ else if name1 == "bob" && name2 == "bob" {
+ return true, nil
+ }
+ return false, nil
+ }
+ func(rm* testCustomRoleManager) GetRoles(name string, domain ...string) ([]string, error) {
+ return[]string{}, nil
+ }
+ func(rm* testCustomRoleManager) GetUsers(name string, domain ...string) ([]string, error) {
+ return[]string{}, nil
+ }
+ func(rm* testCustomRoleManager) PrintRoles() error { return nil }
+
+ func TestRBACModelWithCustomRoleManager(t* testing.T) {
+ e, _ : = NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
+ e.SetRoleManager(NewRoleManager())
+ e.LoadModel()
+ _ = e.LoadPolicy()
+
+ TestEnforce(e, "alice", "data1", "read", true)
+ TestEnforce(e, "alice", "data1", "write", false)
+ TestEnforce(e, "alice", "data2", "read", true)
+ TestEnforce(e, "alice", "data2", "write", true)
+ TestEnforce(e, "bob", "data1", "read", false)
+ TestEnforce(e, "bob", "data1", "write", false)
+ TestEnforce(e, "bob", "data2", "read", false)
+ TestEnforce(e, "bob", "data2", "write", true)
+ }
+
+ type testResource struct {
+ Name string
+ Owner string
+ }
+
+ func newTestResource(name string, owner string) testResource {
+ r: = testResource{}
+ r.Name = name
+ r.Owner = owner
+ return r
+ }
+
+ func TestABACModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/abac_model.conf")
+
+ data1 : = newTestResource("data1", "alice")
+ data2 : = newTestResource("data2", "bob")
+
+ TestEnforce(e, "alice", data1, "read", true)
+ TestEnforce(e, "alice", data1, "write", true)
+ TestEnforce(e, "alice", data2, "read", false)
+ TestEnforce(e, "alice", data2, "write", false)
+ TestEnforce(e, "bob", data1, "read", false)
+ TestEnforce(e, "bob", data1, "write", false)
+ TestEnforce(e, "bob", data2, "read", true)
+ TestEnforce(e, "bob", data2, "write", true)
+ }
+
+ func TestKeyMatchModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv")
+
+ TestEnforce(e, "alice", "/alice_data/resource1", "GET", true)
+ TestEnforce(e, "alice", "/alice_data/resource1", "POST", true)
+ TestEnforce(e, "alice", "/alice_data/resource2", "GET", true)
+ TestEnforce(e, "alice", "/alice_data/resource2", "POST", false)
+ TestEnforce(e, "alice", "/bob_data/resource1", "GET", false)
+ TestEnforce(e, "alice", "/bob_data/resource1", "POST", false)
+ TestEnforce(e, "alice", "/bob_data/resource2", "GET", false)
+ TestEnforce(e, "alice", "/bob_data/resource2", "POST", false)
+
+ TestEnforce(e, "bob", "/alice_data/resource1", "GET", false)
+ TestEnforce(e, "bob", "/alice_data/resource1", "POST", false)
+ TestEnforce(e, "bob", "/alice_data/resource2", "GET", true)
+ TestEnforce(e, "bob", "/alice_data/resource2", "POST", false)
+ TestEnforce(e, "bob", "/bob_data/resource1", "GET", false)
+ TestEnforce(e, "bob", "/bob_data/resource1", "POST", true)
+ TestEnforce(e, "bob", "/bob_data/resource2", "GET", false)
+ TestEnforce(e, "bob", "/bob_data/resource2", "POST", true)
+
+ TestEnforce(e, "cathy", "/cathy_data", "GET", true)
+ TestEnforce(e, "cathy", "/cathy_data", "POST", true)
+ TestEnforce(e, "cathy", "/cathy_data", "DELETE", false)
+ }
+
+ func TestKeyMatch2Model(t* testing.T) {
+ e, _ : = NewEnforcer("examples/keymatch2_model.conf", "examples/keymatch2_policy.csv")
+
+ TestEnforce(e, "alice", "/alice_data", "GET", false)
+ TestEnforce(e, "alice", "/alice_data/resource1", "GET", true)
+ TestEnforce(e, "alice", "/alice_data2/myid", "GET", false)
+ TestEnforce(e, "alice", "/alice_data2/myid/using/res_id", "GET", true)
+ }
+
+ func CustomFunction(key1 string, key2 string) bool{
+ if key1 == "/alice_data2/myid/using/res_id" && key2 == "/alice_data/:resource" {
+ return true
+ }
+ else if key1 == "/alice_data2/myid/using/res_id" && key2 == "/alice_data2/:id/using/:resId" {
+ return true
+ }
+ else {
+ return false
+ }
+ }
+
+ func CustomFunctionWrapper(args ...interface {}) (interface {}, error) {
+ key1: = args[0].(string)
+ key2 : = args[1].(string)
+
+ return bool(CustomFunction(key1, key2)), nil
+ }
+
+ func TestKeyMatchCustomModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/keymatch_custom_model.conf", "examples/keymatch2_policy.csv")
+
+ e.AddFunction("keyMatchCustom", CustomFunctionWrapper)
+
+ TestEnforce(e, "alice", "/alice_data2/myid", "GET", false)
+ TestEnforce(e, "alice", "/alice_data2/myid/using/res_id", "GET", true)
+ }
+
+ func TestIPMatchModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/ipmatch_model.conf", "examples/ipmatch_policy.csv")
+
+ TestEnforce(e, "192.168.2.123", "data1", "read", true)
+ TestEnforce(e, "192.168.2.123", "data1", "write", false)
+ TestEnforce(e, "192.168.2.123", "data2", "read", false)
+ TestEnforce(e, "192.168.2.123", "data2", "write", false)
+
+ TestEnforce(e, "192.168.0.123", "data1", "read", false)
+ TestEnforce(e, "192.168.0.123", "data1", "write", false)
+ TestEnforce(e, "192.168.0.123", "data2", "read", false)
+ TestEnforce(e, "192.168.0.123", "data2", "write", false)
+
+ TestEnforce(e, "10.0.0.5", "data1", "read", false)
+ TestEnforce(e, "10.0.0.5", "data1", "write", false)
+ TestEnforce(e, "10.0.0.5", "data2", "read", false)
+ TestEnforce(e, "10.0.0.5", "data2", "write", true)
+
+ TestEnforce(e, "192.168.0.1", "data1", "read", false)
+ TestEnforce(e, "192.168.0.1", "data1", "write", false)
+ TestEnforce(e, "192.168.0.1", "data2", "read", false)
+ TestEnforce(e, "192.168.0.1", "data2", "write", false)
+ }
+
+ func TestGlobMatchModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/glob_model.conf", "examples/glob_policy.csv")
+ TestEnforce(e, "u1", "/foo/", "read", true)
+ TestEnforce(e, "u1", "/foo", "read", false)
+ TestEnforce(e, "u1", "/foo/subprefix", "read", true)
+ TestEnforce(e, "u1", "foo", "read", false)
+
+ TestEnforce(e, "u2", "/foosubprefix", "read", true)
+ TestEnforce(e, "u2", "/foo/subprefix", "read", false)
+ TestEnforce(e, "u2", "foo", "read", false)
+
+ TestEnforce(e, "u3", "/prefix/foo/subprefix", "read", true)
+ TestEnforce(e, "u3", "/prefix/foo/", "read", true)
+ TestEnforce(e, "u3", "/prefix/foo", "read", false)
+
+ TestEnforce(e, "u4", "/foo", "read", false)
+ TestEnforce(e, "u4", "foo", "read", true)
+ }
+
+ func TestPriorityModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/priority_model.conf", "examples/priority_policy.csv")
+
+ TestEnforce(e, "alice", "data1", "read", true)
+ TestEnforce(e, "alice", "data1", "write", false)
+ TestEnforce(e, "alice", "data2", "read", false)
+ TestEnforce(e, "alice", "data2", "write", false)
+ TestEnforce(e, "bob", "data1", "read", false)
+ TestEnforce(e, "bob", "data1", "write", false)
+ TestEnforce(e, "bob", "data2", "read", true)
+ TestEnforce(e, "bob", "data2", "write", false)
+ }
+
+ func TestPriorityModelIndeterminate(t* testing.T) {
+ e, _ : = NewEnforcer("examples/priority_model.conf", "examples/priority_indeterminate_policy.csv")
+
+ TestEnforce(e, "alice", "data1", "read", false)
+ }
+
+ func TestRBACModelInMultiLines(t* testing.T) {
+ e, _ : = NewEnforcer("examples/rbac_model_in_multi_line.conf", "examples/rbac_policy.csv")
+
+ TestEnforce(e, "alice", "data1", "read", true)
+ TestEnforce(e, "alice", "data1", "write", false)
+ TestEnforce(e, "alice", "data2", "read", true)
+ TestEnforce(e, "alice", "data2", "write", true)
+ TestEnforce(e, "bob", "data1", "read", false)
+ TestEnforce(e, "bob", "data1", "write", false)
+ TestEnforce(e, "bob", "data2", "read", false)
+ TestEnforce(e, "bob", "data2", "write", true)
+ }
+
+ type testSub struct {
+ Name string
+ Age int
+ }
+
+ func newTestSubject(name string, age int) testSub {
+ s: = testSub{}
+ s.Name = name
+ s.Age = age
+ return s
+ }
+
+ func TestABACPolicy(t* testing.T) {
+ e, _ : = NewEnforcer("examples/abac_rule_model.conf", "examples/abac_rule_policy.csv")
+ sub1 : = newTestSubject("alice", 16)
+ sub2 : = newTestSubject("alice", 20)
+ sub3 : = newTestSubject("alice", 65)
+
+ TestEnforce(e, sub1, "/data1", "read", false)
+ TestEnforce(e, sub1, "/data2", "read", false)
+ TestEnforce(e, sub1, "/data1", "write", false)
+ TestEnforce(e, sub1, "/data2", "write", true)
+ TestEnforce(e, sub2, "/data1", "read", true)
+ TestEnforce(e, sub2, "/data2", "read", false)
+ TestEnforce(e, sub2, "/data1", "write", false)
+ TestEnforce(e, sub2, "/data2", "write", true)
+ TestEnforce(e, sub3, "/data1", "read", true)
+ TestEnforce(e, sub3, "/data2", "read", false)
+ TestEnforce(e, sub3, "/data1", "write", false)
+ TestEnforce(e, sub3, "/data2", "write", false)
+ }
+
+ func TestCommentModel(t* testing.T) {
+ e, _ : = NewEnforcer("examples/comment_model.conf", "examples/basic_policy.csv")
+
+ TestEnforce(e, "alice", "data1", "read", true)
+ TestEnforce(e, "alice", "data1", "write", false)
+ TestEnforce(e, "alice", "data2", "read", false)
+ TestEnforce(e, "alice", "data2", "write", false)
+ TestEnforce(e, "bob", "data1", "read", false)
+ TestEnforce(e, "bob", "data1", "write", false)
+ TestEnforce(e, "bob", "data2", "read", false)
+ TestEnforce(e, "bob", "data2", "write", true)
+ }
+ */
+ };
+}
\ No newline at end of file
diff --git a/test/test_role_manager.cpp b/test/test_role_manager.cpp
index 5dfafa5e..36a29308 100644
--- a/test/test_role_manager.cpp
+++ b/test/test_role_manager.cpp
@@ -11,173 +11,174 @@ namespace test_role_manager
TEST_CLASS(TestRoleManager)
{
public:
- void TestRole(RoleManager* rm, string name1, string name2, bool res) {
- bool my_res = rm->HasLink(name1, name2);
-
- Assert::AreEqual(res, my_res);
- }
-
- void TestDomainRole(RoleManager* rm, string name1, string name2, vector domain, bool res) {
- bool my_res = rm->HasLink(name1, name2, domain);
-
- Assert::AreEqual(res, my_res);
- }
-
- TEST_METHOD(TestRole) {
- RoleManager* rm = DefaultRoleManager :: NewRoleManager(3);
- rm->AddLink("u1", "g1");
- rm->AddLink("u2", "g1");
- rm->AddLink("u3", "g2");
- rm->AddLink("u4", "g2");
- rm->AddLink("u4", "g3");
- rm->AddLink("g1", "g3");
-
- // Current role inheritance tree:
- // g3 g2
- // / \ / \
- // g1 u4 u3
- // / \
- // u1 u2
-
- TestRole(rm, "u1", "g1", true);
- TestRole(rm, "u1", "g2", false);
- TestRole(rm, "u1", "g3", true);
- TestRole(rm, "u2", "g1", true);
- TestRole(rm, "u2", "g2", false);
- TestRole(rm, "u2", "g3", true);
- TestRole(rm, "u3", "g1", false);
- TestRole(rm, "u3", "g2", true);
- TestRole(rm, "u3", "g3", false);
- TestRole(rm, "u4", "g1", false);
- TestRole(rm, "u4", "g2", true);
- TestRole(rm, "u4", "g3", true);
-
- rm->DeleteLink("g1", "g3");
- rm->DeleteLink("u4", "g2");
-
- // Current role inheritance tree after deleting the links:
- // g3 g2
- // \ \
- // g1 u4 u3
- // / \
- // u1 u2
-
- TestRole(rm, "u1", "g1", true);
- TestRole(rm, "u1", "g2", false);
- TestRole(rm, "u1", "g3", false);
- TestRole(rm, "u2", "g1", true);
- TestRole(rm, "u2", "g2", false);
- TestRole(rm, "u2", "g3", false);
- TestRole(rm, "u3", "g1", false);
- TestRole(rm, "u3", "g2", true);
- TestRole(rm, "u3", "g3", false);
- TestRole(rm, "u4", "g1", false);
- TestRole(rm, "u4", "g2", false);
- TestRole(rm, "u4", "g3", true);
- }
-
- TEST_METHOD(TestDomainRole) {
- RoleManager* rm = DefaultRoleManager :: NewRoleManager(3);
- vector domain1{ "domain1" };
- vector domain2{ "domain2" };
- rm->AddLink("u1", "g1", domain1);
- rm->AddLink("u2", "g1", domain1);
- rm->AddLink("u3", "admin", domain2);
- rm->AddLink("u4", "admin", domain2);
- rm->AddLink("u4", "admin", domain1);
- rm->AddLink("g1", "admin", domain1);
-
- // Current role inheritance tree:
- // domain1:admin domain2:admin
- // / \ / \
- // domain1:g1 u4 u3
- // / \
- // u1 u2
-
- TestDomainRole(rm, "u1", "g1", domain1, true);
- TestDomainRole(rm, "u1", "g1", domain2, false);
- TestDomainRole(rm, "u1", "admin", domain1, true);
- TestDomainRole(rm, "u1", "admin", domain2, false);
-
- TestDomainRole(rm, "u2", "g1", domain1, true);
- TestDomainRole(rm, "u2", "g1", domain2, false);
- TestDomainRole(rm, "u2", "admin", domain1, true);
- TestDomainRole(rm, "u2", "admin", domain2, false);
-
- TestDomainRole(rm, "u3", "g1", domain1, false);
- TestDomainRole(rm, "u3", "g1", domain2, false);
- TestDomainRole(rm, "u3", "admin", domain1, false);
- TestDomainRole(rm, "u3", "admin", domain2, true);
-
- TestDomainRole(rm, "u4", "g1", domain1, false);
- TestDomainRole(rm, "u4", "g1", domain2, false);
- TestDomainRole(rm, "u4", "admin", domain1, true);
- TestDomainRole(rm, "u4", "admin", domain2, true);
-
- rm->DeleteLink("g1", "admin", domain1);
- rm->DeleteLink("u4", "admin", domain2);
-
- // Current role inheritance tree after deleting the links:
- // domain1:admin domain2:admin
- // \ \
- // domain1:g1 u4 u3
- // / \
- // u1 u2
-
- TestDomainRole(rm, "u1", "g1", domain1, true);
- TestDomainRole(rm, "u1", "g1", domain2, false);
- TestDomainRole(rm, "u1", "admin", domain1, false);
- TestDomainRole(rm, "u1", "admin", domain2, false);
-
- TestDomainRole(rm, "u2", "g1", domain1, true);
- TestDomainRole(rm, "u2", "g1", domain2, false);
- TestDomainRole(rm, "u2", "admin", domain1, false);
- TestDomainRole(rm, "u2", "admin", domain2, false);
-
- TestDomainRole(rm, "u3", "g1", domain1, false);
- TestDomainRole(rm, "u3", "g1", domain2, false);
- TestDomainRole(rm, "u3", "admin", domain1, false);
- TestDomainRole(rm, "u3", "admin", domain2, true);
-
- TestDomainRole(rm, "u4", "g1", domain1, false);
- TestDomainRole(rm, "u4", "g1", domain2, false);
- TestDomainRole(rm, "u4", "admin", domain1, true);
- TestDomainRole(rm, "u4", "admin", domain2, false);
- }
-
- TEST_METHOD(TestClear) {
- RoleManager* rm = DefaultRoleManager::NewRoleManager(3);
- rm->AddLink("u1", "g1");
- rm->AddLink("u2", "g1");
- rm->AddLink("u3", "g2");
- rm->AddLink("u4", "g2");
- rm->AddLink("u4", "g3");
- rm->AddLink("g1", "g3");
-
- // Current role inheritance tree:
- // g3 g2
- // / \ / \
- // g1 u4 u3
- // / \
- // u1 u2
-
- rm->Clear();
-
- // All data is cleared.
- // No role inheritance now.
-
- TestRole(rm, "u1", "g1", false);
- TestRole(rm, "u1", "g2", false);
- TestRole(rm, "u1", "g3", false);
- TestRole(rm, "u2", "g1", false);
- TestRole(rm, "u2", "g2", false);
- TestRole(rm, "u2", "g3", false);
- TestRole(rm, "u3", "g1", false);
- TestRole(rm, "u3", "g2", false);
- TestRole(rm, "u3", "g3", false);
- TestRole(rm, "u4", "g1", false);
- TestRole(rm, "u4", "g2", false);
- TestRole(rm, "u4", "g3", false);
- }
+
+ void TestRole(RoleManager* rm, string name1, string name2, bool res) {
+ bool my_res = rm->HasLink(name1, name2);
+
+ Assert::AreEqual(res, my_res);
+ }
+
+ void TestDomainRole(RoleManager* rm, string name1, string name2, vector domain, bool res) {
+ bool my_res = rm->HasLink(name1, name2, domain);
+
+ Assert::AreEqual(res, my_res);
+ }
+
+ TEST_METHOD(TestRole) {
+ RoleManager* rm = DefaultRoleManager :: NewRoleManager(3);
+ rm->AddLink("u1", "g1");
+ rm->AddLink("u2", "g1");
+ rm->AddLink("u3", "g2");
+ rm->AddLink("u4", "g2");
+ rm->AddLink("u4", "g3");
+ rm->AddLink("g1", "g3");
+
+ // Current role inheritance tree:
+ // g3 g2
+ // / \ / \
+ // g1 u4 u3
+ // / \
+ // u1 u2
+
+ TestRole(rm, "u1", "g1", true);
+ TestRole(rm, "u1", "g2", false);
+ TestRole(rm, "u1", "g3", true);
+ TestRole(rm, "u2", "g1", true);
+ TestRole(rm, "u2", "g2", false);
+ TestRole(rm, "u2", "g3", true);
+ TestRole(rm, "u3", "g1", false);
+ TestRole(rm, "u3", "g2", true);
+ TestRole(rm, "u3", "g3", false);
+ TestRole(rm, "u4", "g1", false);
+ TestRole(rm, "u4", "g2", true);
+ TestRole(rm, "u4", "g3", true);
+
+ rm->DeleteLink("g1", "g3");
+ rm->DeleteLink("u4", "g2");
+
+ // Current role inheritance tree after deleting the links:
+ // g3 g2
+ // \ \
+ // g1 u4 u3
+ // / \
+ // u1 u2
+
+ TestRole(rm, "u1", "g1", true);
+ TestRole(rm, "u1", "g2", false);
+ TestRole(rm, "u1", "g3", false);
+ TestRole(rm, "u2", "g1", true);
+ TestRole(rm, "u2", "g2", false);
+ TestRole(rm, "u2", "g3", false);
+ TestRole(rm, "u3", "g1", false);
+ TestRole(rm, "u3", "g2", true);
+ TestRole(rm, "u3", "g3", false);
+ TestRole(rm, "u4", "g1", false);
+ TestRole(rm, "u4", "g2", false);
+ TestRole(rm, "u4", "g3", true);
+ }
+
+ TEST_METHOD(TestDomainRole) {
+ RoleManager* rm = DefaultRoleManager :: NewRoleManager(3);
+ vector domain1{ "domain1" };
+ vector domain2{ "domain2" };
+ rm->AddLink("u1", "g1", domain1);
+ rm->AddLink("u2", "g1", domain1);
+ rm->AddLink("u3", "admin", domain2);
+ rm->AddLink("u4", "admin", domain2);
+ rm->AddLink("u4", "admin", domain1);
+ rm->AddLink("g1", "admin", domain1);
+
+ // Current role inheritance tree:
+ // domain1:admin domain2:admin
+ // / \ / \
+ // domain1:g1 u4 u3
+ // / \
+ // u1 u2
+
+ TestDomainRole(rm, "u1", "g1", domain1, true);
+ TestDomainRole(rm, "u1", "g1", domain2, false);
+ TestDomainRole(rm, "u1", "admin", domain1, true);
+ TestDomainRole(rm, "u1", "admin", domain2, false);
+
+ TestDomainRole(rm, "u2", "g1", domain1, true);
+ TestDomainRole(rm, "u2", "g1", domain2, false);
+ TestDomainRole(rm, "u2", "admin", domain1, true);
+ TestDomainRole(rm, "u2", "admin", domain2, false);
+
+ TestDomainRole(rm, "u3", "g1", domain1, false);
+ TestDomainRole(rm, "u3", "g1", domain2, false);
+ TestDomainRole(rm, "u3", "admin", domain1, false);
+ TestDomainRole(rm, "u3", "admin", domain2, true);
+
+ TestDomainRole(rm, "u4", "g1", domain1, false);
+ TestDomainRole(rm, "u4", "g1", domain2, false);
+ TestDomainRole(rm, "u4", "admin", domain1, true);
+ TestDomainRole(rm, "u4", "admin", domain2, true);
+
+ rm->DeleteLink("g1", "admin", domain1);
+ rm->DeleteLink("u4", "admin", domain2);
+
+ // Current role inheritance tree after deleting the links:
+ // domain1:admin domain2:admin
+ // \ \
+ // domain1:g1 u4 u3
+ // / \
+ // u1 u2
+
+ TestDomainRole(rm, "u1", "g1", domain1, true);
+ TestDomainRole(rm, "u1", "g1", domain2, false);
+ TestDomainRole(rm, "u1", "admin", domain1, false);
+ TestDomainRole(rm, "u1", "admin", domain2, false);
+
+ TestDomainRole(rm, "u2", "g1", domain1, true);
+ TestDomainRole(rm, "u2", "g1", domain2, false);
+ TestDomainRole(rm, "u2", "admin", domain1, false);
+ TestDomainRole(rm, "u2", "admin", domain2, false);
+
+ TestDomainRole(rm, "u3", "g1", domain1, false);
+ TestDomainRole(rm, "u3", "g1", domain2, false);
+ TestDomainRole(rm, "u3", "admin", domain1, false);
+ TestDomainRole(rm, "u3", "admin", domain2, true);
+
+ TestDomainRole(rm, "u4", "g1", domain1, false);
+ TestDomainRole(rm, "u4", "g1", domain2, false);
+ TestDomainRole(rm, "u4", "admin", domain1, true);
+ TestDomainRole(rm, "u4", "admin", domain2, false);
+ }
+
+ TEST_METHOD(TestClear) {
+ RoleManager* rm = DefaultRoleManager::NewRoleManager(3);
+ rm->AddLink("u1", "g1");
+ rm->AddLink("u2", "g1");
+ rm->AddLink("u3", "g2");
+ rm->AddLink("u4", "g2");
+ rm->AddLink("u4", "g3");
+ rm->AddLink("g1", "g3");
+
+ // Current role inheritance tree:
+ // g3 g2
+ // / \ / \
+ // g1 u4 u3
+ // / \
+ // u1 u2
+
+ rm->Clear();
+
+ // All data is cleared.
+ // No role inheritance now.
+
+ TestRole(rm, "u1", "g1", false);
+ TestRole(rm, "u1", "g2", false);
+ TestRole(rm, "u1", "g3", false);
+ TestRole(rm, "u2", "g1", false);
+ TestRole(rm, "u2", "g2", false);
+ TestRole(rm, "u2", "g3", false);
+ TestRole(rm, "u3", "g1", false);
+ TestRole(rm, "u3", "g2", false);
+ TestRole(rm, "u3", "g3", false);
+ TestRole(rm, "u4", "g1", false);
+ TestRole(rm, "u4", "g2", false);
+ TestRole(rm, "u4", "g3", false);
+ }
};
}
\ No newline at end of file