From edde0509431c87523dc6c47e458869becb57dea8 Mon Sep 17 00:00:00 2001 From: "Yash Pandey (YP)" Date: Mon, 16 Aug 2021 16:11:51 +0530 Subject: [PATCH] feat: Added bindings for synced enforcer Signed-off-by: Yash Pandey (YP) --- bindings/python/CMakeLists.txt | 4 +- bindings/python/main.cpp | 1 + bindings/python/py_cached_enforcer.cpp | 18 ++-- bindings/python/py_casbin.h | 1 + bindings/python/py_enforcer.cpp | 18 ++-- bindings/python/py_synced_enforcer.cpp | 119 +++++++++++++++++++++++++ casbin/enforcer_cached.cpp | 45 ++++++++++ casbin/enforcer_cached.h | 16 ++++ casbin/enforcer_synced.cpp | 12 ++- casbin/enforcer_synced.h | 7 +- include/casbin/casbin_enforcer.h | 23 ++++- tests/python/pycasbin_test_suite.py | 4 + tests/python/test_cached_enforcer.py | 50 +++++++++++ tests/python/test_synced_enforcer.py | 63 +++++++++++++ 14 files changed, 356 insertions(+), 25 deletions(-) create mode 100644 bindings/python/py_synced_enforcer.cpp create mode 100644 tests/python/test_cached_enforcer.py create mode 100644 tests/python/test_synced_enforcer.py diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index e9dd1128..bf316d9c 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -18,7 +18,9 @@ set(SOURCES py_enforcer.cpp py_abac_data.cpp py_model.cpp - py_config.cpp) + py_config.cpp + py_synced_enforcer.cpp +) set(HEADERS py_casbin.h diff --git a/bindings/python/main.cpp b/bindings/python/main.cpp index c413c802..e6a9c6fb 100644 --- a/bindings/python/main.cpp +++ b/bindings/python/main.cpp @@ -39,6 +39,7 @@ PYBIND11_MODULE(pycasbin, m) { bindABACData(m); bindPyModel(m); bindPyConfig(m); + bindPySyncedEnforcer(m); m.attr("__version__") = PY_CASBIN_VERSION; } diff --git a/bindings/python/py_cached_enforcer.cpp b/bindings/python/py_cached_enforcer.cpp index 60f04bdd..4c3ce222 100644 --- a/bindings/python/py_cached_enforcer.cpp +++ b/bindings/python/py_cached_enforcer.cpp @@ -53,11 +53,12 @@ void bindPyCachedEnforcer(py::module &m) { @param enable_log whether to enable Casbin's log. )doc") - // .def("Enforce", py::overload_cast(&casbin::CachedEnforcer::Enforce), R"doc( - // Enforce with a vector param,decides whether a "subject" can access a - // "object" with the operation "action", input parameters are usually: (sub, - // obj, act). - // )doc") + .def("InvalidateCache", &casbin::CachedEnforcer::InvalidateCache) + + .def("Enforce", py::overload_cast(&casbin::CachedEnforcer::Enforce), R"doc( + Enforce with a map param,decides whether a "subject" can access a "object" + with the operation "action", input parameters are usually: (sub, obj, act). + )doc") .def("Enforce", py::overload_cast(&casbin::CachedEnforcer::Enforce), R"doc( Enforce with a map param,decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). @@ -66,12 +67,7 @@ void bindPyCachedEnforcer(py::module &m) { Enforce with a map param,decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). )doc") - // .def("EnforceWithMatcher", py::overload_cast(&casbin::CachedEnforcer::EnforceWithMatcher), R"doc( - // EnforceWithMatcher use a custom matcher to decides whether a "subject" can - // access a "object" with the operation "action", input parameters are - // usually: (matcher, sub, obj, act), use model matcher by default when - // matcher is "". - // )doc") + .def("EnforceWithMatcher", py::overload_cast(&casbin::CachedEnforcer::EnforceWithMatcher), R"doc( EnforceWithMatcher use a custom matcher to decides whether a "subject" can access a "object" with the operation "action", input parameters are diff --git a/bindings/python/py_casbin.h b/bindings/python/py_casbin.h index 1646cf1c..6a13b6c2 100644 --- a/bindings/python/py_casbin.h +++ b/bindings/python/py_casbin.h @@ -23,3 +23,4 @@ void bindPyCachedEnforcer(py::module &m); void bindABACData(py::module &m); void bindPyModel(py::module &m); void bindPyConfig(py::module &m); +void bindPySyncedEnforcer(py::module& m); diff --git a/bindings/python/py_enforcer.cpp b/bindings/python/py_enforcer.cpp index d952fd01..d806f0db 100644 --- a/bindings/python/py_enforcer.cpp +++ b/bindings/python/py_enforcer.cpp @@ -24,13 +24,14 @@ namespace py = pybind11; void bindPyEnforcer(py::module& m) { py::class_(m, "Enforcer") - .def(py::init<>()) - .def(py::init()) - .def(py::init>()) - .def(py::init, std::shared_ptr>()) - .def(py::init>()) - .def(py::init()) - .def(py::init()) + .def(py::init<>(), "") + .def(py::init(), "") + .def(py::init>(), "") + .def(py::init, std::shared_ptr>(), "") + .def(py::init>(), "") + .def(py::init(), "") + .def(py::init(), "") + .def("InitWithFile", &casbin::Enforcer::InitWithFile, "InitWithFile initializes an enforcer with a model file and a policy file.") .def("InitWithAdapter", &casbin::Enforcer::InitWithAdapter, "InitWithAdapter initializes an enforcer with a database adapter.") .def("InitWithModelAndAdapter", &casbin::Enforcer::InitWithModelAndAdapter, "InitWithModelAndAdapter initializes an enforcer with a model and a database adapter.") @@ -40,6 +41,7 @@ void bindPyEnforcer(py::module& m) { Because the policy is attached to a model, so the policy is invalidated and needs to be reloaded by calling LoadPolicy(). )doc") + .def("GetModel", &casbin::Enforcer::GetModel, "GetModel gets the current model.") .def("SetModel", &casbin::Enforcer::SetModel, "SetModel sets the current model.") .def("GetAdapter", &casbin::Enforcer::GetAdapter, "GetAdapter gets the current adapter.") @@ -60,10 +62,8 @@ void bindPyEnforcer(py::module& m) { .def("EnableAutoBuildRoleLinks", &casbin::Enforcer::EnableAutoBuildRoleLinks, "EnableAutoBuildRoleLinks controls whether to rebuild the role inheritance relations when a role is added or deleted.") .def("BuildRoleLinks", &casbin::Enforcer::BuildRoleLinks, "BuildRoleLinks manually rebuild the role inheritance relations.") .def("BuildIncrementalRoleLinks", &casbin::Enforcer::BuildIncrementalRoleLinks, "BuildIncrementalRoleLinks provides incremental build the role inheritance relations.") - // .def("Enforce", py::overload_cast(&casbin::Enforcer::Enforce), "Enforce decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (sub, obj, act).") .def("Enforce", py::overload_cast(&casbin::Enforcer::Enforce), "Enforce with a vector param, decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (sub, obj, act).") .def("Enforce", py::overload_cast(&casbin::Enforcer::Enforce), "Enforce with a map param, decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (sub, obj, act).") - // .def("EnforceWithMatcher", py::overload_cast(&casbin::Enforcer::EnforceWithMatcher), "EnforceWithMatcher use a custom matcher to decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is \"\".") .def("EnforceWithMatcher", py::overload_cast(&casbin::Enforcer::EnforceWithMatcher), "EnforceWithMatcher use a custom matcher to decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is \"\".") .def("EnforceWithMatcher", py::overload_cast(&casbin::Enforcer::EnforceWithMatcher), "EnforceWithMatcher use a custom matcher to decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is \"\".") .def("BatchEnforce", &casbin::Enforcer::BatchEnforce, "BatchEnforce enforce in batches") diff --git a/bindings/python/py_synced_enforcer.cpp b/bindings/python/py_synced_enforcer.cpp new file mode 100644 index 00000000..610eff19 --- /dev/null +++ b/bindings/python/py_synced_enforcer.cpp @@ -0,0 +1,119 @@ +/* +* Copyright 2021 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. +*/ + +#include +#include +#include +#include + +#include "py_casbin.h" + +namespace py = pybind11; + +void bindPySyncedEnforcer(py::module& m) { + py::class_(m, "SyncedEnforcer") + .def(py::init<>(), "Enforcer is the default constructor.") + .def(py::init(), R"doc( + Enforcer initializes an enforcer with a model file and a policy file. + @param model_path the path of the model file. + @param policy_file the path of the policy file. + )doc") + .def(py::init>(), R"doc( + Enforcer initializes an enforcer with a database adapter. + @param model_path the path of the model file. + @param adapter the adapter. + )doc") + .def(py::init, std::shared_ptr>(), R"doc( + Enforcer initializes an enforcer with a model and a database adapter. + @param m the model. + @param adapter the adapter. + )doc") + .def(py::init>(), R"doc( + Enforcer initializes an enforcer with a model. + @param m the model. + )doc") + .def(py::init(), R"doc( + Enforcer initializes an enforcer with a model file. + @param model_path the path of the model file. + )doc") + .def(py::init(), R"doc( + Enforcer initializes an enforcer with a model file, a policy file and an enable log flag. + @param model_path the path of the model file. + @param policy_file the path of the policy file. + @param enable_log whether to enable Casbin's log. + )doc") + + .def("StartAutoLoadPolicy", &casbin::SyncedEnforcer::StartAutoLoadPolicy, "StartAutoLoadPolicy starts a thread that will go through every specified duration call LoadPolicy") + .def("IsAutoLoadingRunning", &casbin::SyncedEnforcer::IsAutoLoadingRunning, "IsAutoLoadingRunning check if SyncedEnforcer is auto loading policies") + .def("StopAutoLoadPolicy", &casbin::SyncedEnforcer::StopAutoLoadPolicy, "StopAutoLoadPolicy causes the thread to exit") + .def("SetWatcher", &casbin::SyncedEnforcer::SetWatcher, "SetWatcher sets the current watcher.") + .def("LoadModel", &casbin::SyncedEnforcer::LoadModel, "LoadModel reloads the model from the model CONF file.") + .def("ClearPolicy", &casbin::SyncedEnforcer::ClearPolicy, "ClearPolicy clears all policy.") + .def("LoadPolicy", &casbin::SyncedEnforcer::LoadPolicy, "LoadPolicy reloads the policy from file/database.") + // .def("LoadFilteredPolicy", &casbin::SyncedEnforcer::LoadFilteredPolicy, "LoadFilteredPolicy reloads a filtered policy from file/database.") + .def("SavePolicy", &casbin::SyncedEnforcer::SavePolicy, "SavePolicy saves the current policy (usually after changed with Casbin API) back to file/database.") + .def("BuildRoleLinks", &casbin::SyncedEnforcer::BuildRoleLinks, "BuildRoleLinks manually rebuild the role inheritance relations.") + .def("Enforce", py::overload_cast(&casbin::SyncedEnforcer::Enforce), "Enforce with a vector param, decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (sub, obj, act).") + .def("Enforce", py::overload_cast(&casbin::SyncedEnforcer::Enforce), "Enforce with a map param, decides whether a \"subject\" can access a \"object\" with the operation \"action\", input parameters are usually: (sub, obj, act).") + .def("BatchEnforce", &casbin::SyncedEnforcer::BatchEnforce, "BatchEnforce enforce in batches") + .def("BatchEnforceWithMatcher", &casbin::SyncedEnforcer::BatchEnforceWithMatcher, "BatchEnforceWithMatcher enforce with matcher in batches") + + /* Management API member functions. */ + + .def("GetAllSubjects", &casbin::SyncedEnforcer::GetAllSubjects) + .def("GetAllNamedSubjects", &casbin::SyncedEnforcer::GetAllNamedSubjects) + .def("GetAllObjects", &casbin::SyncedEnforcer::GetAllObjects) + .def("GetAllNamedObjects", &casbin::SyncedEnforcer::GetAllNamedObjects) + .def("GetAllNamedActions", &casbin::SyncedEnforcer::GetAllNamedActions) + .def("GetAllRoles", &casbin::SyncedEnforcer::GetAllRoles) + .def("GetAllNamedRoles", &casbin::SyncedEnforcer::GetAllNamedRoles) + .def("GetPolicy", &casbin::SyncedEnforcer::GetPolicy) + .def("GetNamedPolicy", &casbin::SyncedEnforcer::GetNamedPolicy) + .def("GetFilteredNamedPolicy", &casbin::SyncedEnforcer::GetFilteredNamedPolicy) + .def("GetGroupingPolicy", &casbin::SyncedEnforcer::GetGroupingPolicy) + .def("GetFilteredGroupingPolicy", &casbin::SyncedEnforcer::GetFilteredGroupingPolicy) + .def("GetNamedGroupingPolicy", &casbin::SyncedEnforcer::GetNamedGroupingPolicy) + .def("GetFilteredNamedGroupingPolicy", &casbin::SyncedEnforcer::GetFilteredNamedGroupingPolicy) + + .def("HasPolicy", &casbin::SyncedEnforcer::HasPolicy) + .def("HasNamedPolicy", &casbin::SyncedEnforcer::HasNamedPolicy) + .def("AddPolicy", &casbin::SyncedEnforcer::AddPolicy) + .def("AddNamedPolicy", &casbin::SyncedEnforcer::AddNamedPolicy) + .def("AddNamedPolicies", &casbin::SyncedEnforcer::AddNamedPolicies) + .def("RemovePolicy", &casbin::SyncedEnforcer::RemovePolicy) + .def("RemovePolicies", &casbin::SyncedEnforcer::RemovePolicies) + .def("RemoveFilteredPolicy", &casbin::SyncedEnforcer::RemoveFilteredPolicy) + .def("RemoveNamedPolicies", &casbin::SyncedEnforcer::RemoveNamedPolicies) + .def("RemoveFilteredNamedPolicy", &casbin::SyncedEnforcer::RemoveFilteredNamedPolicy) + .def("HasNamedGroupingPolicy", &casbin::SyncedEnforcer::HasNamedGroupingPolicy) + .def("AddGroupingPolicy", &casbin::SyncedEnforcer::AddGroupingPolicy) + .def("AddGroupingPolicies", &casbin::SyncedEnforcer::AddGroupingPolicies) + .def("AddNamedGroupingPolicy", &casbin::SyncedEnforcer::AddNamedGroupingPolicy) + .def("AddNamedGroupingPolicies", &casbin::SyncedEnforcer::AddNamedGroupingPolicies) + .def("RemoveGroupingPolicy", &casbin::SyncedEnforcer::RemoveGroupingPolicy) + .def("RemoveGroupingPolicies", &casbin::SyncedEnforcer::RemoveGroupingPolicies) + .def("RemoveFilteredGroupingPolicy", &casbin::SyncedEnforcer::RemoveFilteredGroupingPolicy) + .def("RemoveNamedGroupingPolicy", &casbin::SyncedEnforcer::RemoveNamedGroupingPolicy) + .def("RemoveNamedGroupingPolicies", &casbin::SyncedEnforcer::RemoveNamedGroupingPolicies) + .def("RemoveFilteredNamedGroupingPolicy", &casbin::SyncedEnforcer::RemoveFilteredNamedGroupingPolicy) + .def("AddFunction", &casbin::SyncedEnforcer::AddFunction) + .def("UpdateGroupingPolicy", &casbin::SyncedEnforcer::UpdateGroupingPolicy) + .def("UpdateNamedGroupingPolicy", &casbin::SyncedEnforcer::UpdateNamedGroupingPolicy) + .def("UpdatePolicy", &casbin::SyncedEnforcer::UpdatePolicy) + .def("UpdateNamedPolicy", &casbin::SyncedEnforcer::UpdateNamedPolicy) + .def("UpdatePolicies", &casbin::SyncedEnforcer::UpdatePolicies) + .def("UpdateNamedPolicies", &casbin::SyncedEnforcer::UpdateNamedPolicies); +} diff --git a/casbin/enforcer_cached.cpp b/casbin/enforcer_cached.cpp index e20e8316..9c94fd7e 100644 --- a/casbin/enforcer_cached.cpp +++ b/casbin/enforcer_cached.cpp @@ -148,6 +148,10 @@ bool CachedEnforcer ::Enforce(Scope scope) { return EnforceWithMatcher("", scope); } +bool CachedEnforcer::Enforce(const DataVector& params) { + return EnforceWithMatcher("", params); +} + // Enforce with a vector param,decides whether a "subject" can access a "object" // with the operation "action", input parameters are usually: (sub, obj, act). bool CachedEnforcer::Enforce(const DataList& params) { @@ -167,6 +171,47 @@ bool CachedEnforcer ::EnforceWithMatcher(const std::string& matcher, Scope scope return Enforcer::EnforceWithMatcher(matcher, scope); } +// EnforceWithMatcher use a custom matcher to decides whether a "subject" can +// access a "object" with the operation "action", input parameters are usually: +// (matcher, sub, obj, act), use model matcher by default when matcher is "". +bool CachedEnforcer::EnforceWithMatcher(const std::string& matcher, const DataVector& params) { + if (!enableCache) { + return Enforcer::EnforceWithMatcher(matcher, params); + } + + std::string key; + for (const auto& r : params) { + if(const auto string_param = std::get_if(&r)) + key += *string_param; + else if(const auto abac_param = std::get_if>(&r)) { + auto data_ptr = *abac_param; + for(auto [_, attrib_value] : data_ptr->GetAttributes()) { + if(auto string_value = std::get_if(&attrib_value)) + key += *string_value + "$"; + else if(auto int_value = std::get_if(&attrib_value)) + key += std::to_string(*int_value) + "$"; + else if(auto double_value = std::get_if(&attrib_value)) + key += std::to_string(*double_value) + "$"; + else if(auto float_value = std::get_if(&attrib_value)) + key += std::to_string(*float_value) + "$"; + } + } + key += "$$"; + } + key += matcher; + key += "$"; + + std::pair res_ok = getCachedResult(key); + + if (res_ok.second) { + return res_ok.first; + } + + bool res = Enforcer::EnforceWithMatcher(matcher, params); + setCachedResult(key, res); + return res; +} + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are usually: // (matcher, sub, obj, act), use model matcher by default when matcher is "". diff --git a/casbin/enforcer_cached.h b/casbin/enforcer_cached.h index a6126080..cd83287d 100644 --- a/casbin/enforcer_cached.h +++ b/casbin/enforcer_cached.h @@ -85,23 +85,39 @@ class CachedEnforcer : public Enforcer { CachedEnforcer(const std::string& model_path, const std::string& policy_file, bool enable_log); bool Enforce(Scope scope); + + // Enforce with a vector param,decides whether a "subject" can access a + // "object" with the operation "action", input parameters are usually: (sub, + // obj, act). + bool Enforce(const DataVector& params); + // Enforce with a vector param,decides whether a "subject" can access a // "object" with the operation "action", input parameters are usually: (sub, // obj, act). bool Enforce(const DataList& params); + // Enforce with a map param,decides whether a "subject" can access a "object" // with the operation "action", input parameters are usually: (sub, obj, act). bool Enforce(const DataMap& params); + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are // usually: (matcher, sub, obj, act), use model matcher by default when // matcher is "". bool EnforceWithMatcher(const std::string& matcher, Scope scope); + + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can + // access a "object" with the operation "action", input parameters are + // usually: (matcher, sub, obj, act), use model matcher by default when + // matcher is "". + bool EnforceWithMatcher(const std::string& matcher, const DataVector& params); + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are // usually: (matcher, sub, obj, act), use model matcher by default when // matcher is "". bool EnforceWithMatcher(const std::string& matcher, const DataList& params); + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are // usually: (matcher, sub, obj, act), use model matcher by default when diff --git a/casbin/enforcer_synced.cpp b/casbin/enforcer_synced.cpp index 8bd899d6..c001be2f 100644 --- a/casbin/enforcer_synced.cpp +++ b/casbin/enforcer_synced.cpp @@ -116,7 +116,7 @@ void SyncedEnforcer ::StartAutoLoadPolicy(std::chrono::duration lock(policyMutex); + return Enforcer::Enforce(params); +} + // Enforce with a vector param,decides whether a "subject" can access a // "object" with the operation "action", input parameters are usually: (sub, // obj, act). @@ -208,7 +216,7 @@ std::vector SyncedEnforcer ::BatchEnforce(const std::initializer_list SyncedEnforcer ::BatchEnforceWithMatcher(const std::string& matcher, const std::initializer_list& requests) { +std::vector SyncedEnforcer::BatchEnforceWithMatcher(const std::string& matcher, const std::initializer_list& requests) { std::lock_guard lock(policyMutex); return Enforcer::BatchEnforceWithMatcher(matcher, requests); } diff --git a/casbin/enforcer_synced.h b/casbin/enforcer_synced.h index fed3b8d4..4c12e1fe 100644 --- a/casbin/enforcer_synced.h +++ b/casbin/enforcer_synced.h @@ -91,7 +91,7 @@ class SyncedEnforcer : public Enforcer { void StartAutoLoadPolicy(std::chrono::duration t); // IsAutoLoadingRunning check if SyncedEnforcer is auto loading policies - inline bool IsAutoLoadingRunning(); + bool IsAutoLoadingRunning(); // StopAutoLoadPolicy causes the thread to exit void StopAutoLoadPolicy(); @@ -128,6 +128,11 @@ class SyncedEnforcer : public Enforcer { // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). bool Enforce(Scope); + // Enforce with a vector param,decides whether a "subject" can access a + // "object" with the operation "action", input parameters are usually: (sub, + // obj, act). + bool Enforce(const DataVector& params); + // Enforce with a vector param,decides whether a "subject" can access a // "object" with the operation "action", input parameters are usually: (sub, // obj, act). diff --git a/include/casbin/casbin_enforcer.h b/include/casbin/casbin_enforcer.h index 66a41797..81925d8a 100644 --- a/include/casbin/casbin_enforcer.h +++ b/include/casbin/casbin_enforcer.h @@ -442,23 +442,39 @@ namespace casbin { CachedEnforcer(const std::string& model_path, const std::string& policy_file, bool enable_log); bool Enforce(Scope scope); + + // Enforce with a vector param,decides whether a "subject" can access a + // "object" with the operation "action", input parameters are usually: (sub, + // obj, act). + bool Enforce(const DataVector& params); + // Enforce with a vector param,decides whether a "subject" can access a // "object" with the operation "action", input parameters are usually: (sub, // obj, act). bool Enforce(const DataList& params); + // Enforce with a map param,decides whether a "subject" can access a "object" // with the operation "action", input parameters are usually: (sub, obj, act). bool Enforce(const DataMap& params); + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are // usually: (matcher, sub, obj, act), use model matcher by default when // matcher is "". bool EnforceWithMatcher(const std::string& matcher, Scope scope); + + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can + // access a "object" with the operation "action", input parameters are + // usually: (matcher, sub, obj, act), use model matcher by default when + // matcher is "". + bool EnforceWithMatcher(const std::string& matcher, const DataVector& params); + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are // usually: (matcher, sub, obj, act), use model matcher by default when // matcher is "". bool EnforceWithMatcher(const std::string& matcher, const DataList& params); + // EnforceWithMatcher use a custom matcher to decides whether a "subject" can // access a "object" with the operation "action", input parameters are // usually: (matcher, sub, obj, act), use model matcher by default when @@ -530,7 +546,7 @@ namespace casbin { void StartAutoLoadPolicy(std::chrono::duration t); // IsAutoLoadingRunning check if SyncedEnforcer is auto loading policies - inline bool IsAutoLoadingRunning(); + bool IsAutoLoadingRunning(); // StopAutoLoadPolicy causes the thread to exit void StopAutoLoadPolicy(); @@ -567,6 +583,11 @@ namespace casbin { // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). bool Enforce(Scope); + // Enforce with a vector param,decides whether a "subject" can access a + // "object" with the operation "action", input parameters are usually: (sub, + // obj, act). + bool Enforce(const DataVector& params); + // Enforce with a vector param,decides whether a "subject" can access a // "object" with the operation "action", input parameters are usually: (sub, // obj, act). diff --git a/tests/python/pycasbin_test_suite.py b/tests/python/pycasbin_test_suite.py index 04f340fb..e4dc2e0c 100644 --- a/tests/python/pycasbin_test_suite.py +++ b/tests/python/pycasbin_test_suite.py @@ -19,6 +19,8 @@ import test_enforcer import test_model import test_config +import test_cached_enforcer +import test_synced_enforcer def suite(): @@ -29,6 +31,8 @@ def suite(): suite.addTest(loader.loadTestsFromModule(test_enforcer)) suite.addTest(loader.loadTestsFromModule(test_model)) suite.addTest(loader.loadTestsFromModule(test_config)) + suite.addTest(loader.loadTestsFromModule(test_cached_enforcer)) + #suite.addTest(loader.loadTestsFromModule(test_synced_enforcer)) return suite diff --git a/tests/python/test_cached_enforcer.py b/tests/python/test_cached_enforcer.py new file mode 100644 index 00000000..ec0773df --- /dev/null +++ b/tests/python/test_cached_enforcer.py @@ -0,0 +1,50 @@ +# Copyright 2021 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. + +import pycasbin as casbin +from config_path import * +import unittest + +class TestCachedEnforcer(unittest.TestCase): + def setUp(self): + self.initCachedEnforcer(basic_model_path, basic_policy_path) + + def initCachedEnforcer(self, model, policy): + self.current_model = model + self.current_policy = policy + self.e = casbin.CachedEnforcer(self.current_model, self.current_policy) + + def test_Cache(self): + self.initCachedEnforcer(basic_model_path, basic_policy_path) + + self.assertEqual(self.e.Enforce(["alice", "data1", "read"]), True) + self.assertEqual(self.e.Enforce(["alice", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "write"]), False) + + # The cache is enabled, so even if we remove a policy rule, the decision + # for ("alice", "data1", "read") will still be true, as it uses the cached result. + self.e.RemovePolicy(["alice", "data1", "read"]) + self.assertEqual(self.e.Enforce(["alice", "data1", "read"]), True) + self.assertEqual(self.e.Enforce(["alice", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "write"]), False) + + # Now we invalidate the cache, then all first-coming Enforce() has to be evaluated in real-time. + # The decision for ("alice", "data1", "read") will be False now. + self.e.InvalidateCache() + self.assertEqual(self.e.Enforce(["alice", "data1", "read"]), False) + self.assertEqual(self.e.Enforce(["alice", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "write"]), False) \ No newline at end of file diff --git a/tests/python/test_synced_enforcer.py b/tests/python/test_synced_enforcer.py new file mode 100644 index 00000000..9cde1337 --- /dev/null +++ b/tests/python/test_synced_enforcer.py @@ -0,0 +1,63 @@ +# Copyright 2021 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. + +import pycasbin as casbin +from config_path import * +import unittest +from datetime import timedelta +import time + +class TestSyncedEnforcer(unittest.TestCase): + def setUp(self): + self.initSyncedEnforcer(basic_model_path, basic_policy_path) + + def initSyncedEnforcer(self, model, policy): + self.current_model = model + self.current_policy = policy + self.e = casbin.SyncedEnforcer(self.current_model, self.current_policy) + + def test_Sync(self): + self.initSyncedEnforcer(basic_model_path, basic_policy_path) + self.e.StartAutoLoadPolicy(timedelta(microseconds=200)) + self.assertEqual(self.e.Enforce(["alice", "data1", "read"]), True) + self.assertEqual(self.e.Enforce(["alice", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "write"]), False) + self.assertEqual(self.e.Enforce(["bob", "data1", "read"]), False) + self.assertEqual(self.e.Enforce(["bob", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["bob", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["bob", "data2", "write"]), True) + + time.sleep(2) + e.StopAutoLoadPolicy() + + def test_StopLoadPolicy(self): + self.initSyncedEnforcer(basic_model_path, basic_policy_path) + self.e.StartAutoLoadPolicy(timedelta(microseconds=5)) + + self.assertEqual(self.e.IsAutoLoadingRunning(), True) + + self.assertEqual(self.e.Enforce(["alice", "data1", "read"]), True) + self.assertEqual(self.e.Enforce(["alice", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["alice", "data2", "write"]), False) + self.assertEqual(self.e.Enforce(["bob", "data1", "read"]), False) + self.assertEqual(self.e.Enforce(["bob", "data1", "write"]), False) + self.assertEqual(self.e.Enforce(["bob", "data2", "read"]), False) + self.assertEqual(self.e.Enforce(["bob", "data2", "write"]), True) + + self.e.StopAutoLoadPolicy() + + time.sleep(1) + self.assertEqual(self.e.IsAutoLoadingRunning(), False)