-
-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added distributed enforcer file along with respective unit tests
Signed-off-by: divyagar <divyagarg2601@gmail.com>
- Loading branch information
Showing
11 changed files
with
305 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from .enforcer import * | ||
from .synced_enforcer import SyncedEnforcer | ||
from .distributed_enforcer import DistributedEnforcer | ||
from . import util |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
from casbin import SyncedEnforcer | ||
import logging | ||
|
||
from casbin.persist import batch_adapter | ||
from casbin.model.policy_op import PolicyOp | ||
from casbin.persist.adapters import update_adapter | ||
|
||
|
||
class DistributedEnforcer(SyncedEnforcer): | ||
"""DistributedEnforcer wraps SyncedEnforcer for dispatcher.""" | ||
|
||
def __init__(self, model=None, adapter=None): | ||
self.logger = logging.getLogger() | ||
SyncedEnforcer.__init__(self, model, adapter) | ||
|
||
def add_policy_self(self, should_persist, sec, ptype, rules): | ||
""" | ||
AddPolicySelf provides a method for dispatcher to add authorization rules to the current policy. | ||
The function returns the rules affected and error. | ||
""" | ||
no_exists_policy = [] | ||
for rule in rules: | ||
if self.get_model().has_policy(sec, ptype, rule): | ||
no_exists_policy.append(rule) | ||
|
||
if should_persist: | ||
try: | ||
if isinstance(self.adapter, batch_adapter): | ||
self.adapter.add_policies(sec, ptype, rules) | ||
except Exception as e: | ||
self.logger.log("An error occurred: " + e) | ||
|
||
self.get_model().add_policies(sec, ptype, no_exists_policy) | ||
|
||
if sec == "g": | ||
try: | ||
self.build_incremental_role_links(PolicyOp.Policy_add, ptype, no_exists_policy) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
return no_exists_policy | ||
|
||
return rules | ||
|
||
def remove_policy_self(self, should_persist, sec, ptype, rules): | ||
""" | ||
remove_policy_self provides a method for dispatcher to remove policies from current policy. | ||
The function returns the rules affected and error. | ||
""" | ||
if(should_persist): | ||
try: | ||
if(isinstance(self.adapter, batch_adapter)): | ||
self.adapter.remove_policy(sec, ptype, rules) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
|
||
self.get_model().remove_policies(sec, ptype, rules) | ||
|
||
if sec == "g": | ||
try: | ||
self.build_incremental_role_links(PolicyOp.Policy_remove, ptype, rules) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
return rules | ||
|
||
return rules | ||
|
||
def remove_filtered_policy_self(self, should_persist, sec, ptype, field_index, *field_values): | ||
""" | ||
remove_filtered_policy_self provides a method for dispatcher to remove an authorization | ||
rule from the current policy,field filters can be specified. | ||
The function returns the rules affected and error. | ||
""" | ||
if should_persist: | ||
try: | ||
self.adapter.remove_filtered_policy(sec, ptype, field_index, field_values) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
|
||
effects = self.get_model().remove_filtered_policy_returns_effects(sec, ptype, field_index, field_values) | ||
|
||
if sec == "g": | ||
try: | ||
self.build_incremental_role_links(PolicyOp.Policy_remove, ptype, effects) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
return effects | ||
|
||
return effects | ||
|
||
def clear_policy_self(self, should_persist): | ||
""" | ||
clear_policy_self provides a method for dispatcher to clear all rules from the current policy. | ||
""" | ||
if should_persist: | ||
try: | ||
self.adapter.save_policy(None) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
|
||
self.get_model().clear_policy() | ||
|
||
def update_policy_self(self, should_persist, sec, ptype, old_rule, new_rule): | ||
""" | ||
update_policy_self provides a method for dispatcher to update an authorization rule from the current policy. | ||
""" | ||
if should_persist: | ||
try: | ||
if isinstance(self.adapter, update_adapter): | ||
self.adapter.update_policy(sec, ptype, old_rule, new_rule) | ||
except Exception as e: | ||
self.logger.log("An exception occurred: " + e) | ||
return False | ||
|
||
rule_updated = self.get_model().update_policy(sec, ptype, old_rule, new_rule) | ||
|
||
if not rule_updated: | ||
return False | ||
|
||
rules = [] | ||
if sec == "g": | ||
try: | ||
rules.append(old_rule) | ||
self.build_incremental_role_links(PolicyOp.Policy_remove, ptype, rules) | ||
except Exception as e: | ||
return False | ||
|
||
try: | ||
rules.append(new_rule) | ||
self.build_incremental_role_links(PolicyOp.Policy_add, ptype, rules) | ||
except Exception as e: | ||
return False | ||
|
||
|
||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ | |
from casbin import util, config | ||
from .policy import Policy | ||
|
||
|
||
class Model(Policy): | ||
|
||
section_name_map = { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import enum | ||
|
||
class PolicyOp(enum.Enum): | ||
Policy_add = 1 | ||
Policy_remove = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class UpdateAdapter: | ||
""" UpdateAdapter is the interface for Casbin adapters with add update policy function. """ | ||
|
||
def update_policy(self, sec, ptype, old_rule, new_policy): | ||
""" | ||
update_policy updates a policy rule from storage. | ||
This is part of the Auto-Save feature. | ||
""" | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import casbin | ||
from tests.test_enforcer import get_examples, TestCaseBase | ||
|
||
|
||
class TestDistributedApi(TestCaseBase): | ||
|
||
def get_enforcer(self, model=None, adapter=None): | ||
return casbin.DistributedEnforcer( | ||
model, | ||
adapter, | ||
) | ||
|
||
def test(self): | ||
e = self.get_enforcer( | ||
get_examples("rbac_model.conf"), | ||
get_examples("rbac_policy.csv") | ||
) | ||
|
||
e.add_policy_self(False, "p", "p", [ | ||
["alice", "data1", "read"], | ||
["bob", "data2", "write"], | ||
["data2_admin", "data2", "read"], | ||
["data2_admin", "data2", "write"] | ||
]) | ||
e.add_policy_self(False, "g", "g", [["alice", "data2_admin"]]) | ||
|
||
self.assertTrue(e.enforce("alice", "data1", "read")) | ||
self.assertFalse(e.enforce("alice", "data1", "write")) | ||
self.assertTrue(e.enforce("bob", "data2", "write")) | ||
self.assertFalse(e.enforce("bob", "data2", "read")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "read")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "write")) | ||
self.assertTrue(e.enforce("alice", "data2", "read")) | ||
self.assertTrue(e.enforce("alice", "data2", "write")) | ||
|
||
e.update_policy_self(False, "p", "p", ["alice", "data1", "read"],["alice", "data1", "write"]) | ||
e.update_policy_self(False, "g", "g", ["alice", "data2_admin"], ["tom", "alice"]) | ||
|
||
self.assertFalse(e.enforce("alice", "data1", "read")) | ||
self.assertTrue(e.enforce("alice", "data1", "write")) | ||
self.assertFalse(e.enforce("bob", "data2", "read")) | ||
self.assertTrue(e.enforce("bob", "data2", "write")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "read")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "write")) | ||
self.assertFalse(e.enforce("tom", "data1", "read")) | ||
self.assertTrue(e.enforce("tom", "data1", "write")) | ||
|
||
e.remove_policy_self(False, "p", "p", [ | ||
["alice", "data1", "write"] | ||
]) | ||
e.remove_policy_self(False, "g", "g", [ | ||
["alice", "data2_admin"] | ||
]) | ||
|
||
self.assertFalse(e.enforce("alice", "data1", "read")) | ||
self.assertFalse(e.enforce("alice", "data1", "write")) | ||
self.assertFalse(e.enforce("bob", "data2", "read")) | ||
self.assertTrue(e.enforce("bob", "data2", "write")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "read")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "write")) | ||
self.assertFalse(e.enforce("alice", "data2", "read")) | ||
self.assertFalse(e.enforce("alice", "data2", "write")) | ||
|
||
e.remove_filtered_policy_self(False, "p", "p", 0, "bob", "data2", "write") | ||
e.remove_filtered_policy_self(False, "g", "g", 0, "tom", "data2_admin") | ||
|
||
self.assertFalse(e.enforce("alice", "data1", "read")) | ||
self.assertFalse(e.enforce("alice", "data1", "write")) | ||
self.assertFalse(e.enforce("bob", "data2", "read")) | ||
self.assertFalse(e.enforce("bob", "data2", "write")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "read")) | ||
self.assertTrue(e.enforce("data2_admin", "data2", "write")) | ||
self.assertFalse(e.enforce("tom", "data1", "read")) | ||
self.assertFalse(e.enforce("tom", "data1", "write")) | ||
|
||
e.clear_policy_self(False) | ||
self.assertFalse(e.enforce("alice", "data1", "read")) | ||
self.assertFalse(e.enforce("alice", "data1", "write")) | ||
self.assertFalse(e.enforce("bob", "data2", "read")) | ||
self.assertFalse(e.enforce("bob", "data2", "write")) | ||
self.assertFalse(e.enforce("data2_admin", "data2", "read")) | ||
self.assertFalse(e.enforce("data2_admin", "data2", "write")) | ||
|
||
|
||
class TestDistributedApiSynced(TestDistributedApi): | ||
|
||
def get_enforcer(self, model=None, adapter=None): | ||
return casbin.DistributedEnforcer( | ||
model, | ||
adapter, | ||
) |