elody 0.0.63__py3-none-any.whl → 0.0.162__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- elody/client.py +70 -23
- elody/csv.py +118 -21
- elody/error_codes.py +112 -0
- elody/exceptions.py +14 -0
- elody/job.py +95 -0
- elody/loader.py +33 -5
- elody/migration/__init__.py +0 -0
- elody/migration/base_object_migrator.py +18 -0
- elody/object_configurations/__init__.py +0 -0
- elody/object_configurations/base_object_configuration.py +174 -0
- elody/object_configurations/elody_configuration.py +144 -0
- elody/object_configurations/job_configuration.py +65 -0
- elody/policies/authentication/base_user_tenant_validation_policy.py +48 -15
- elody/policies/authorization/filter_generic_objects_policy.py +68 -22
- elody/policies/authorization/filter_generic_objects_policy_v2.py +166 -0
- elody/policies/authorization/generic_object_detail_policy.py +10 -27
- elody/policies/authorization/generic_object_mediafiles_policy.py +82 -0
- elody/policies/authorization/generic_object_metadata_policy.py +8 -27
- elody/policies/authorization/generic_object_relations_policy.py +12 -29
- elody/policies/authorization/generic_object_request_policy.py +56 -55
- elody/policies/authorization/generic_object_request_policy_v2.py +133 -0
- elody/policies/authorization/mediafile_derivatives_policy.py +92 -0
- elody/policies/authorization/mediafile_download_policy.py +71 -0
- elody/policies/authorization/multi_tenant_policy.py +14 -6
- elody/policies/authorization/tenant_request_policy.py +3 -1
- elody/policies/helpers.py +37 -0
- elody/policies/permission_handler.py +217 -199
- elody/policies/tenant_id_resolver.py +375 -0
- elody/schemas.py +0 -3
- elody/util.py +165 -11
- {elody-0.0.63.dist-info → elody-0.0.162.dist-info}/METADATA +16 -11
- elody-0.0.162.dist-info/RECORD +47 -0
- {elody-0.0.63.dist-info → elody-0.0.162.dist-info}/WHEEL +1 -1
- {elody-0.0.63.dist-info → elody-0.0.162.dist-info}/top_level.txt +1 -0
- tests/__init_.py +0 -0
- tests/data.py +74 -0
- tests/unit/__init__.py +0 -0
- tests/unit/test_csv.py +410 -0
- tests/unit/test_utils.py +293 -0
- elody-0.0.63.dist-info/RECORD +0 -27
- {elody-0.0.63.dist-info → elody-0.0.162.dist-info}/LICENSE +0 -0
|
@@ -3,7 +3,7 @@ import re as regex
|
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from elody.policies.permission_handler import (
|
|
5
5
|
get_permissions,
|
|
6
|
-
|
|
6
|
+
mask_protected_content_post_request_hook,
|
|
7
7
|
)
|
|
8
8
|
from flask import Request # pyright: ignore
|
|
9
9
|
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
@@ -20,9 +20,7 @@ class FilterGenericObjectsPolicy(BaseAuthorizationPolicy):
|
|
|
20
20
|
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
21
21
|
):
|
|
22
22
|
request: Request = request_context.http_request
|
|
23
|
-
if not
|
|
24
|
-
"^/[^/]+/filter$", request.path
|
|
25
|
-
):
|
|
23
|
+
if not regex.match("^(/[^/]+/v[0-9]+)?/[^/]+/filter$", request.path):
|
|
26
24
|
return policy_context
|
|
27
25
|
|
|
28
26
|
if not isinstance(user_context.access_restrictions.filters, list):
|
|
@@ -32,6 +30,7 @@ class FilterGenericObjectsPolicy(BaseAuthorizationPolicy):
|
|
|
32
30
|
policy_context.access_verdict = True
|
|
33
31
|
return policy_context
|
|
34
32
|
|
|
33
|
+
policy_context.access_verdict = False
|
|
35
34
|
for role in user_context.x_tenant.roles:
|
|
36
35
|
permissions = get_permissions(role, user_context)
|
|
37
36
|
if not permissions:
|
|
@@ -46,7 +45,7 @@ class FilterGenericObjectsPolicy(BaseAuthorizationPolicy):
|
|
|
46
45
|
if access_verdict != None:
|
|
47
46
|
policy_context.access_verdict = access_verdict
|
|
48
47
|
if not policy_context.access_verdict:
|
|
49
|
-
|
|
48
|
+
break
|
|
50
49
|
|
|
51
50
|
if policy_context.access_verdict:
|
|
52
51
|
return policy_context
|
|
@@ -60,7 +59,7 @@ class FilterGenericObjectsPolicy(BaseAuthorizationPolicy):
|
|
|
60
59
|
type_filter = filter
|
|
61
60
|
elif (
|
|
62
61
|
filter["type"] == "selection"
|
|
63
|
-
and filter
|
|
62
|
+
and filter.get("parent_key", "") == ""
|
|
64
63
|
and filter["key"] == "type"
|
|
65
64
|
):
|
|
66
65
|
type_filter = filter
|
|
@@ -69,12 +68,26 @@ class FilterGenericObjectsPolicy(BaseAuthorizationPolicy):
|
|
|
69
68
|
user_context.access_restrictions.filters.append( # pyright: ignore
|
|
70
69
|
{
|
|
71
70
|
"type": "selection",
|
|
72
|
-
"
|
|
73
|
-
|
|
71
|
+
"key": "type",
|
|
72
|
+
# TODO refactor this in a more generic way
|
|
74
73
|
"value": [
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
"language",
|
|
75
|
+
"type",
|
|
76
|
+
"collectionForm",
|
|
77
|
+
"institution",
|
|
78
|
+
"tag",
|
|
79
|
+
"triple",
|
|
80
|
+
"person",
|
|
81
|
+
"externalRecord",
|
|
82
|
+
"verzameling",
|
|
83
|
+
"arches_record",
|
|
84
|
+
"photographer",
|
|
85
|
+
"creator",
|
|
86
|
+
"assetPart",
|
|
87
|
+
"set",
|
|
88
|
+
"license",
|
|
89
|
+
"mediafile",
|
|
90
|
+
"share_link",
|
|
78
91
|
],
|
|
79
92
|
"match_exact": True,
|
|
80
93
|
}
|
|
@@ -103,24 +116,57 @@ class PostRequestRules:
|
|
|
103
116
|
type_filter_values.remove(type_filter_value)
|
|
104
117
|
continue
|
|
105
118
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
for
|
|
119
|
+
restrictions_grouped_by_index = {}
|
|
120
|
+
schemas = permissions["read"][type_filter_value]
|
|
121
|
+
for schema in schemas.keys():
|
|
122
|
+
restrictions = schemas[schema].get("object_restrictions", {})
|
|
123
|
+
for restricted_key, restricting_value in restrictions.items():
|
|
124
|
+
index, restricted_key = restricted_key.split(":")
|
|
125
|
+
prefix = ""
|
|
126
|
+
if restricted_key[0] == "!":
|
|
127
|
+
restricted_key = restricted_key[1:]
|
|
128
|
+
prefix += "!"
|
|
129
|
+
if restricted_key[0] == "?":
|
|
130
|
+
restricted_key = restricted_key[1:]
|
|
131
|
+
prefix += "?"
|
|
132
|
+
key = f"{schema}|{restricted_key}"
|
|
133
|
+
|
|
134
|
+
if group := restrictions_grouped_by_index.get(index):
|
|
135
|
+
group["key"].append(key)
|
|
136
|
+
else:
|
|
137
|
+
restrictions_grouped_by_index.update(
|
|
138
|
+
{
|
|
139
|
+
index: {
|
|
140
|
+
"key": [key],
|
|
141
|
+
"value": restricting_value,
|
|
142
|
+
"prefix": prefix,
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
for restriction in restrictions_grouped_by_index.values():
|
|
148
|
+
user_context.access_restrictions.filters.append( # pyright: ignore
|
|
149
|
+
{
|
|
150
|
+
"type": "selection",
|
|
151
|
+
"key": restriction["key"],
|
|
152
|
+
"value": restriction["value"],
|
|
153
|
+
"match_exact": True,
|
|
154
|
+
"operator": "or" if restriction["prefix"] == "?" else "and",
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
if restriction["prefix"] == "?":
|
|
111
158
|
user_context.access_restrictions.filters.append( # pyright: ignore
|
|
112
159
|
{
|
|
113
|
-
"type": "
|
|
114
|
-
"parent_key": parent_key if parent_key != "root" else "",
|
|
160
|
+
"type": "text",
|
|
115
161
|
"key": restriction["key"],
|
|
116
|
-
"value":
|
|
117
|
-
"
|
|
162
|
+
"value": "",
|
|
163
|
+
"operator": "or",
|
|
118
164
|
}
|
|
119
165
|
)
|
|
120
166
|
|
|
121
167
|
if len(type_filter_values) == 0:
|
|
122
|
-
return
|
|
168
|
+
return False
|
|
123
169
|
user_context.access_restrictions.post_request_hook = (
|
|
124
|
-
|
|
170
|
+
mask_protected_content_post_request_hook(user_context, permissions)
|
|
125
171
|
)
|
|
126
172
|
return True
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import re as regex
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from elody.policies.permission_handler import (
|
|
5
|
+
get_permissions,
|
|
6
|
+
mask_protected_content_post_request_hook,
|
|
7
|
+
)
|
|
8
|
+
from flask import Request # pyright: ignore
|
|
9
|
+
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
10
|
+
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
11
|
+
PolicyContext,
|
|
12
|
+
)
|
|
13
|
+
from inuits_policy_based_auth.contexts.user_context import ( # pyright: ignore
|
|
14
|
+
UserContext,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FilterGenericObjectsPolicyV2(BaseAuthorizationPolicy):
|
|
19
|
+
def authorize(
|
|
20
|
+
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
21
|
+
):
|
|
22
|
+
request: Request = request_context.http_request
|
|
23
|
+
if not regex.match("^(/[^/]+/v[0-9]+)?/[^/]+/filter$", request.path):
|
|
24
|
+
return policy_context
|
|
25
|
+
|
|
26
|
+
if not isinstance(user_context.access_restrictions.filters, list):
|
|
27
|
+
user_context.access_restrictions.filters = []
|
|
28
|
+
type_filter, filters = self.__split_type_filter(
|
|
29
|
+
user_context, deepcopy(request.json or [])
|
|
30
|
+
)
|
|
31
|
+
if not type_filter:
|
|
32
|
+
policy_context.access_verdict = True
|
|
33
|
+
return policy_context
|
|
34
|
+
|
|
35
|
+
policy_context.access_verdict = False
|
|
36
|
+
for role in user_context.x_tenant.roles:
|
|
37
|
+
permissions = get_permissions(role, user_context)
|
|
38
|
+
if not permissions:
|
|
39
|
+
continue
|
|
40
|
+
|
|
41
|
+
rules = [PostRequestRules]
|
|
42
|
+
access_verdict = None
|
|
43
|
+
for rule in rules:
|
|
44
|
+
access_verdict = rule().apply(
|
|
45
|
+
type_filter["value"], filters, user_context, request, permissions
|
|
46
|
+
)
|
|
47
|
+
if access_verdict != None:
|
|
48
|
+
policy_context.access_verdict = access_verdict
|
|
49
|
+
if not policy_context.access_verdict:
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
if policy_context.access_verdict:
|
|
53
|
+
return policy_context
|
|
54
|
+
|
|
55
|
+
return policy_context
|
|
56
|
+
|
|
57
|
+
def __split_type_filter(self, user_context: UserContext, request_body: list):
|
|
58
|
+
type_filter = None
|
|
59
|
+
for filter in request_body:
|
|
60
|
+
if filter["type"] == "type":
|
|
61
|
+
type_filter = filter
|
|
62
|
+
elif filter["type"] == "selection" and filter["key"] == "type":
|
|
63
|
+
type_filter = filter
|
|
64
|
+
elif item_types := filter.get("item_types"):
|
|
65
|
+
type_filter = {
|
|
66
|
+
"type": "selection",
|
|
67
|
+
"key": "type",
|
|
68
|
+
"value": item_types,
|
|
69
|
+
"match_exact": True,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if not type_filter:
|
|
73
|
+
if tenant_relation_type := user_context.bag.get("tenant_relation_type"):
|
|
74
|
+
user_context.access_restrictions.filters.append( # pyright: ignore
|
|
75
|
+
{
|
|
76
|
+
"type": "selection",
|
|
77
|
+
"key": tenant_relation_type,
|
|
78
|
+
"value": [
|
|
79
|
+
user_context.bag.get(
|
|
80
|
+
"tenant_defining_entity_id", user_context.x_tenant.id
|
|
81
|
+
)
|
|
82
|
+
],
|
|
83
|
+
"match_exact": True,
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
return None, request_body
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
request_body.remove(type_filter)
|
|
90
|
+
except ValueError:
|
|
91
|
+
pass
|
|
92
|
+
return type_filter, request_body
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class PostRequestRules:
|
|
96
|
+
def apply(
|
|
97
|
+
self,
|
|
98
|
+
type_filter_values: str | list[str],
|
|
99
|
+
filters: list[dict],
|
|
100
|
+
user_context: UserContext,
|
|
101
|
+
request: Request,
|
|
102
|
+
permissions,
|
|
103
|
+
) -> bool | None:
|
|
104
|
+
if request.method != "POST":
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
if isinstance(type_filter_values, str):
|
|
108
|
+
type_filter_values = [type_filter_values]
|
|
109
|
+
|
|
110
|
+
type_filter_values_copy = deepcopy(type_filter_values)
|
|
111
|
+
for type_filter_value in type_filter_values_copy:
|
|
112
|
+
if type_filter_value not in permissions["read"].keys():
|
|
113
|
+
type_filter_values.remove(type_filter_value)
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
restrictions_grouped_by_index = {}
|
|
117
|
+
schemas = permissions["read"][type_filter_value]
|
|
118
|
+
for schema in schemas.keys():
|
|
119
|
+
restrictions = schemas[schema].get("object_restrictions", {})
|
|
120
|
+
for restricted_key, restricting_value in restrictions.items():
|
|
121
|
+
index, restricted_key = restricted_key.split(":")
|
|
122
|
+
key = f"{schema}|{restricted_key}"
|
|
123
|
+
if group := restrictions_grouped_by_index.get(index):
|
|
124
|
+
group["key"].append(key)
|
|
125
|
+
else:
|
|
126
|
+
restrictions_grouped_by_index.update(
|
|
127
|
+
{
|
|
128
|
+
index: {
|
|
129
|
+
"key": [key],
|
|
130
|
+
"value": restricting_value,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# support false soft call read responses
|
|
136
|
+
for filter in filters:
|
|
137
|
+
key = filter.get("key", "")
|
|
138
|
+
if isinstance(key, list):
|
|
139
|
+
key = ",".join(key)
|
|
140
|
+
for restriction in restrictions_grouped_by_index.values():
|
|
141
|
+
if key not in ",".join(restriction["key"]):
|
|
142
|
+
continue
|
|
143
|
+
values = (
|
|
144
|
+
filter["value"]
|
|
145
|
+
if isinstance(filter["value"], list)
|
|
146
|
+
else [filter["value"]]
|
|
147
|
+
)
|
|
148
|
+
if not any(value in restriction["value"] for value in values):
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
for restriction in restrictions_grouped_by_index.values():
|
|
152
|
+
user_context.access_restrictions.filters.append( # pyright: ignore
|
|
153
|
+
{
|
|
154
|
+
"type": "selection",
|
|
155
|
+
"key": restriction["key"],
|
|
156
|
+
"value": restriction["value"],
|
|
157
|
+
"match_exact": True,
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if len(type_filter_values) == 0:
|
|
162
|
+
return False
|
|
163
|
+
user_context.access_restrictions.post_request_hook = (
|
|
164
|
+
mask_protected_content_post_request_hook(user_context, permissions)
|
|
165
|
+
)
|
|
166
|
+
return True
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import re as regex
|
|
2
2
|
|
|
3
|
+
from elody.policies.helpers import get_content, get_item
|
|
3
4
|
from elody.policies.permission_handler import (
|
|
4
|
-
get_mask_protected_content_post_request_hook,
|
|
5
5
|
get_permissions,
|
|
6
6
|
handle_single_item_request,
|
|
7
7
|
)
|
|
8
8
|
from flask import Request # pyright: ignore
|
|
9
|
-
from flask_restful import abort # pyright: ignore
|
|
10
9
|
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
11
10
|
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
12
11
|
PolicyContext,
|
|
@@ -22,27 +21,10 @@ class GenericObjectDetailPolicy(BaseAuthorizationPolicy):
|
|
|
22
21
|
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
23
22
|
):
|
|
24
23
|
request: Request = request_context.http_request
|
|
25
|
-
if not
|
|
26
|
-
"^/[^/]+/[^/]+$|^/ngsi-ld/v1/entities/[^/]+$", request.path
|
|
27
|
-
):
|
|
24
|
+
if not regex.match("^(/[^/]+/v[0-9]+)?/[^/]+/[^/]+$", request.path):
|
|
28
25
|
return policy_context
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
collection = "entities"
|
|
32
|
-
if not request.path.startswith("/ngsi-ld/v1/entities"):
|
|
33
|
-
collection = request.path.split("/")[1]
|
|
34
|
-
id = view_args.get("id")
|
|
35
|
-
item = (
|
|
36
|
-
StorageManager()
|
|
37
|
-
.get_db_engine()
|
|
38
|
-
.get_item_from_collection_by_id(view_args.get("collection", collection), id)
|
|
39
|
-
)
|
|
40
|
-
if not item:
|
|
41
|
-
abort(
|
|
42
|
-
404,
|
|
43
|
-
message=f"Item with id {id} doesn't exist in collection {collection}",
|
|
44
|
-
)
|
|
45
|
-
|
|
27
|
+
item = get_item(StorageManager(), user_context.bag, request.view_args)
|
|
46
28
|
for role in user_context.x_tenant.roles:
|
|
47
29
|
permissions = get_permissions(role, user_context)
|
|
48
30
|
if not permissions:
|
|
@@ -61,7 +43,7 @@ class GenericObjectDetailPolicy(BaseAuthorizationPolicy):
|
|
|
61
43
|
if access_verdict != None:
|
|
62
44
|
policy_context.access_verdict = access_verdict
|
|
63
45
|
if not policy_context.access_verdict:
|
|
64
|
-
|
|
46
|
+
break
|
|
65
47
|
|
|
66
48
|
if policy_context.access_verdict:
|
|
67
49
|
return policy_context
|
|
@@ -75,6 +57,7 @@ class PostRequestRules:
|
|
|
75
57
|
) -> bool | None:
|
|
76
58
|
if request.method != "POST":
|
|
77
59
|
return None
|
|
60
|
+
|
|
78
61
|
return handle_single_item_request(user_context, item, permissions, "create")
|
|
79
62
|
|
|
80
63
|
|
|
@@ -85,9 +68,6 @@ class GetRequestRules:
|
|
|
85
68
|
if request.method != "GET":
|
|
86
69
|
return None
|
|
87
70
|
|
|
88
|
-
user_context.access_restrictions.post_request_hook = (
|
|
89
|
-
get_mask_protected_content_post_request_hook(user_context, permissions)
|
|
90
|
-
)
|
|
91
71
|
return handle_single_item_request(user_context, item, permissions, "read")
|
|
92
72
|
|
|
93
73
|
|
|
@@ -98,8 +78,9 @@ class PutRequestRules:
|
|
|
98
78
|
if request.method != "PUT":
|
|
99
79
|
return None
|
|
100
80
|
|
|
81
|
+
content = get_content(item, request, request.json)
|
|
101
82
|
return handle_single_item_request(
|
|
102
|
-
user_context, item, permissions, "update",
|
|
83
|
+
user_context, item, permissions, "update", content
|
|
103
84
|
)
|
|
104
85
|
|
|
105
86
|
|
|
@@ -110,8 +91,9 @@ class PatchRequestRules:
|
|
|
110
91
|
if request.method != "PATCH":
|
|
111
92
|
return None
|
|
112
93
|
|
|
94
|
+
content = get_content(item, request, request.json)
|
|
113
95
|
return handle_single_item_request(
|
|
114
|
-
user_context, item, permissions, "update",
|
|
96
|
+
user_context, item, permissions, "update", content
|
|
115
97
|
)
|
|
116
98
|
|
|
117
99
|
|
|
@@ -121,4 +103,5 @@ class DeleteRequestRules:
|
|
|
121
103
|
) -> bool | None:
|
|
122
104
|
if request.method != "DELETE":
|
|
123
105
|
return None
|
|
106
|
+
|
|
124
107
|
return handle_single_item_request(user_context, item, permissions, "delete")
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import re as regex
|
|
2
|
+
|
|
3
|
+
from elody.error_codes import ErrorCode, get_error_code, get_read, get_write
|
|
4
|
+
from elody.policies.permission_handler import (
|
|
5
|
+
get_permissions,
|
|
6
|
+
handle_single_item_request,
|
|
7
|
+
)
|
|
8
|
+
from flask import Request # pyright: ignore
|
|
9
|
+
from flask_restful import abort # pyright: ignore
|
|
10
|
+
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
11
|
+
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
12
|
+
PolicyContext,
|
|
13
|
+
)
|
|
14
|
+
from inuits_policy_based_auth.contexts.user_context import ( # pyright: ignore
|
|
15
|
+
UserContext,
|
|
16
|
+
)
|
|
17
|
+
from storage.storagemanager import StorageManager # pyright: ignore
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GenericObjectMediafilesPolicy(BaseAuthorizationPolicy):
|
|
21
|
+
def authorize(
|
|
22
|
+
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
23
|
+
):
|
|
24
|
+
request: Request = request_context.http_request
|
|
25
|
+
if not regex.match("^(/[^/]+/v[0-9]+)?/[^/]+/[^/]+/mediafiles$", request.path):
|
|
26
|
+
return policy_context
|
|
27
|
+
|
|
28
|
+
view_args = request.view_args or {}
|
|
29
|
+
collection = view_args.get("collection", request.path.split("/")[-3])
|
|
30
|
+
id = view_args.get("id")
|
|
31
|
+
item = (
|
|
32
|
+
StorageManager()
|
|
33
|
+
.get_db_engine()
|
|
34
|
+
.get_item_from_collection_by_id(collection, id)
|
|
35
|
+
)
|
|
36
|
+
if not item:
|
|
37
|
+
abort(
|
|
38
|
+
404,
|
|
39
|
+
message=f"{get_error_code(ErrorCode.ITEM_NOT_FOUND_IN_COLLECTION, get_read())} | id:{id} | collection:{collection} - Item with id {id} doesn't exist in collection {collection}",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
for role in user_context.x_tenant.roles:
|
|
43
|
+
permissions = get_permissions(role, user_context)
|
|
44
|
+
if not permissions:
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
rules = [
|
|
48
|
+
PostRequestRules,
|
|
49
|
+
GetRequestRules,
|
|
50
|
+
]
|
|
51
|
+
access_verdict = None
|
|
52
|
+
for rule in rules:
|
|
53
|
+
access_verdict = rule().apply(item, user_context, request, permissions)
|
|
54
|
+
if access_verdict != None:
|
|
55
|
+
policy_context.access_verdict = access_verdict
|
|
56
|
+
if not policy_context.access_verdict:
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
if policy_context.access_verdict:
|
|
60
|
+
return policy_context
|
|
61
|
+
|
|
62
|
+
return policy_context
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class PostRequestRules:
|
|
66
|
+
def apply(
|
|
67
|
+
self, item, user_context: UserContext, request: Request, permissions
|
|
68
|
+
) -> bool | None:
|
|
69
|
+
if request.method != "POST":
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
return handle_single_item_request(user_context, item, permissions, "create")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class GetRequestRules:
|
|
76
|
+
def apply(
|
|
77
|
+
self, item, user_context: UserContext, request: Request, permissions
|
|
78
|
+
) -> bool | None:
|
|
79
|
+
if request.method != "GET":
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
return handle_single_item_request(user_context, item, permissions, "read")
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import re as regex
|
|
2
2
|
|
|
3
|
+
from elody.policies.helpers import get_content, get_item
|
|
3
4
|
from elody.policies.permission_handler import (
|
|
4
|
-
get_mask_protected_content_post_request_hook,
|
|
5
5
|
get_permissions,
|
|
6
6
|
handle_single_item_request,
|
|
7
7
|
)
|
|
8
8
|
from flask import Request # pyright: ignore
|
|
9
|
-
from flask_restful import abort # pyright: ignore
|
|
10
9
|
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
11
10
|
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
12
11
|
PolicyContext,
|
|
@@ -22,25 +21,10 @@ class GenericObjectMetadataPolicy(BaseAuthorizationPolicy):
|
|
|
22
21
|
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
23
22
|
):
|
|
24
23
|
request: Request = request_context.http_request
|
|
25
|
-
if not
|
|
26
|
-
"^/[^/]+/[^/]+/metadata$", request.path
|
|
27
|
-
):
|
|
24
|
+
if not regex.match("^(/elody/v[0-9]+)?/[^/]+/[^/]+/metadata$", request.path):
|
|
28
25
|
return policy_context
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
collection = view_args.get("collection", request.path.split("/")[1])
|
|
32
|
-
id = view_args.get("id")
|
|
33
|
-
item = (
|
|
34
|
-
StorageManager()
|
|
35
|
-
.get_db_engine()
|
|
36
|
-
.get_item_from_collection_by_id(collection, id)
|
|
37
|
-
)
|
|
38
|
-
if not item:
|
|
39
|
-
abort(
|
|
40
|
-
404,
|
|
41
|
-
message=f"Item with id {id} doesn't exist in collection {collection}",
|
|
42
|
-
)
|
|
43
|
-
|
|
27
|
+
item = get_item(StorageManager(), user_context.bag, request.view_args)
|
|
44
28
|
for role in user_context.x_tenant.roles:
|
|
45
29
|
permissions = get_permissions(role, user_context)
|
|
46
30
|
if not permissions:
|
|
@@ -53,7 +37,7 @@ class GenericObjectMetadataPolicy(BaseAuthorizationPolicy):
|
|
|
53
37
|
if access_verdict != None:
|
|
54
38
|
policy_context.access_verdict = access_verdict
|
|
55
39
|
if not policy_context.access_verdict:
|
|
56
|
-
|
|
40
|
+
break
|
|
57
41
|
|
|
58
42
|
if policy_context.access_verdict:
|
|
59
43
|
return policy_context
|
|
@@ -68,11 +52,6 @@ class GetRequestRules:
|
|
|
68
52
|
if request.method != "GET":
|
|
69
53
|
return None
|
|
70
54
|
|
|
71
|
-
user_context.access_restrictions.post_request_hook = (
|
|
72
|
-
get_mask_protected_content_post_request_hook(
|
|
73
|
-
user_context, permissions, item["type"]
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
55
|
return handle_single_item_request(user_context, item, permissions, "read")
|
|
77
56
|
|
|
78
57
|
|
|
@@ -83,8 +62,9 @@ class PutRequestRules:
|
|
|
83
62
|
if request.method != "PUT":
|
|
84
63
|
return None
|
|
85
64
|
|
|
65
|
+
content = get_content(item, request, {"metadata": request.json})
|
|
86
66
|
return handle_single_item_request(
|
|
87
|
-
user_context, item, permissions, "update",
|
|
67
|
+
user_context, item, permissions, "update", content
|
|
88
68
|
)
|
|
89
69
|
|
|
90
70
|
|
|
@@ -95,6 +75,7 @@ class PatchRequestRules:
|
|
|
95
75
|
if request.method != "PATCH":
|
|
96
76
|
return None
|
|
97
77
|
|
|
78
|
+
content = get_content(item, request, {"metadata": request.json})
|
|
98
79
|
return handle_single_item_request(
|
|
99
|
-
user_context, item, permissions, "update",
|
|
80
|
+
user_context, item, permissions, "update", content
|
|
100
81
|
)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import re as regex
|
|
2
2
|
|
|
3
|
+
from elody.policies.helpers import get_content, get_item
|
|
3
4
|
from elody.policies.permission_handler import (
|
|
4
|
-
get_mask_protected_content_post_request_hook,
|
|
5
5
|
get_permissions,
|
|
6
6
|
handle_single_item_request,
|
|
7
7
|
)
|
|
8
8
|
from flask import Request # pyright: ignore
|
|
9
|
-
from flask_restful import abort # pyright: ignore
|
|
10
9
|
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
11
10
|
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
12
11
|
PolicyContext,
|
|
@@ -22,25 +21,10 @@ class GenericObjectRelationsPolicy(BaseAuthorizationPolicy):
|
|
|
22
21
|
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
23
22
|
):
|
|
24
23
|
request: Request = request_context.http_request
|
|
25
|
-
if not
|
|
26
|
-
"^/[^/]+/[^/]+/relations$", request.path
|
|
27
|
-
):
|
|
24
|
+
if not regex.match("^(/elody/v[0-9]+)?/[^/]+/[^/]+/relations$", request.path):
|
|
28
25
|
return policy_context
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
collection = view_args.get("collection", request.path.split("/")[1])
|
|
32
|
-
id = view_args.get("id")
|
|
33
|
-
item = (
|
|
34
|
-
StorageManager()
|
|
35
|
-
.get_db_engine()
|
|
36
|
-
.get_item_from_collection_by_id(collection, id)
|
|
37
|
-
)
|
|
38
|
-
if not item:
|
|
39
|
-
abort(
|
|
40
|
-
404,
|
|
41
|
-
message=f"Item with id {id} doesn't exist in collection {collection}",
|
|
42
|
-
)
|
|
43
|
-
|
|
27
|
+
item = get_item(StorageManager(), user_context.bag, request.view_args)
|
|
44
28
|
for role in user_context.x_tenant.roles:
|
|
45
29
|
permissions = get_permissions(role, user_context)
|
|
46
30
|
if not permissions:
|
|
@@ -59,7 +43,7 @@ class GenericObjectRelationsPolicy(BaseAuthorizationPolicy):
|
|
|
59
43
|
if access_verdict != None:
|
|
60
44
|
policy_context.access_verdict = access_verdict
|
|
61
45
|
if not policy_context.access_verdict:
|
|
62
|
-
|
|
46
|
+
break
|
|
63
47
|
|
|
64
48
|
if policy_context.access_verdict:
|
|
65
49
|
return policy_context
|
|
@@ -74,8 +58,9 @@ class PostRequestRules:
|
|
|
74
58
|
if request.method != "POST":
|
|
75
59
|
return None
|
|
76
60
|
|
|
61
|
+
content = get_content(item, request, {"relations": request.json})
|
|
77
62
|
return handle_single_item_request(
|
|
78
|
-
user_context, item, permissions, "create",
|
|
63
|
+
user_context, item, permissions, "create", content
|
|
79
64
|
)
|
|
80
65
|
|
|
81
66
|
|
|
@@ -86,11 +71,6 @@ class GetRequestRules:
|
|
|
86
71
|
if request.method != "GET":
|
|
87
72
|
return None
|
|
88
73
|
|
|
89
|
-
user_context.access_restrictions.post_request_hook = (
|
|
90
|
-
get_mask_protected_content_post_request_hook(
|
|
91
|
-
user_context, permissions, item["type"]
|
|
92
|
-
)
|
|
93
|
-
)
|
|
94
74
|
return handle_single_item_request(user_context, item, permissions, "read")
|
|
95
75
|
|
|
96
76
|
|
|
@@ -101,8 +81,9 @@ class PutRequestRules:
|
|
|
101
81
|
if request.method != "PUT":
|
|
102
82
|
return None
|
|
103
83
|
|
|
84
|
+
content = get_content(item, request, {"relations": request.json})
|
|
104
85
|
return handle_single_item_request(
|
|
105
|
-
user_context, item, permissions, "update",
|
|
86
|
+
user_context, item, permissions, "update", content
|
|
106
87
|
)
|
|
107
88
|
|
|
108
89
|
|
|
@@ -113,8 +94,9 @@ class PatchRequestRules:
|
|
|
113
94
|
if request.method != "PATCH":
|
|
114
95
|
return None
|
|
115
96
|
|
|
97
|
+
content = get_content(item, request, {"relations": request.json})
|
|
116
98
|
return handle_single_item_request(
|
|
117
|
-
user_context, item, permissions, "update",
|
|
99
|
+
user_context, item, permissions, "update", content
|
|
118
100
|
)
|
|
119
101
|
|
|
120
102
|
|
|
@@ -125,6 +107,7 @@ class DeleteRequestRules:
|
|
|
125
107
|
if request.method != "DELETE":
|
|
126
108
|
return None
|
|
127
109
|
|
|
110
|
+
content = get_content(item, request, {"relations": request.json})
|
|
128
111
|
return handle_single_item_request(
|
|
129
|
-
user_context, item, permissions, "delete",
|
|
112
|
+
user_context, item, permissions, "delete", content
|
|
130
113
|
)
|