diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 06c92ad6..aa92a0e4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,41 +19,65 @@ on: [push, pull_request]
jobs:
linux:
- name: "Linux Ubuntu 20.04"
+ name: "Linux Ubuntu 20.04 (GNU 9.3.0)"
runs-on: ubuntu-20.04
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v2
- - name: Building files
+ - name: Configuring CMake files
id: building-files
run: |
- make
+ mkdir build && cd build && cmake ..
- name: Building library
id: building-lib
run: |
- make library
+ cd build && cmake --build . --config Debug --target all -j 10 --
- name: Cleanup
- id: cleanup
+ id: clean-up
run: |
- make clean
+ rm -r build lib
+
+ windows:
+ name: "Windows 10 (MSVC 19.29)"
+ runs-on: windows-latest
+ steps:
+ - name: Checkout
+ id: checkout
+ uses: actions/checkout@v2
+ - name: Configuring CMake files
+ id: building-files
+ run: |
+ mkdir build
+ cd build
+ cmake ..
+ - name: Building library
+ id: building-lib
+ run: |
+ cd build
+ cmake --build . --config Release --target casbin -j 10 --
+ - name: Cleanup
+ id: clean-up
+ run: |
+ rm -r build
+ rm -r lib
macos:
- name: "macOS Catalina 10.15"
+ name: "macOS Catalina 10.15 (AppleClang 12.0)"
runs-on: macos-latest
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v2
- - name: Building files
+ - name: Configuring CMake files
id: building-files
run: |
- make
+ mkdir build && cd build && cmake ..
- name: Building library
id: building-lib
run: |
- make library
+ cd build && cmake --build . --config Debug --target all -j 10 --
- name: Cleanup
- id: cleanup
+ id: clean-up
run: |
- make clean
+ rm -r build lib
diff --git a/.gitignore b/.gitignore
index 7b14ee16..fd90e1d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -354,6 +354,7 @@ MigrationBackup/
.idea/
*.iml
.vscode
+.DS_Store
# CMake work directory
cmake-build/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f8363a4b..6da0a7b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.19)
set(CMAKE_WARN_DEPRECATED ON)
diff --git a/README.md b/README.md
index 84b27717..77bb6cef 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,8 @@ Casbin-CPP
Operating Systems | Availability status
----------------- | -------------------
Windows (VS C++) | :heavy_check_mark: Available
-Linux and MacOS | :heavy_check_mark: Available
+Linux | :heavy_check_mark: Available
+macOS | :heavy_check_mark: Available
![casbin Logo](casbin-logo.png)
diff --git a/casbin/CMakeLists.txt b/casbin/CMakeLists.txt
index 83861d8e..37ca1be3 100644
--- a/casbin/CMakeLists.txt
+++ b/casbin/CMakeLists.txt
@@ -1,8 +1,15 @@
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
-FILE(GLOB_RECURSE SC_FILES "*.cpp" "*.h")
+FILE(GLOB_RECURSE SRC_FILES "*.cpp" "*.h")
-add_library(casbin ${SC_FILES})
+add_library(casbin ${SRC_FILES})
+include_directories(${CMAKE_SOURCE_DIR}/casbin)
+
+target_precompile_headers(casbin PUBLIC "pch.h")
set_target_properties(casbin PROPERTIES PREFIX "")
-set_target_properties(casbin PROPERTIES SUFFIX ".o")
+if(WIN32 OR MSVC)
+ set_target_properties(casbin PROPERTIES SUFFIX ".lib")
+elseif(UNIX)
+ set_target_properties(casbin PROPERTIES SUFFIX ".a")
+endif()
diff --git a/casbin/casbin.vcxproj b/casbin/casbin.vcxproj
index 78734730..d2cdb9ec 100644
--- a/casbin/casbin.vcxproj
+++ b/casbin/casbin.vcxproj
@@ -273,6 +273,7 @@
+
@@ -286,6 +287,7 @@
+
diff --git a/casbin/casbin.vcxproj.filters b/casbin/casbin.vcxproj.filters
index b737c515..98977348 100644
--- a/casbin/casbin.vcxproj.filters
+++ b/casbin/casbin.vcxproj.filters
@@ -494,6 +494,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/casbin/internal_api.cpp b/casbin/internal_api.cpp
index 73cb5647..31258a0b 100644
--- a/casbin/internal_api.cpp
+++ b/casbin/internal_api.cpp
@@ -25,11 +25,12 @@
#include "./util/util.h"
#include "./persist/watcher_ex.h"
#include "./exception/unsupported_operation_exception.h"
+#include "./persist/watcher_update.h"
namespace casbin {
// addPolicy adds a rule to the current policy.
-bool Enforcer :: addPolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
+bool Enforcer::addPolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
bool rule_added = m_model->AddPolicy(sec, p_type, rule);
if(!rule_added)
return rule_added;
@@ -59,7 +60,7 @@ bool Enforcer :: addPolicy(const std::string& sec, const std::string& p_type, co
}
// addPolicies adds rules to the current policy.
-bool Enforcer :: addPolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules) {
+bool Enforcer::addPolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules) {
bool rules_added = m_model->AddPolicies(sec, p_type, rules);
if (!rules_added)
return rules_added;
@@ -83,7 +84,7 @@ bool Enforcer :: addPolicies(const std::string& sec, const std::string& p_type,
}
// removePolicy removes a rule from the current policy.
-bool Enforcer :: removePolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
+bool Enforcer::removePolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
bool rule_removed = m_model->RemovePolicy(sec, p_type, rule);
if(!rule_removed)
return rule_removed;
@@ -113,7 +114,7 @@ bool Enforcer :: removePolicy(const std::string& sec, const std::string& p_type,
}
// removePolicies removes rules from the current policy.
-bool Enforcer :: removePolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules) {
+bool Enforcer::removePolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules) {
bool rules_removed = m_model->AddPolicies(sec, p_type, rules);
if (!rules_removed)
return rules_removed;
@@ -136,7 +137,7 @@ bool Enforcer :: removePolicies(const std::string& sec, const std::string& p_typ
}
// removeFilteredPolicy removes rules based on field filters from the current policy.
-bool Enforcer :: removeFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector& field_values){
+bool Enforcer::removeFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector& field_values){
std::pair>> p = m_model->RemoveFilteredPolicy(sec, p_type, field_index, field_values);
bool rule_removed = p.first;
std::vector> effects = p.second;
@@ -166,12 +167,46 @@ bool Enforcer :: removeFilteredPolicy(const std::string& sec, const std::string&
return rule_removed;
}
-bool Enforcer :: updatePolicy(const std::string& sec, const std::string& p_type, const std::vector& oldRule, const std::vector& newRule) {
- return true;
+bool Enforcer::updatePolicy(const std::string& sec, const std::string& p_type, const std::vector& oldRule, const std::vector& newRule) {
+ bool is_rule_updated = m_model->UpdatePolicy(sec, p_type, oldRule, newRule);
+ if(!is_rule_updated)
+ return false;
+
+ if(sec == "g") {
+ this->BuildIncrementalRoleLinks(policy_remove, p_type, { oldRule });
+ this->BuildIncrementalRoleLinks(policy_add, p_type, { newRule });
+ }
+ if (m_watcher && m_auto_notify_watcher) {
+ if(IsInstanceOf(m_watcher.get())) {
+ std::dynamic_pointer_cast(m_watcher)->UpdateForUpdatePolicy(oldRule, newRule);
+ }
+ else {
+ m_watcher->Update();
+ }
+ }
+ return is_rule_updated;
}
-bool Enforcer :: updatePolicies(const std::string& sec, const std::string& p_type, const std::vector>& p1, const std::vector>& p2) {
- return true;
+bool Enforcer::updatePolicies(const std::string& sec, const std::string& p_type, const std::vector>& oldRules, const std::vector>& newRules) {
+ bool is_rules_updated = m_model->UpdatePolicies(sec, p_type, oldRules, newRules);
+ if(!is_rules_updated)
+ return false;
+
+ if(sec == "g") {
+ this->BuildIncrementalRoleLinks(policy_remove, p_type, oldRules);
+ this->BuildIncrementalRoleLinks(policy_add, p_type, newRules);
+ }
+
+ if (m_watcher && m_auto_notify_watcher) {
+ if(IsInstanceOf(m_watcher.get())) {
+ std::dynamic_pointer_cast(m_watcher)->UpdateForUpdatePolicies(oldRules, newRules);
+ }
+ else {
+ m_watcher->Update();
+ }
+ }
+
+ return is_rules_updated;
}
} // namespace casbin
diff --git a/casbin/ip_parser/parser/Print.h b/casbin/ip_parser/parser/Print.h
index b0cfb859..98772cd8 100644
--- a/casbin/ip_parser/parser/Print.h
+++ b/casbin/ip_parser/parser/Print.h
@@ -1,8 +1,6 @@
#ifndef IP_PARSER_PARSER_PRINT
#define IP_PARSER_PARSER_PRINT
-#include
-
#include "./IP.h"
namespace casbin {
diff --git a/casbin/ip_parser/parser/pch.h b/casbin/ip_parser/parser/pch.h
index 37b9b303..16fa8a00 100644
--- a/casbin/ip_parser/parser/pch.h
+++ b/casbin/ip_parser/parser/pch.h
@@ -1,4 +1,6 @@
#ifndef IPPARSER_PARSER_PCH
#define IPPARSER_PARSER_PCH
+#include
+
#endif
\ No newline at end of file
diff --git a/casbin/logger.cpp b/casbin/logger.cpp
index a60566a1..e4c534bc 100644
--- a/casbin/logger.cpp
+++ b/casbin/logger.cpp
@@ -3,9 +3,8 @@
#ifndef LOGGER_CPP
#define LOGGER_CPP
-#include
-#include "log/Logger.h"
-#include "log/log_util.h"
+#include "./log/Logger.h"
+#include "./log/log_util.h"
namespace casbin {
diff --git a/casbin/model/model.cpp b/casbin/model/model.cpp
index 198a792b..ff366795 100644
--- a/casbin/model/model.cpp
+++ b/casbin/model/model.cpp
@@ -29,7 +29,7 @@
namespace casbin {
-std::unordered_map Model :: section_name_map = {
+std::unordered_map Model::section_name_map = {
{"r", "request_definition"},
{"p", "policy_definition"},
{"g", "role_definition"},
@@ -37,9 +37,9 @@ std::unordered_map Model :: section_name_map = {
{"m", "matchers"}
};
-std::vector Model :: required_sections{"r","p","e","m"};
+std::vector Model::required_sections{"r","p","e","m"};
-void Model :: LoadModelFromConfig(std::shared_ptr cfg) {
+void Model::LoadModelFromConfig(std::shared_ptr cfg) {
for (std::unordered_map::iterator it = section_name_map.begin(); it != section_name_map.end(); it++)
LoadSection(this, cfg, it->first);
@@ -52,11 +52,11 @@ void Model :: LoadModelFromConfig(std::shared_ptr cfg) {
throw MissingRequiredSections("missing required sections: " + Join(ms, ","));
}
-bool Model :: HasSection(std::string sec) {
+bool Model::HasSection(const std::string& sec) {
return this->m.find(sec) != this->m.end();
}
-void Model :: LoadSection(Model* model, std::shared_ptr cfg, std::string sec) {
+void Model::LoadSection(Model* model, std::shared_ptr cfg, const std::string& sec) {
int i = 1;
while(true) {
if (!LoadAssertion(model, cfg, sec, sec+GetKeySuffix(i))){
@@ -77,17 +77,17 @@ std::string Model ::GetKeySuffix(int i) {
return s;
}
-bool Model :: LoadAssertion(Model* model, std::shared_ptr cfg, std::string sec, std::string key) {
+bool Model::LoadAssertion(Model* model, std::shared_ptr cfg, const std::string& sec, const std::string& key) {
std::string value = cfg->GetString(section_name_map[sec] + "::" + key);
return model->AddDef(sec, key, value);
}
// AddDef adds an assertion to the model.
-bool Model :: AddDef(std::string sec, std::string key, std::string value) {
+bool Model::AddDef(const std::string& sec, const std::string& key, const std::string& value) {
if(value == "")
return false;
- std::shared_ptr ast(new Assertion());
+ std::shared_ptr ast = std::make_shared();
ast->key = key;
ast->value = value;
if (sec == "r" || sec == "p") {
@@ -100,7 +100,7 @@ bool Model :: AddDef(std::string sec, std::string key, std::string value) {
if (m.find(sec) == m.end())
m[sec] = AssertionMap();
- ast->policy = std::vector>{};
+ ast->policy = {};
m[sec].assertion_map[key] = ast;
@@ -108,19 +108,20 @@ bool Model :: AddDef(std::string sec, std::string key, std::string value) {
}
// LoadModel loads the model from model CONF file.
-void Model :: LoadModel(std::string path) {
+void Model::LoadModel(const std::string& path) {
std::shared_ptr cfg = Config::NewConfig(path);
LoadModelFromConfig(cfg);
}
// LoadModelFromText loads the model from the text.
-void Model :: LoadModelFromText(std::string text) {
+void Model::LoadModelFromText(const std::string& text) {
std::shared_ptr cfg = Config::NewConfigFromText(text);
LoadModelFromConfig(cfg);
}
// PrintModel prints the model to the log.
-void Model :: PrintModel() {
+void Model::PrintModel() {
+ // ------TODO------
// DefaultLogger df_logger;
// df_logger.EnableLog(true);
@@ -128,52 +129,53 @@ void Model :: PrintModel() {
// LogUtil::SetLogger(*logger);
// LogUtil::LogPrint("Model:");
- // for (unordered_map :: iterator it1 = M.begin() ; it1 != M.end() ; it1++){
- // for(unordered_map :: iterator it2 = (it1->second).AMap.begin() ; it2 != (it1->second).AMap.end() ; it2++){
+ // for (unordered_map ::iterator it1 = M.begin() ; it1 != M.end() ; it1++){
+ // for(unordered_map ::iterator it2 = (it1->second).AMap.begin() ; it2 != (it1->second).AMap.end() ; it2++){
// LogUtil::LogPrintf("%s.%s: %s", it1->first, it2->first, it2->second->Value);
// }
// }
}
-Model :: Model(){
+Model::Model(){
}
-Model :: Model(std::string path){
+Model::Model(const std::string& path){
LoadModel(path);
}
// NewModel creates an empty model.
-Model* Model :: NewModel() {
+Model* Model::NewModel() {
return new Model();
}
// NewModel creates a model from a .CONF file.
-Model* Model :: NewModelFromFile(std::string path) {
+Model* Model::NewModelFromFile(const std::string& path) {
Model* m = NewModel();
m->LoadModel(path);
return m;
}
// NewModel creates a model from a std::string which contains model text.
-Model* Model :: NewModelFromString(std::string text) {
+Model* Model::NewModelFromString(const std::string& text) {
Model* m = NewModel();
m->LoadModelFromText(text);
return m;
}
-void Model :: BuildIncrementalRoleLinks(std::shared_ptr rm, policy_op op, std::string sec, std::string p_type, std::vector> rules) {
+void Model::BuildIncrementalRoleLinks(std::shared_ptr rm, policy_op op, const std::string& sec, const std::string& p_type, const std::vector>& rules) {
if (sec == "g")
this->m[sec].assertion_map[p_type]->BuildIncrementalRoleLinks(rm, op, rules);
}
// BuildRoleLinks initializes the roles in RBAC.
-void Model :: BuildRoleLinks(std::shared_ptr rm) {
- for (std::unordered_map> :: iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++)
+void Model::BuildRoleLinks(std::shared_ptr rm) {
+ for (std::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.
-void Model :: PrintPolicy() {
+void Model::PrintPolicy() {
+ // ------TODO------
// DefaultLogger df_logger;
// df_logger.EnableLog(true);
@@ -182,35 +184,39 @@ void Model :: PrintPolicy() {
// LogUtil::LogPrint("Policy:");
- // for (std::unordered_map :: iterator it = this->m["p"].assertion_map.begin() ; it != this->m["p"].assertion_map.end() ; it++) {
+ // for (std::unordered_map::iterator it = this->m["p"].assertion_map.begin() ; it != this->m["p"].assertion_map.end() ; it++) {
// LogUtil::LogPrint(it->first, ": ", (it->second)->Value, ": ", (it->second)->policy);
// }
- // for (std::unordered_map :: iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++) {
+ // for (std::unordered_map::iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++) {
// LogUtil::LogPrint(it->first, ": ", (it->second)->Value, ": ", (it->second)->policy);
// }
}
// ClearPolicy clears all current policy.
-void Model :: ClearPolicy() {
- for (std::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();
+void Model::ClearPolicy() {
+ // Caching "p" assertion map by reference for the scope of this function
+ auto& p_assertion_map = this->m["p"].assertion_map;
+ for (auto it : p_assertion_map) {
+ if((it.second)->policy.size() > 0)
+ (it.second)->policy.clear();
}
- for (std::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();
+ // Caching "g" assertion map by reference for the scope of this function
+ auto& g_assertion_map = this->m["g"].assertion_map;
+ for (auto it : g_assertion_map){
+ if((it.second)->policy.size() > 0)
+ (it.second)->policy.clear();
}
}
// GetPolicy gets all rules in a policy.
-std::vector> Model :: GetPolicy(std::string sec, std::string p_type) {
- return (this->m)[sec].assertion_map[p_type]->policy;
+std::vector> Model::GetPolicy(const std::string& sec, const std::string& p_type) {
+ return this->m[sec].assertion_map[p_type]->policy;
}
// GetFilteredPolicy gets rules based on field filters from a policy.
-std::vector> Model :: GetFilteredPolicy(std::string sec, std::string p_type, int field_index, std::vector field_values) {
+std::vector> Model::GetFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector& field_values) {
std::vector> res;
std::vector> policy(m[sec].assertion_map[p_type]->policy);
for(int i = 0 ; i < policy.size() ; i++){
@@ -229,17 +235,17 @@ std::vector> Model :: GetFilteredPolicy(std::string sec
}
// HasPolicy determines whether a model has the specified policy rule.
-bool Model :: HasPolicy(std::string sec, std::string p_type, std::vector rule) {
- std::vector> policy = m[sec].assertion_map[p_type]->policy;
- for(int i=0 ; i < policy.size() ; i++)
- if (ArrayEquals(rule, policy[i]))
+bool Model::HasPolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
+ auto& policy = this->m[sec].assertion_map[p_type]->policy;
+ for(auto policy_it : policy)
+ if (ArrayEquals(rule, policy_it))
return true;
return false;
}
// AddPolicy adds a policy rule to the model.
-bool Model :: AddPolicy(std::string sec, std::string p_type, std::vector rule) {
+bool Model::AddPolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
if(!this->HasPolicy(sec, p_type, rule)) {
m[sec].assertion_map[p_type]->policy.push_back(rule);
return true;
@@ -249,43 +255,114 @@ bool Model :: AddPolicy(std::string sec, std::string p_type, std::vector> rules) {
- for (int i = 0; i < rules.size(); i++)
- if (this->HasPolicy(sec, p_type, rules[i]))
+bool Model::AddPolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules) {
+ for (auto rule : rules)
+ if (this->HasPolicy(sec, p_type, rule))
return false;
- for (int i = 0; i < rules.size(); i++)
- this->m[sec].assertion_map[p_type]->policy.push_back(rules[i]);
+ for (auto rule : rules)
+ this->m[sec].assertion_map[p_type]->policy.push_back(rule);
+
+ return true;
+}
+
+bool Model::UpdatePolicy(const std::string& sec, const std::string& p_type, const std::vector& oldRule, const std::vector& newRule) {
+ // Caching policy by reference for the scope of this function
+ auto& policy = m[sec].assertion_map[p_type]->policy;
+
+ // Status flags
+ bool is_oldRule_deleted = false, is_newRule_added = false;
+
+ for (auto it = policy.begin(); it != policy.end(); ++it) {
+ if(ArrayEquals(oldRule, *it)) {
+ policy.erase(it);
+ is_oldRule_deleted = true;
+ break;
+ }
+ }
+
+ if(!is_oldRule_deleted)
+ return false;
+
+ // Prevents duplicate policies
+ if(!this->HasPolicy(sec, p_type, newRule)) {
+ policy.push_back(newRule);
+ is_newRule_added = true;
+ }
+
+ if(!is_newRule_added)
+ return false;
+
+ return is_oldRule_deleted && is_newRule_added;
+}
+
+bool Model::UpdatePolicies(const std::string& sec, const std::string& p_type, const std::vector>& oldRules, const std::vector>& newRules) {
+ // Caching policy by reference for the scope of this function
+ auto& policy = this->m[sec].assertion_map[p_type]->policy;
+
+ // Deleting old rules
+ bool is_oldRule_deleted;
+ for (auto oldRule : oldRules) {
+ is_oldRule_deleted = false;
+ for (auto it = policy.begin(); it != policy.end(); ++it) {
+ if(ArrayEquals(oldRule, *it)) {
+ policy.erase(it);
+ is_oldRule_deleted = true;
+ break;
+ }
+ }
+ if(!is_oldRule_deleted)
+ return false;
+ }
+
+ // Checking if the policy already contains newRule
+ for(auto newRule : newRules) {
+ if(!this->HasPolicy(sec, p_type, newRule))
+ continue;
+ else
+ return false;
+ }
+
+ for(auto newRule : newRules) {
+ policy.push_back(newRule);
+ }
return true;
}
// RemovePolicy removes a policy rule from the model.
-bool Model :: RemovePolicy(std::string sec, std::string p_type, std::vector rule) {
- for (int i = 0 ; i < m[sec].assertion_map[p_type]->policy.size() ; i++) {
- if (ArrayEquals(rule, m[sec].assertion_map[p_type]->policy[i])) {
- m[sec].assertion_map[p_type]->policy.erase(m[sec].assertion_map[p_type]->policy.begin() + i);
+bool Model::RemovePolicy(const std::string& sec, const std::string& p_type, const std::vector& rule) {
+ // Caching policy by reference for the scope of this function
+ auto& policy = m[sec].assertion_map[p_type]->policy;
+ for (auto it = policy.begin(); it != policy.end(); ++it) {
+ if(ArrayEquals(rule, *it)) {
+ policy.erase(it);
return true;
}
}
-
return false;
}
// RemovePolicies removes policy rules from the model.
-bool Model :: RemovePolicies(std::string sec, std::string p_type, std::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]))
- goto OUTER;
+bool Model::RemovePolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules) {
+ // Caching policy by reference for the scope of this function
+ auto& policy = this->m[sec].assertion_map[p_type]->policy;
+
+ bool is_equal;
+ for (auto rule : rules) {
+ is_equal = false;
+ for (auto policy_it : policy) {
+ if (ArrayEquals(rule, policy_it))
+ is_equal = true;
}
- return false;
+ if(!is_equal)
+ 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++){
- 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);
+ for (auto rule : rules) {
+ for (auto policy_it = policy.begin(); policy_it != policy.end(); ++policy_it) {
+ if (ArrayEquals(rule, *policy_it))
+ policy.erase(policy_it);
}
}
@@ -293,7 +370,7 @@ bool Model :: RemovePolicies(std::string sec, std::string p_type, std::vector>> Model :: RemoveFilteredPolicy(std::string sec, std::string p_type, int field_index, std::vector field_values) {
+std::pair>> Model::RemoveFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector& field_values) {
std::vector> tmp;
std::vector> effects;
std::vector> policy(m[sec].assertion_map[p_type]->policy);
@@ -320,7 +397,7 @@ std::pair>> Model :: RemoveFilteredPo
}
// GetValuesForFieldInPolicy gets all values for a field for all rules in a policy, duplicated values are removed.
-std::vector Model :: GetValuesForFieldInPolicy(std::string sec, std::string p_type, int field_index) {
+std::vector Model::GetValuesForFieldInPolicy(const std::string& sec, const std::string& p_type, int field_index) {
std::vector values;
std::vector> policy(m[sec].assertion_map[p_type]->policy);
for(int i = 0 ; i < policy.size() ; i++)
@@ -332,10 +409,10 @@ std::vector Model :: GetValuesForFieldInPolicy(std::string sec, std
}
// GetValuesForFieldInPolicyAllTypes gets all values for a field for all rules in a policy of all p_types, duplicated values are removed.
-std::vector Model :: GetValuesForFieldInPolicyAllTypes(std::string sec, int field_index) {
+std::vector Model::GetValuesForFieldInPolicyAllTypes(const std::string& sec, int field_index) {
std::vector values;
- for (std::unordered_map> :: iterator it = m[sec].assertion_map.begin() ; it != m[sec].assertion_map.end() ; it++) {
+ for (std::unordered_map>::iterator it = m[sec].assertion_map.begin() ; it != m[sec].assertion_map.end() ; it++) {
std::vector values_for_field(this->GetValuesForFieldInPolicy(sec, it->first, field_index));
for(int i = 0 ; i < values_for_field.size() ; i++)
values.push_back(values_for_field[i]);
diff --git a/casbin/model/model.h b/casbin/model/model.h
index fc1d2361..5bfb546f 100644
--- a/casbin/model/model.h
+++ b/casbin/model/model.h
@@ -32,38 +32,38 @@ class AssertionMap {
};
// Model represents the whole access control model.
-class Model{
+class Model {
private:
static std::unordered_map section_name_map;
- static void LoadSection(Model* model, std::shared_ptr cfg, std::string sec);
+ static void LoadSection(Model* model, std::shared_ptr cfg, const std::string& sec);
static std::string GetKeySuffix(int i);
- static bool LoadAssertion(Model* model, std::shared_ptr cfg, std::string sec, std::string key);
+ static bool LoadAssertion(Model* model, std::shared_ptr cfg, const std::string& sec, const std::string& key);
public:
Model();
- Model(std::string path);
+ Model(const std::string& path);
std::unordered_map m;
// Minimal required sections for a model to be valid
static std::vector required_sections;
- bool HasSection(std::string sec);
+ bool HasSection(const std::string& sec);
// AddDef adds an assertion to the model.
- bool AddDef(std::string sec, std::string key, std::string value);
+ bool AddDef(const std::string& sec, const std::string& key, const std::string& value);
// LoadModel loads the model from model CONF file.
- void LoadModel(std::string path);
+ void LoadModel(const std::string& path);
// LoadModelFromText loads the model from the text.
- void LoadModelFromText(std::string text);
+ void LoadModelFromText(const std::string& text);
void LoadModelFromConfig(std::shared_ptr cfg);
@@ -74,12 +74,12 @@ class Model{
static Model* NewModel();
// NewModel creates a model from a .CONF file.
- static Model* NewModelFromFile(std::string path);
+ static Model* NewModelFromFile(const std::string& path);
// NewModel creates a model from a std::string which contains model text.
- static Model* NewModelFromString(std::string text);
+ static Model* NewModelFromString(const std::string& text);
- void BuildIncrementalRoleLinks(std::shared_ptr rm, policy_op op, std::string sec, std::string p_type, std::vector> rules);
+ void BuildIncrementalRoleLinks(std::shared_ptr rm, policy_op op, const std::string& sec, const std::string& p_type, const std::vector>& rules);
// BuildRoleLinks initializes the roles in RBAC.
void BuildRoleLinks(std::shared_ptr rm);
@@ -91,34 +91,40 @@ class Model{
void ClearPolicy();
// GetPolicy gets all rules in a policy.
- std::vector> GetPolicy(std::string sec, std::string p_type);
+ std::vector> GetPolicy(const std::string& sec, const std::string& p_type);
// GetFilteredPolicy gets rules based on field filters from a policy.
- std::vector> GetFilteredPolicy(std::string sec, std::string p_type, int field_index, std::vector field_values);
+ std::vector> GetFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector& field_values);
// HasPolicy determines whether a model has the specified policy rule.
- bool HasPolicy(std::string sec, std::string p_type, std::vector rule);
+ bool HasPolicy(const std::string& sec, const std::string& p_type, const std::vector& rule);
// AddPolicy adds a policy rule to the model.
- bool AddPolicy(std::string sec, std::string p_type, std::vector rule);
+ bool AddPolicy(const std::string& sec, const std::string& p_type, const std::vector& rule);
// AddPolicies adds policy rules to the model.
- bool AddPolicies(std::string sec, std::string p_type, std::vector> rules);
+ bool AddPolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules);
+
+ // UpdatePolicy updates a policy rule from the model.
+ bool UpdatePolicy(const std::string& sec, const std::string& p_type, const std::vector& oldRule, const std::vector& newRule);
+
+ // UpdatePolicies updates a set of policy rules from the model.
+ bool UpdatePolicies(const std::string& sec, const std::string& p_type, const std::vector>& oldRules, const std::vector>& newRules);
// RemovePolicy removes a policy rule from the model.
- bool RemovePolicy(std::string sec, std::string p_type, std::vector rule);
+ bool RemovePolicy(const std::string& sec, const std::string& p_type, const std::vector& rule);
// RemovePolicies removes policy rules from the model.
- bool RemovePolicies(std::string sec, std::string p_type, std::vector> rules);
+ bool RemovePolicies(const std::string& sec, const std::string& p_type, const std::vector>& rules);
// RemoveFilteredPolicy removes policy rules based on field filters from the model.
- std::pair>> RemoveFilteredPolicy(std::string sec, std::string p_type, int field_index, std::vector field_values);
+ std::pair>> RemoveFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector& field_values);
// GetValuesForFieldInPolicy gets all values for a field for all rules in a policy, duplicated values are removed.
- std::vector GetValuesForFieldInPolicy(std::string sec, std::string p_type, int field_index);
+ std::vector GetValuesForFieldInPolicy(const std::string& sec, const std::string& p_type, int field_index);
// GetValuesForFieldInPolicyAllTypes gets all values for a field for all rules in a policy of all p_types, duplicated values are removed.
- std::vector GetValuesForFieldInPolicyAllTypes(std::string sec, int field_index);
+ std::vector GetValuesForFieldInPolicyAllTypes(const std::string& sec, int field_index);
};
}; // namespace casbin
diff --git a/casbin/pch.h b/casbin/pch.h
index 787a37c4..d8fd4627 100644
--- a/casbin/pch.h
+++ b/casbin/pch.h
@@ -25,5 +25,18 @@
// add headers that you want to pre-compile here
// #include "framework.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#endif //PCH_H
diff --git a/casbin/persist/watcher_update.h b/casbin/persist/watcher_update.h
new file mode 100644
index 00000000..c0ea147a
--- /dev/null
+++ b/casbin/persist/watcher_update.h
@@ -0,0 +1,50 @@
+/*
+* Copyright 2020 The casbin Authors. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef WATCHER_UPDATE_H
+#define WATCHER_UPDATE_H
+
+#include "watcher.h"
+
+namespace casbin {
+
+/**
+ * @brief WatcherUpdatable is the strengthen for Casbin watchers.
+ *
+ */
+class WatcherUpdatable : public Watcher {
+public:
+ /**
+ * @brief UpdateForUpdatePolicy calls the update callback of other instances to synchronize their policy.
+ * It is called after Enforcer::UpdatePolicy()
+ *
+ * @param oldRule Old rule which is to be replaced
+ * @param newRule New rule which will replace oldRule
+ */
+ virtual void UpdateForUpdatePolicy(const std::vector& oldRule, const std::vector& newRule) = 0;
+ /**
+ * @brief UpdateForUpdatePolicies calls the update callback of other instances to synchronize their policy.
+ * It is called after Enforcer::UpdatePolicies()
+ *
+ * @param oldRules Old rules which are to be replaced
+ * @param newRules New rules which will replace oldRules
+ */
+ virtual void UpdateForUpdatePolicies(const std::vector>& oldRules, const std::vector>& newRules) = 0;
+};
+
+}
+
+#endif
diff --git a/casbin/util/is_instance_of.cpp b/casbin/util/is_instance_of.cpp
index 6395090f..b3a72608 100644
--- a/casbin/util/is_instance_of.cpp
+++ b/casbin/util/is_instance_of.cpp
@@ -22,6 +22,7 @@
#include "./util.h"
#include "../persist/watcher_ex.h"
+#include "../persist/watcher_update.h"
namespace casbin {
@@ -31,6 +32,7 @@ bool IsInstanceOf(const T*) {
}
template bool IsInstanceOf(class Watcher const*);
+template bool IsInstanceOf(class Watcher const*);
} // namespace casbin
diff --git a/casbin/util/ticker.h b/casbin/util/ticker.h
index f1889268..3725df06 100644
--- a/casbin/util/ticker.h
+++ b/casbin/util/ticker.h
@@ -14,18 +14,15 @@
* limitations under the License.
*/
+#include "pch.h"
+
#ifndef TICKER_H
#define TICKER_H
-#include
#include
+#include
#include
-#include
-#include
#include
-#include
-#include
-#include
namespace casbin {
diff --git a/test/test_management_api.cpp b/test/test_management_api.cpp
index fd4037e5..d49da842 100644
--- a/test/test_management_api.cpp
+++ b/test/test_management_api.cpp
@@ -23,10 +23,10 @@ namespace test_management_api
std::string policy = "../../examples/rbac_policy.csv";
Enforcer e = Enforcer(model, policy);
- Assert::IsTrue(ArrayEquals(std::vector{ "alice", "bob", "data2_admin" }, e.GetAllSubjects()));
- Assert::IsTrue(ArrayEquals(std::vector{ "data1", "data2" }, e.GetAllObjects()));
- Assert::IsTrue(ArrayEquals(std::vector{ "read", "write" }, e.GetAllActions()));
- Assert::IsTrue(ArrayEquals(std::vector{ "data2_admin" }, e.GetAllRoles()));
+ Assert::IsTrue(ArrayEquals({ "alice", "bob", "data2_admin" }, e.GetAllSubjects()));
+ Assert::IsTrue(ArrayEquals({ "data1", "data2" }, e.GetAllObjects()));
+ Assert::IsTrue(ArrayEquals({ "read", "write" }, e.GetAllActions()));
+ Assert::IsTrue(ArrayEquals({ "data2_admin" }, e.GetAllRoles()));
}
void TestGetPolicy(Enforcer e, std::vector> res) {
@@ -89,35 +89,35 @@ namespace test_management_api
{ "data2_admin", "data2", "read" },
{ "data2_admin", "data2", "write" }});
- TestGetFilteredPolicy(e, 0, std::vector>{ {"alice", "data1", "read"} }, std::vector{"alice"});
- TestGetFilteredPolicy(e, 0, std::vector>{ {"bob", "data2", "write"}}, std::vector{"bob"});
- TestGetFilteredPolicy(e, 0, std::vector>{ {"data2_admin", "data2", "read"}, { "data2_admin", "data2", "write" }}, std::vector{"data2_admin"});
- TestGetFilteredPolicy(e, 1, std::vector>{ {"alice", "data1", "read"}}, std::vector{"data1"});
- TestGetFilteredPolicy(e, 1, std::vector>{ {"bob", "data2", "write"}, { "data2_admin", "data2", "read" }, { "data2_admin", "data2", "write" }}, std::vector{"data2"});
- TestGetFilteredPolicy(e, 2, std::vector>{ {"alice", "data1", "read"}, { "data2_admin", "data2", "read" }}, std::vector{"read"});
- TestGetFilteredPolicy(e, 2, std::vector>{ {"bob", "data2", "write"}, { "data2_admin", "data2", "write" }}, std::vector{"write"});
+ TestGetFilteredPolicy(e, 0, { {"alice", "data1", "read"} }, {"alice"});
+ TestGetFilteredPolicy(e, 0, { {"bob", "data2", "write"}}, {"bob"});
+ TestGetFilteredPolicy(e, 0, { {"data2_admin", "data2", "read"}, { "data2_admin", "data2", "write" }}, {"data2_admin"});
+ TestGetFilteredPolicy(e, 1, { {"alice", "data1", "read"}}, {"data1"});
+ TestGetFilteredPolicy(e, 1, { {"bob", "data2", "write"}, { "data2_admin", "data2", "read" }, { "data2_admin", "data2", "write" }}, {"data2"});
+ TestGetFilteredPolicy(e, 2, { {"alice", "data1", "read"}, { "data2_admin", "data2", "read" }}, {"read"});
+ TestGetFilteredPolicy(e, 2, { {"bob", "data2", "write"}, { "data2_admin", "data2", "write" }}, {"write"});
- TestGetFilteredPolicy(e, 0, std::vector>{ {"data2_admin", "data2", "read"}, { "data2_admin", "data2", "write" }}, std::vector{"data2_admin", "data2"});
+ TestGetFilteredPolicy(e, 0, { {"data2_admin", "data2", "read"}, { "data2_admin", "data2", "write" }}, {"data2_admin", "data2"});
// Note: "" (empty string) in fieldValues means matching all values.
- TestGetFilteredPolicy(e, 0, std::vector>{ {"data2_admin", "data2", "read"}}, std::vector{"data2_admin", "", "read"});
- TestGetFilteredPolicy(e, 1, std::vector>{ {"bob", "data2", "write"}, { "data2_admin", "data2", "write" }}, std::vector{"data2", "write"});
+ TestGetFilteredPolicy(e, 0, { {"data2_admin", "data2", "read"}}, {"data2_admin", "", "read"});
+ TestGetFilteredPolicy(e, 1, { {"bob", "data2", "write"}, { "data2_admin", "data2", "write" }}, {"data2", "write"});
- TestHasPolicy(e, std::vector{"alice", "data1", "read"}, true);
- TestHasPolicy(e, std::vector{"bob", "data2", "write"}, true);
- TestHasPolicy(e, std::vector{"alice", "data2", "read"}, false);
- TestHasPolicy(e, std::vector{"bob", "data3", "write"}, false);
+ TestHasPolicy(e, {"alice", "data1", "read"}, true);
+ TestHasPolicy(e, {"bob", "data2", "write"}, true);
+ TestHasPolicy(e, {"alice", "data2", "read"}, false);
+ TestHasPolicy(e, {"bob", "data3", "write"}, false);
TestGetGroupingPolicy(e, std::vector>{ {"alice", "data2_admin"}});
- TestGetFilteredGroupingPolicy(e, 0, std::vector>{{"alice", "data2_admin"}}, std::vector{"alice"});
- TestGetFilteredGroupingPolicy(e, 0, std::vector>{}, std::vector{"bob"});
- TestGetFilteredGroupingPolicy(e, 1, std::vector>{}, std::vector{"data1_admin"});
- TestGetFilteredGroupingPolicy(e, 1, std::vector>{ {"alice", "data2_admin"}}, std::vector{"data2_admin"});
+ TestGetFilteredGroupingPolicy(e, 0, {{"alice", "data2_admin"}}, {"alice"});
+ TestGetFilteredGroupingPolicy(e, 0, {}, {"bob"});
+ TestGetFilteredGroupingPolicy(e, 1, {}, {"data1_admin"});
+ TestGetFilteredGroupingPolicy(e, 1, { {"alice", "data2_admin"}}, {"data2_admin"});
// Note: "" (empty string) in fieldValues means matching all values.
- TestGetFilteredGroupingPolicy(e, 0, std::vector>{ {"alice", "data2_admin"}}, std::vector{"", "data2_admin"});
+ TestGetFilteredGroupingPolicy(e, 0, { {"alice", "data2_admin"}}, {"", "data2_admin"});
- TestHasGroupingPolicy(e, std::vector{"alice", "data2_admin"}, true);
- TestHasGroupingPolicy(e, std::vector{"bob", "data2_admin"}, false);
+ TestHasGroupingPolicy(e, {"alice", "data2_admin"}, true);
+ TestHasGroupingPolicy(e, {"bob", "data2_admin"}, false);
}
@@ -127,19 +127,20 @@ namespace test_management_api
std::shared_ptr adapter = std::shared_ptr(new BatchFileAdapter(policy));
Enforcer e = Enforcer(model, adapter);
- TestGetPolicy(e, std::vector>{
+ TestGetPolicy(e, {
{"alice", "data1", "read"},
- { "bob", "data2", "write" },
- { "data2_admin", "data2", "read" },
- { "data2_admin", "data2", "write" }});
+ {"bob", "data2", "write"},
+ {"data2_admin", "data2", "read"},
+ {"data2_admin", "data2", "write"}
+ });
- e.RemovePolicy(std::vector{"alice", "data1", "read"});
- e.RemovePolicy(std::vector{"bob", "data2", "write"});
- e.RemovePolicy(std::vector{"alice", "data1", "read"});
- e.AddPolicy(std::vector{"eve", "data3", "read"});
- e.AddPolicy(std::vector{"eve", "data3", "read"});
+ e.RemovePolicy({"alice", "data1", "read"});
+ e.RemovePolicy({"bob", "data2", "write"});
+ e.RemovePolicy({"alice", "data1", "read"});
+ e.AddPolicy({"eve", "data3", "read"});
+ e.AddPolicy({"eve", "data3", "read"});
- std::vector>rules{
+ std::vector> rules {
{"jack", "data4", "read"},
{"katy", "data4", "write"},
{"leyo", "data4", "read"},
@@ -149,91 +150,113 @@ namespace test_management_api
e.AddPolicies(rules);
e.AddPolicies(rules);
- TestGetPolicy(e, std::vector>{
+ TestGetPolicy(e, {
{"data2_admin", "data2", "read"},
{ "data2_admin", "data2", "write" },
{ "eve", "data3", "read" },
{ "jack", "data4", "read" },
{ "katy", "data4", "write" },
{ "leyo", "data4", "read" },
- { "ham", "data4", "write" }});
+ { "ham", "data4", "write" }
+ });
e.RemovePolicies(rules);
e.RemovePolicies(rules);
- std::vectornamed_policy{ "eve", "data3", "read" };
+ std::vector named_policy{ "eve", "data3", "read" };
e.RemoveNamedPolicy("p", named_policy);
e.AddNamedPolicy("p", named_policy);
- TestGetPolicy(e, std::vector>{
+ TestGetPolicy(e, {
{"data2_admin", "data2", "read"},
{ "data2_admin", "data2", "write" },
- { "eve", "data3", "read" }});
+ { "eve", "data3", "read" }
+ });
- e.RemoveFilteredPolicy(1, std::vector{"data2"});
+ e.RemoveFilteredPolicy(1, {"data2"});
- TestGetPolicy(e, std::vector>{ {"eve", "data3", "read"}});
+ TestGetPolicy(e, { {"eve", "data3", "read"}});
+
+ e.UpdatePolicy({"eve", "data3", "read"}, {"eve", "data3", "write"});
+ TestGetPolicy(e, {{"eve", "data3", "write"}});
+
+ e.AddPolicies(rules);
+ e.UpdatePolicies({
+ {"eve", "data3", "write"},
+ {"leyo", "data4", "read"},
+ {"katy", "data4", "write"}
+ }, {
+ {"eve", "data3", "read"},
+ {"leyo", "data4", "write"},
+ {"katy", "data1", "write"}
+ });
+
+ TestGetPolicy(e, {
+ {"eve", "data3", "read"},
+ {"leyo", "data4", "write"},
+ {"katy", "data1", "write"}
+ });
}
TEST_METHOD(TestModifyGroupingPolicyAPI) {
std::string model = "../../examples/rbac_model.conf";
std::string policy = "../../examples/rbac_policy.csv";
- std::shared_ptr adapter = std::shared_ptr(new BatchFileAdapter(policy));
+ std::shared_ptr adapter = std::make_shared(policy);
Enforcer e = Enforcer(model, adapter);
- Assert::IsTrue(ArrayEquals(std::vector{"data2_admin"}, e.GetRolesForUser("alice")));
- Assert::IsTrue(ArrayEquals(std::vector{}, e.GetRolesForUser("bob")));
- Assert::IsTrue(ArrayEquals(std::vector{}, e.GetRolesForUser("eve")));
- Assert::IsTrue(ArrayEquals(std::vector{}, e.GetRolesForUser("non_exist")));
+ Assert::IsTrue(ArrayEquals({"data2_admin"}, e.GetRolesForUser("alice")));
+ Assert::IsTrue(ArrayEquals({}, e.GetRolesForUser("bob")));
+ Assert::IsTrue(ArrayEquals({}, e.GetRolesForUser("eve")));
+ Assert::IsTrue(ArrayEquals({}, e.GetRolesForUser("non_exist")));
- e.RemoveGroupingPolicy(std::vector{"alice", "data2_admin"});
- e.AddGroupingPolicy(std::vector{"bob", "data1_admin"});
- e.AddGroupingPolicy(std::vector{"eve", "data3_admin"});
+ e.RemoveGroupingPolicy({"alice", "data2_admin"});
+ e.AddGroupingPolicy({"bob", "data1_admin"});
+ e.AddGroupingPolicy({"eve", "data3_admin"});
- std::vector> grouping_rules{
+ std::vector> grouping_rules {
{"ham", "data4_admin"},
{"jack", "data5_admin"},
};
e.AddGroupingPolicies(grouping_rules);
- Assert::IsTrue(ArrayEquals(std::vector{"data4_admin"}, e.GetRolesForUser("ham")));
- Assert::IsTrue(ArrayEquals(std::vector{"data5_admin"}, e.GetRolesForUser("jack")));
+ Assert::IsTrue(ArrayEquals({"data4_admin"}, e.GetRolesForUser("ham")));
+ Assert::IsTrue(ArrayEquals({"data5_admin"}, e.GetRolesForUser("jack")));
e.RemoveGroupingPolicies(grouping_rules);
- Assert::IsTrue(ArrayEquals(std::vector{}, e.GetRolesForUser("alice")));
+ Assert::IsTrue(ArrayEquals({}, e.GetRolesForUser("alice")));
std::vector named_grouping_policy{ "alice", "data2_admin" };
- Assert::IsTrue(ArrayEquals(std::vector{}, e.GetRolesForUser("alice")));
+ Assert::IsTrue(ArrayEquals({}, e.GetRolesForUser("alice")));
e.AddNamedGroupingPolicy("g", named_grouping_policy);
- Assert::IsTrue(ArrayEquals(std::vector{"data2_admin"}, e.GetRolesForUser("alice")));
+ Assert::IsTrue(ArrayEquals({"data2_admin"}, e.GetRolesForUser("alice")));
e.RemoveNamedGroupingPolicy("g", named_grouping_policy);
e.AddNamedGroupingPolicies("g", grouping_rules);
e.AddNamedGroupingPolicies("g", grouping_rules);
- Assert::IsTrue(ArrayEquals(std::vector