-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpermissions.py
126 lines (106 loc) · 3.56 KB
/
permissions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import enum
from typing import Optional
from security.authzed_resource import AuthzedResource, AuthzedResourceType
from security.policy import Policy, RoleBasedPolicy
from resources import Resource
class AuthzedAction(enum.Enum):
"""
To identify the type of action, according to the familiar CRUD terminology.
"""
ALL = "all"
READ = "read"
EDIT = "edit" # Create-Update-Delete
class DecisionStrategy(enum.Enum):
"""
The strategy to be adopted in case of multiple policies are defined.
"""
UNANIMOUS = "unanimous"
AFFIRMATIVE = "affirmative"
CONSENSUS = "consensus"
class Permission:
"""
The Permission class defines the authorization policies to be validated whenever the identified actions are
requested on the matching resources.
"""
def __init__(
self,
name: str,
resources: list[AuthzedResource] = [AuthzedResource(AuthzedResourceType.ALL)],
actions: Optional[list[AuthzedAction]] = [AuthzedAction.ALL],
policies: Optional[list[Policy]] = [], # Equivalent to allow-all
decision_strategy: Optional[DecisionStrategy] = DecisionStrategy.UNANIMOUS,
):
self._name = name
self._resources = resources
self._actions = actions
self._policies = policies
self._decision_strategy = decision_strategy
@property
def name(self):
return self._name
@property
def resources(self):
return self._resources
@property
def actions(self):
return self._actions
@property
def policies(self):
return self._policies
@property
def decision_strategy(self):
return self._decision_strategy
@classmethod
def with_permission_to_read(
cls,
name: str,
roles: list[str],
name_patterns: Optional[list[str]] = [],
required_tags: Optional[dict[str, str]] = {},
decision_strategy: Optional[DecisionStrategy] = DecisionStrategy.AFFIRMATIVE,
):
return cls(
name=name,
resources=[
AuthzedResource(
type=AuthzedResourceType.ALL,
name_patterns=name_patterns,
required_tags=required_tags,
)
],
actions=[AuthzedAction.READ],
policies=[RoleBasedPolicy(roles)],
decision_strategy=decision_strategy,
)
@classmethod
def with_permission_to_write(
cls,
name: str,
roles: list[str],
name_patterns: Optional[list[str]] = [],
required_tags: Optional[dict[str, str]] = {},
decision_strategy: Optional[DecisionStrategy] = DecisionStrategy.AFFIRMATIVE,
):
return cls(
name=name,
resources=[
AuthzedResource(
type=AuthzedResourceType.ALL,
name_patterns=name_patterns,
required_tags=required_tags,
)
],
actions=[AuthzedAction.EDIT],
policies=[RoleBasedPolicy(roles)],
decision_strategy=decision_strategy,
)
def match_resource(self, resource: Resource) -> bool:
for r in self._resources:
if r.type == AuthzedResourceType.ALL or resource.get_type() == r.type:
# TODO name and tags match
return True
return False
def match_actions(self, actions: list[AuthzedAction]):
if AuthzedAction.ALL in self._actions:
return True
return all(a in actions for a in self._actions)