Skip to content

Commit 88b9b8a

Browse files
authored
feat: implements delete policy (#8)
* finish main part of delete policy finish remove policy fix problem of remove policy * add remove_filtered_policy * remove useless line
1 parent 32e1413 commit 88b9b8a

4 files changed

Lines changed: 229 additions & 60 deletions

File tree

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ install:
99
- pip install -r requirements.txt
1010
- pip install coveralls
1111
script:
12-
- coverage run -m unittest discover -s tests -t tests
12+
- coverage run -m unittest discover --verbose --start-directory tests/ --pattern "test_*.py" --top-level-directory tests/
1313
after_success:
1414
- coveralls
1515
deploy:

casbin_pymongo_adapter/adapter.py

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import casbin
21
from casbin import persist
32
from pymongo import MongoClient
43

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

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

2725
return d
2826

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

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

4349
def load_policy(self, model):
44-
'''
45-
implementing add Interface for casbin \n
46-
load all policy rules from mongodb \n
47-
'''
50+
"""Implementing add Interface for casbin. Load all policy rules from mongodb
51+
52+
Args:
53+
model (CasbinRule): CasbinRule object
54+
"""
4855

4956
for line in self._collection.find():
5057
if 'ptype' not in line:
5158
continue
52-
5359
rule = CasbinRule(line['ptype'])
54-
if 'v0' in line:
55-
rule.v0 = line['v0']
56-
if 'v1' in line:
57-
rule.v1 = line['v1']
58-
if 'v2' in line:
59-
rule.v2 = line['v2']
60-
if 'v3' in line:
61-
rule.v3 = line['v3']
62-
if 'v4' in line:
63-
rule.v4 = line['v4']
64-
if 'v5' in line:
65-
rule.v5 = line['v5']
60+
for key, value in line.items():
61+
setattr(rule, key, value)
6662

6763
persist.load_policy_line(str(rule), model)
6864

6965
def _save_policy_line(self, ptype, rule):
7066
line = CasbinRule(ptype=ptype)
71-
if len(rule) > 0:
72-
line.v0 = rule[0]
73-
if len(rule) > 1:
74-
line.v1 = rule[1]
75-
if len(rule) > 2:
76-
line.v2 = rule[2]
77-
if len(rule) > 3:
78-
line.v3 = rule[3]
79-
if len(rule) > 4:
80-
line.v4 = rule[4]
81-
if len(rule) > 5:
82-
line.v5 = rule[5]
67+
for index, value in enumerate(rule):
68+
setattr(line, f'v{index}', value)
8369
self._collection.insert_one(line.dict())
84-
85-
def save_policy(self, model):
86-
'''
87-
implementing add Interface for casbin \n
88-
save the policy in mongodb \n
89-
'''
70+
71+
def _find_policy_lines(self, ptype, rule):
72+
line = CasbinRule(ptype=ptype)
73+
for index, value in enumerate(rule):
74+
setattr(line, f'v{index}', value)
75+
return self._collection.find(line.dict())
76+
77+
def _delete_policy_lines(self, ptype, rule):
78+
line = CasbinRule(ptype=ptype)
79+
for index, value in enumerate(rule):
80+
setattr(line, f'v{index}', value)
81+
82+
# if rule is empty, do nothing
83+
# else find all given rules and delete them
84+
if len(line.dict()) == 0:
85+
return 0
86+
else:
87+
line_dict = line.dict()
88+
line_dict_keys_len = len(line_dict)
89+
results = self._collection.find(line_dict)
90+
to_delete = [result['_id'] for result in results
91+
if line_dict_keys_len == len(result.keys()) - 1]
92+
results = self._collection.delete_many({'_id' : {'$in': to_delete}})
93+
return results.deleted_count
94+
95+
def save_policy(self, model) -> bool:
96+
"""Implement add Interface for casbin. Save the policy in mongodb
97+
98+
Args:
99+
model (Class Model): Casbin Model which loads from .conf file usually.
100+
101+
Returns:
102+
bool: True if succeed
103+
"""
90104
for sec in ["p", "g"]:
91105
if sec not in model.model.keys():
92106
continue
@@ -96,15 +110,51 @@ def save_policy(self, model):
96110
return True
97111

98112
def add_policy(self, sec, ptype, rule):
99-
"""add policy rules to mongodb"""
113+
"""Add policy rules to mongodb
114+
115+
Args:
116+
sec (str): Section name, 'g' or 'p'
117+
ptype (str): Policy type, 'g', 'g2', 'p', etc.
118+
rule (CasbinRule): Casbin rule will be added
119+
120+
Returns:
121+
bool: True if succeed else False
122+
"""
100123
self._save_policy_line(ptype, rule)
124+
return True
101125

102126
def remove_policy(self, sec, ptype, rule):
103-
"""delete policy rules from mongodb"""
104-
pass
127+
"""Remove policy rules in mongodb(rules duplicate are also removed)
128+
129+
Args:
130+
ptype (str): Policy type, 'g', 'g2', 'p', etc.
131+
rule (CasbinRule): Casbin rule if it is exactly same as will be removed.
132+
133+
Returns:
134+
Number: Number of policies be removed
135+
"""
136+
deleted_count = self._delete_policy_lines(ptype, rule)
137+
return deleted_count > 0
105138

106139
def remove_filtered_policy(self, sec, ptype, field_index, *field_values):
140+
"""Remove policy rules taht match the filter from the storage.
141+
This is part of the Auto-Save feature.
142+
143+
Args:
144+
ptype (str): Policy type, 'g', 'g2', 'p', etc.
145+
rule (CasbinRule): Casbin rule will be removed
146+
field_index (int): The policy index at which the filed_values begins filtering. Its range is [0, 5]
147+
field_values(List[str]): A list of rules to filter policy which starts from
148+
149+
Returns:
150+
bool: True if succeed else False
107151
"""
108-
delete policy rules for matching filters from mongodb
109-
"""
110-
pass
152+
if not (0 <= field_index <=5):
153+
return False
154+
if not (1 <= field_index + len(field_values) <= 6):
155+
return False
156+
query = {f'v{index + field_index}' : value
157+
for index, value in enumerate(field_values)}
158+
query['ptype'] = ptype
159+
results = self._collection.delete_many(query)
160+
return results.deleted_count > 0
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[request_definition]
2+
r = sub, obj, act
3+
4+
[policy_definition]
5+
p = sub, obj, act
6+
7+
[role_definition]
8+
g = _, _
9+
g2 = _, _
10+
11+
[policy_effect]
12+
e = some(where (p.eft == allow))
13+
14+
[matchers]
15+
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act

0 commit comments

Comments
 (0)