Skip to content

Commit

Permalink
feat: implements delete policy (#8)
Browse files Browse the repository at this point in the history
* finish main part of delete policy

finish remove policy

fix problem of remove policy

* add remove_filtered_policy

* remove useless line
  • Loading branch information
AmosChenYQ authored Jun 15, 2021
1 parent 32e1413 commit 88b9b8a
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 60 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ install:
- pip install -r requirements.txt
- pip install coveralls
script:
- coverage run -m unittest discover -s tests -t tests
- coverage run -m unittest discover --verbose --start-directory tests/ --pattern "test_*.py" --top-level-directory tests/
after_success:
- coveralls
deploy:
Expand Down
142 changes: 96 additions & 46 deletions casbin_pymongo_adapter/adapter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import casbin
from casbin import persist
from pymongo import MongoClient

Expand All @@ -19,10 +18,9 @@ def __init__(self, ptype = None, v0 = None, v1 = None, v2 = None, v3 = None, v4
def dict(self):
d = {'ptype': self.ptype}

for i, v in enumerate([self.v0, self.v1, self.v2, self.v3, self.v4, self.v5]):
if v is None:
break
d['v' + str(i)] = v
for value in dir(self):
if getattr(self, value) is not None and value.startswith('v') and value[1:].isnumeric():
d[value] = getattr(self, value)

return d

Expand All @@ -36,57 +34,73 @@ class Adapter(persist.Adapter):
"""the interface for Casbin adapters."""

def __init__(self, uri, dbname, collection="casbin_rule"):
"""Create an adapter for Mongodb
Args:
uri (str): This should be the same requiement as pymongo Client's 'uri' parameter.
See https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.
dbname (str): Database to store policy.
collection (str, optional): Collection of the choosen database. Defaults to "casbin_rule".
"""
client = MongoClient(uri)
db = client[dbname]
self._collection = db[collection]

def load_policy(self, model):
'''
implementing add Interface for casbin \n
load all policy rules from mongodb \n
'''
"""Implementing add Interface for casbin. Load all policy rules from mongodb
Args:
model (CasbinRule): CasbinRule object
"""

for line in self._collection.find():
if 'ptype' not in line:
continue

rule = CasbinRule(line['ptype'])
if 'v0' in line:
rule.v0 = line['v0']
if 'v1' in line:
rule.v1 = line['v1']
if 'v2' in line:
rule.v2 = line['v2']
if 'v3' in line:
rule.v3 = line['v3']
if 'v4' in line:
rule.v4 = line['v4']
if 'v5' in line:
rule.v5 = line['v5']
for key, value in line.items():
setattr(rule, key, value)

persist.load_policy_line(str(rule), model)

def _save_policy_line(self, ptype, rule):
line = CasbinRule(ptype=ptype)
if len(rule) > 0:
line.v0 = rule[0]
if len(rule) > 1:
line.v1 = rule[1]
if len(rule) > 2:
line.v2 = rule[2]
if len(rule) > 3:
line.v3 = rule[3]
if len(rule) > 4:
line.v4 = rule[4]
if len(rule) > 5:
line.v5 = rule[5]
for index, value in enumerate(rule):
setattr(line, f'v{index}', value)
self._collection.insert_one(line.dict())

def save_policy(self, model):
'''
implementing add Interface for casbin \n
save the policy in mongodb \n
'''

def _find_policy_lines(self, ptype, rule):
line = CasbinRule(ptype=ptype)
for index, value in enumerate(rule):
setattr(line, f'v{index}', value)
return self._collection.find(line.dict())

def _delete_policy_lines(self, ptype, rule):
line = CasbinRule(ptype=ptype)
for index, value in enumerate(rule):
setattr(line, f'v{index}', value)

# if rule is empty, do nothing
# else find all given rules and delete them
if len(line.dict()) == 0:
return 0
else:
line_dict = line.dict()
line_dict_keys_len = len(line_dict)
results = self._collection.find(line_dict)
to_delete = [result['_id'] for result in results
if line_dict_keys_len == len(result.keys()) - 1]
results = self._collection.delete_many({'_id' : {'$in': to_delete}})
return results.deleted_count

def save_policy(self, model) -> bool:
"""Implement add Interface for casbin. Save the policy in mongodb
Args:
model (Class Model): Casbin Model which loads from .conf file usually.
Returns:
bool: True if succeed
"""
for sec in ["p", "g"]:
if sec not in model.model.keys():
continue
Expand All @@ -96,15 +110,51 @@ def save_policy(self, model):
return True

def add_policy(self, sec, ptype, rule):
"""add policy rules to mongodb"""
"""Add policy rules to mongodb
Args:
sec (str): Section name, 'g' or 'p'
ptype (str): Policy type, 'g', 'g2', 'p', etc.
rule (CasbinRule): Casbin rule will be added
Returns:
bool: True if succeed else False
"""
self._save_policy_line(ptype, rule)
return True

def remove_policy(self, sec, ptype, rule):
"""delete policy rules from mongodb"""
pass
"""Remove policy rules in mongodb(rules duplicate are also removed)
Args:
ptype (str): Policy type, 'g', 'g2', 'p', etc.
rule (CasbinRule): Casbin rule if it is exactly same as will be removed.
Returns:
Number: Number of policies be removed
"""
deleted_count = self._delete_policy_lines(ptype, rule)
return deleted_count > 0

def remove_filtered_policy(self, sec, ptype, field_index, *field_values):
"""Remove policy rules taht match the filter from the storage.
This is part of the Auto-Save feature.
Args:
ptype (str): Policy type, 'g', 'g2', 'p', etc.
rule (CasbinRule): Casbin rule will be removed
field_index (int): The policy index at which the filed_values begins filtering. Its range is [0, 5]
field_values(List[str]): A list of rules to filter policy which starts from
Returns:
bool: True if succeed else False
"""
delete policy rules for matching filters from mongodb
"""
pass
if not (0 <= field_index <=5):
return False
if not (1 <= field_index + len(field_values) <= 6):
return False
query = {f'v{index + field_index}' : value
for index, value in enumerate(field_values)}
query['ptype'] = ptype
results = self._collection.delete_many(query)
return results.deleted_count > 0
15 changes: 15 additions & 0 deletions tests/rbac_with_resources_roles.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _
g2 = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act
Loading

0 comments on commit 88b9b8a

Please sign in to comment.