elody 0.0.63__py3-none-any.whl → 0.0.163__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 +128 -33
- 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.163.dist-info}/METADATA +16 -11
- elody-0.0.163.dist-info/RECORD +47 -0
- {elody-0.0.63.dist-info → elody-0.0.163.dist-info}/WHEEL +1 -1
- {elody-0.0.63.dist-info → elody-0.0.163.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.163.dist-info}/LICENSE +0 -0
|
@@ -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
|
)
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import re as regex
|
|
2
2
|
|
|
3
|
+
from elody.policies.helpers import get_content
|
|
4
|
+
from configuration import get_object_configuration_mapper # pyright: ignore
|
|
3
5
|
from elody.policies.permission_handler import (
|
|
4
6
|
get_permissions,
|
|
5
|
-
|
|
7
|
+
handle_single_item_request,
|
|
8
|
+
mask_protected_content_post_request_hook,
|
|
6
9
|
)
|
|
7
|
-
from elody.util import
|
|
10
|
+
from elody.util import interpret_flat_key
|
|
8
11
|
from flask import Request # pyright: ignore
|
|
9
12
|
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
10
13
|
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
@@ -20,9 +23,7 @@ class GenericObjectRequestPolicy(BaseAuthorizationPolicy):
|
|
|
20
23
|
self, policy_context: PolicyContext, user_context: UserContext, request_context
|
|
21
24
|
):
|
|
22
25
|
request: Request = request_context.http_request
|
|
23
|
-
if not
|
|
24
|
-
"^/[^/]+$|^/ngsi-ld/v1/entities$", request.path
|
|
25
|
-
):
|
|
26
|
+
if not regex.match("^(/[^/]+/v[0-9]+)?/[^/]+$", request.path):
|
|
26
27
|
return policy_context
|
|
27
28
|
|
|
28
29
|
for role in user_context.x_tenant.roles:
|
|
@@ -37,7 +38,7 @@ class GenericObjectRequestPolicy(BaseAuthorizationPolicy):
|
|
|
37
38
|
if access_verdict != None:
|
|
38
39
|
policy_context.access_verdict = access_verdict
|
|
39
40
|
if not policy_context.access_verdict:
|
|
40
|
-
|
|
41
|
+
break
|
|
41
42
|
|
|
42
43
|
if policy_context.access_verdict:
|
|
43
44
|
return policy_context
|
|
@@ -46,25 +47,20 @@ class GenericObjectRequestPolicy(BaseAuthorizationPolicy):
|
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
class PostRequestRules:
|
|
49
|
-
def apply(
|
|
50
|
+
def apply(
|
|
51
|
+
self, user_context: UserContext, request: Request, permissions
|
|
52
|
+
) -> bool | None:
|
|
50
53
|
if request.method != "POST":
|
|
51
54
|
return None
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if
|
|
55
|
-
restrictions = permissions["create"][item["type"]].get("restrictions", {})
|
|
56
|
-
for metadata in restrictions.get("metadata", []):
|
|
57
|
-
value = get_item_metadata_value(item, metadata["key"])
|
|
58
|
-
if isinstance(value, str):
|
|
59
|
-
if value not in metadata["value"]:
|
|
60
|
-
return None
|
|
61
|
-
elif isinstance(value, list):
|
|
62
|
-
for expected_value in metadata["value"]:
|
|
63
|
-
if expected_value not in value:
|
|
64
|
-
return None
|
|
55
|
+
if request.args.get("dry_run", False):
|
|
56
|
+
return True
|
|
57
|
+
if regex.match(r"^/batch?$", request.path):
|
|
65
58
|
return True
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
content = get_content(request.json, request, request.json)
|
|
61
|
+
return handle_single_item_request(
|
|
62
|
+
user_context, request.json, permissions, "create", content
|
|
63
|
+
)
|
|
68
64
|
|
|
69
65
|
|
|
70
66
|
class GetRequestRules:
|
|
@@ -73,45 +69,27 @@ class GetRequestRules:
|
|
|
73
69
|
) -> bool | None:
|
|
74
70
|
if request.method != "GET":
|
|
75
71
|
return None
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
type_query_parameter = (
|
|
73
|
+
"mediafile"
|
|
74
|
+
if regex.match(r"^/mediafiles(?:\?(.*))?$", request.path)
|
|
75
|
+
else request.args.get("type")
|
|
76
|
+
)
|
|
78
77
|
allowed_item_types = list(permissions["read"].keys())
|
|
79
78
|
filters = []
|
|
80
79
|
|
|
81
80
|
if type_query_parameter:
|
|
82
81
|
if type_query_parameter in allowed_item_types:
|
|
82
|
+
config = get_object_configuration_mapper().get(type_query_parameter)
|
|
83
|
+
object_lists = config.document_info()["object_lists"]
|
|
84
|
+
|
|
83
85
|
restrictions = permissions["read"][type_query_parameter].get(
|
|
84
|
-
"
|
|
86
|
+
"object_restrictions", {}
|
|
85
87
|
)
|
|
86
|
-
for
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
{
|
|
92
|
-
"$elemMatch": {
|
|
93
|
-
"key": metadata["key"],
|
|
94
|
-
"value": {"$in": metadata["value"]},
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
filters.append({parent_key: {"$all": all_matches}})
|
|
99
|
-
elif parent_key == "relations":
|
|
100
|
-
for relation in restrictions[parent_key]:
|
|
101
|
-
all_matches.append(
|
|
102
|
-
{
|
|
103
|
-
"$elemMatch": {
|
|
104
|
-
"type": relation["key"],
|
|
105
|
-
"key": {"$in": relation["value"]},
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
)
|
|
109
|
-
filters.append({parent_key: {"$all": all_matches}})
|
|
110
|
-
elif parent_key == "root":
|
|
111
|
-
for restriction in restrictions[parent_key]:
|
|
112
|
-
filters.append(
|
|
113
|
-
{restriction["key"]: {"$in": restriction["value"]}}
|
|
114
|
-
)
|
|
88
|
+
for key, value in restrictions.items():
|
|
89
|
+
keys_info = interpret_flat_key(key, object_lists)
|
|
90
|
+
filters.append(
|
|
91
|
+
_build_nested_matcher(object_lists, keys_info, value)
|
|
92
|
+
)
|
|
115
93
|
else:
|
|
116
94
|
return None
|
|
117
95
|
else:
|
|
@@ -123,7 +101,10 @@ class GetRequestRules:
|
|
|
123
101
|
"key": user_context.bag.get(
|
|
124
102
|
"tenant_defining_entity_id", user_context.x_tenant.id
|
|
125
103
|
),
|
|
126
|
-
"type":
|
|
104
|
+
"type": [
|
|
105
|
+
user_context.bag["tenant_relation_type"],
|
|
106
|
+
"belongsTo",
|
|
107
|
+
],
|
|
127
108
|
}
|
|
128
109
|
}
|
|
129
110
|
},
|
|
@@ -131,6 +112,26 @@ class GetRequestRules:
|
|
|
131
112
|
|
|
132
113
|
user_context.access_restrictions.filters = filters
|
|
133
114
|
user_context.access_restrictions.post_request_hook = (
|
|
134
|
-
|
|
115
|
+
mask_protected_content_post_request_hook(user_context, permissions)
|
|
135
116
|
)
|
|
136
117
|
return True
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _build_nested_matcher(object_lists, keys_info, value, index=0):
|
|
121
|
+
info = keys_info[index]
|
|
122
|
+
|
|
123
|
+
if info["object_list"]:
|
|
124
|
+
nested_matcher = _build_nested_matcher(
|
|
125
|
+
object_lists, keys_info, value, index + 1
|
|
126
|
+
)
|
|
127
|
+
elem_match = {
|
|
128
|
+
"$elemMatch": {
|
|
129
|
+
object_lists[info["key"]]: info["object_key"],
|
|
130
|
+
keys_info[index + 1]["key"]: nested_matcher,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return elem_match if index > 0 else {info["key"]: elem_match}
|
|
134
|
+
|
|
135
|
+
if isinstance(value, list):
|
|
136
|
+
value = {"$in": value}
|
|
137
|
+
return value if index > 0 else {info["key"]: value}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import re as regex
|
|
2
|
+
|
|
3
|
+
from configuration import get_object_configuration_mapper # pyright: ignore
|
|
4
|
+
from elody.policies.helpers import get_content
|
|
5
|
+
from elody.policies.permission_handler import (
|
|
6
|
+
get_permissions,
|
|
7
|
+
handle_single_item_request,
|
|
8
|
+
mask_protected_content_post_request_hook,
|
|
9
|
+
)
|
|
10
|
+
from flask import Request # pyright: ignore
|
|
11
|
+
from inuits_policy_based_auth import BaseAuthorizationPolicy # pyright: ignore
|
|
12
|
+
from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignore
|
|
13
|
+
PolicyContext,
|
|
14
|
+
)
|
|
15
|
+
from inuits_policy_based_auth.contexts.user_context import ( # pyright: ignore
|
|
16
|
+
UserContext,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GenericObjectRequestPolicyV2(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]+)?/[^/]+$", request.path):
|
|
26
|
+
return policy_context
|
|
27
|
+
|
|
28
|
+
for role in user_context.x_tenant.roles:
|
|
29
|
+
permissions = get_permissions(role, user_context)
|
|
30
|
+
if not permissions:
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
rules = [PostRequestRules, GetRequestRules]
|
|
34
|
+
access_verdict = None
|
|
35
|
+
for rule in rules:
|
|
36
|
+
access_verdict = rule().apply(user_context, request, permissions)
|
|
37
|
+
if access_verdict != None:
|
|
38
|
+
policy_context.access_verdict = access_verdict
|
|
39
|
+
if not policy_context.access_verdict:
|
|
40
|
+
break
|
|
41
|
+
|
|
42
|
+
if policy_context.access_verdict:
|
|
43
|
+
return policy_context
|
|
44
|
+
|
|
45
|
+
return policy_context
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PostRequestRules:
|
|
49
|
+
def apply(
|
|
50
|
+
self, user_context: UserContext, request: Request, permissions
|
|
51
|
+
) -> bool | None:
|
|
52
|
+
if request.method != "POST":
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
content = get_content(request.json, request, request.json)
|
|
56
|
+
schema_type = get_object_configuration_mapper().get(content["type"]).SCHEMA_TYPE
|
|
57
|
+
item = {**content, "schema": {"type": schema_type}}
|
|
58
|
+
return handle_single_item_request(
|
|
59
|
+
user_context, item, permissions, "create", content
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class GetRequestRules:
|
|
64
|
+
def apply(
|
|
65
|
+
self, user_context: UserContext, request: Request, permissions
|
|
66
|
+
) -> bool | None:
|
|
67
|
+
if request.method != "GET":
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
type_query_parameter = request.args.get("type")
|
|
71
|
+
allowed_item_types = list(permissions["read"].keys())
|
|
72
|
+
filters = []
|
|
73
|
+
|
|
74
|
+
if type_query_parameter:
|
|
75
|
+
if type_query_parameter not in allowed_item_types:
|
|
76
|
+
return None
|
|
77
|
+
type_permissions = permissions["read"][type_query_parameter]
|
|
78
|
+
schemas = list(type_permissions.keys())
|
|
79
|
+
if len(schemas) > 0:
|
|
80
|
+
number_of_object_restrictions = len(
|
|
81
|
+
type_permissions[schemas[0]].get("object_restrictions", {}).keys()
|
|
82
|
+
)
|
|
83
|
+
for i in range(number_of_object_restrictions):
|
|
84
|
+
keys, values = [], []
|
|
85
|
+
for schema in schemas:
|
|
86
|
+
object_restrictions = type_permissions[schema].get(
|
|
87
|
+
"object_restrictions", {}
|
|
88
|
+
)
|
|
89
|
+
key = [
|
|
90
|
+
key
|
|
91
|
+
for key in object_restrictions.keys()
|
|
92
|
+
if key.startswith(f"{i}:")
|
|
93
|
+
][0]
|
|
94
|
+
keys.append(f"{schema}|{key.split(':')[1]}")
|
|
95
|
+
values = object_restrictions[key]
|
|
96
|
+
filters.append(
|
|
97
|
+
{
|
|
98
|
+
"type": "selection",
|
|
99
|
+
"key": keys,
|
|
100
|
+
"value": values,
|
|
101
|
+
"match_exact": True,
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
filters.insert(0, {"type": "type", "value": type_query_parameter})
|
|
105
|
+
else:
|
|
106
|
+
filters.append(
|
|
107
|
+
{
|
|
108
|
+
"type": "selection",
|
|
109
|
+
"key": "type",
|
|
110
|
+
"value": allowed_item_types,
|
|
111
|
+
"match_exact": True,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
if tenant_relation_type := user_context.bag.get("tenant_relation_type"):
|
|
115
|
+
filters.append(
|
|
116
|
+
{
|
|
117
|
+
"type": "selection",
|
|
118
|
+
"key": tenant_relation_type,
|
|
119
|
+
"value": [
|
|
120
|
+
"tenant:super",
|
|
121
|
+
user_context.bag.get(
|
|
122
|
+
"tenant_defining_entity_id", user_context.x_tenant.id
|
|
123
|
+
),
|
|
124
|
+
],
|
|
125
|
+
"match_exact": True,
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
user_context.access_restrictions.filters = filters
|
|
130
|
+
user_context.access_restrictions.post_request_hook = (
|
|
131
|
+
mask_protected_content_post_request_hook(user_context, permissions)
|
|
132
|
+
)
|
|
133
|
+
return True
|
|
@@ -0,0 +1,92 @@
|
|
|
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 MediafileDerivativesPolicy(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(r"^/mediafiles/(.+)/derivatives$", 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")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class DeleteRequestRules:
|
|
86
|
+
def apply(
|
|
87
|
+
self, item, user_context: UserContext, request: Request, permissions
|
|
88
|
+
) -> bool | None:
|
|
89
|
+
if request.method != "DELETE":
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
return handle_single_item_request(user_context, item, permissions, "delete")
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import re as regex
|
|
2
|
+
|
|
3
|
+
from elody.error_codes import ErrorCode, get_error_code, get_read
|
|
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 MediafileDownloadPolicy(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(r"^/mediafiles/(.+)/download$", 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
|
+
GetRequestRules,
|
|
49
|
+
]
|
|
50
|
+
access_verdict = None
|
|
51
|
+
for rule in rules:
|
|
52
|
+
access_verdict = rule().apply(item, user_context, request, permissions)
|
|
53
|
+
if access_verdict != None:
|
|
54
|
+
policy_context.access_verdict = access_verdict
|
|
55
|
+
if not policy_context.access_verdict:
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
if policy_context.access_verdict:
|
|
59
|
+
return policy_context
|
|
60
|
+
|
|
61
|
+
return policy_context
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class GetRequestRules:
|
|
65
|
+
def apply(
|
|
66
|
+
self, item, user_context: UserContext, request: Request, permissions
|
|
67
|
+
) -> bool | None:
|
|
68
|
+
if request.method != "GET":
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
return handle_single_item_request(user_context, item, permissions, "read")
|