arcane-flask 2.2.2__tar.gz → 3.0.0__tar.gz
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.
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/PKG-INFO +1 -1
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/authentication.py +84 -63
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/pyproject.toml +1 -1
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/README.md +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/__init__.py +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/exception_decorator.py +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/http_response.py +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/log.py +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/services.py +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/tracking.py +0 -0
- {arcane_flask-2.2.2 → arcane_flask-3.0.0}/arcane/flask/types.py +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import functools
|
|
2
3
|
import inspect
|
|
3
4
|
import time
|
|
@@ -14,7 +15,6 @@ from google.cloud.exceptions import ServiceUnavailable
|
|
|
14
15
|
from arcane.core import CLIENTS_PARAM, ALL_CLIENTS_RIGHTS, RightsLevelEnum, GOOGLE_EXCEPTIONS_TO_RETRY, BadRequestError
|
|
15
16
|
from arcane.datastore import Client as DatastoreClient
|
|
16
17
|
from arcane.pubsub import Client as PubSubClient
|
|
17
|
-
import concurrent.futures
|
|
18
18
|
|
|
19
19
|
from .tracking import send_tracking_information
|
|
20
20
|
|
|
@@ -75,75 +75,96 @@ def check_access_rights(service: str,
|
|
|
75
75
|
start = time.time()
|
|
76
76
|
is_appengine_cron = request.headers.get('X-Appengine-Cron', False)
|
|
77
77
|
|
|
78
|
-
if is_appengine_cron:
|
|
79
|
-
logging.info("App Engine calls service : " + service)
|
|
80
|
-
return job_func(*args, **kwargs)
|
|
81
|
-
|
|
82
78
|
claims = {}
|
|
83
79
|
origin = ''
|
|
84
|
-
# Check feature rights
|
|
85
|
-
if auth_enabled:
|
|
86
|
-
token = str(request.headers.get('Authorization', '')).split(' ').pop()
|
|
87
|
-
origin = str(request.headers.get('origin', ''))
|
|
88
|
-
try:
|
|
89
|
-
claims = verify_token(token)
|
|
90
|
-
except (firebase_auth.ExpiredIdTokenError,
|
|
91
|
-
firebase_auth.RevokedIdTokenError,
|
|
92
|
-
firebase_auth.InvalidIdTokenError) as e:
|
|
93
|
-
if required_rights != RightsLevelEnum.NONE:
|
|
94
|
-
return {'detail': 'You don\'t have access to Adscale resources\n', 'firebase_log': str(e)}, 401
|
|
95
|
-
except ValueError as e:
|
|
96
|
-
return {'detail': str(e)}, 401
|
|
97
80
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
81
|
+
async def async_execution():
|
|
82
|
+
nonlocal claims, origin
|
|
83
|
+
|
|
84
|
+
if is_appengine_cron:
|
|
85
|
+
logging.info("App Engine calls service : " + service)
|
|
86
|
+
if asyncio.iscoroutinefunction(job_func):
|
|
87
|
+
return await job_func(*args, **kwargs)
|
|
88
|
+
else:
|
|
89
|
+
return job_func(*args, **kwargs)
|
|
90
|
+
|
|
91
|
+
# Check feature rights
|
|
92
|
+
if auth_enabled:
|
|
93
|
+
token = str(request.headers.get('Authorization', '')).split(' ').pop()
|
|
94
|
+
origin = str(request.headers.get('origin', ''))
|
|
95
|
+
try:
|
|
96
|
+
claims = verify_token(token)
|
|
97
|
+
except (firebase_auth.ExpiredIdTokenError,
|
|
98
|
+
firebase_auth.RevokedIdTokenError,
|
|
99
|
+
firebase_auth.InvalidIdTokenError) as e:
|
|
100
|
+
if required_rights != RightsLevelEnum.NONE:
|
|
101
|
+
return {'detail': 'You don\'t have access to Adscale resources\n', 'firebase_log': str(e)}, 401
|
|
102
|
+
except ValueError as e:
|
|
103
|
+
return {'detail': str(e)}, 401
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
_check_feature_right_access(
|
|
107
|
+
claims,
|
|
108
|
+
required_rights,
|
|
109
|
+
service_user_right
|
|
110
|
+
)
|
|
111
|
+
except BadRequestError:
|
|
112
|
+
rights = _get_level_access_for_a_feature_from_claims(claims, service_user_right)
|
|
113
|
+
return {'detail': f"You don't have access to this resource : your rights are "
|
|
114
|
+
f"'{rights_mapper.get(str(rights), '0')}' for service '{service}'. "
|
|
115
|
+
f"You need '{rights_mapper.get(str(required_rights), '0')}'.",
|
|
116
|
+
'claims': f"Your current rights are {json.dumps(claims, indent=4, sort_keys=True)}"}, 401
|
|
117
|
+
|
|
118
|
+
# Fill authorized_clients
|
|
119
|
+
if receive_rights_per_client:
|
|
120
|
+
if not auth_enabled:
|
|
121
|
+
authorized_clients = [ALL_CLIENTS_RIGHTS]
|
|
121
122
|
else:
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
# Value defined for service to service calls
|
|
124
|
+
service_authorized_clients = claims.get('authorized_clients')
|
|
125
|
+
db_user_id = claims.get('db_user_id')
|
|
126
|
+
if service_authorized_clients and not db_user_id:
|
|
127
|
+
authorized_clients = service_authorized_clients
|
|
124
128
|
else:
|
|
125
|
-
|
|
126
|
-
if user is None:
|
|
129
|
+
if not db_user_id:
|
|
127
130
|
authorized_clients = []
|
|
128
131
|
else:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
132
|
+
user = datastore_client.get_entity(USERS_KIND, int(db_user_id))
|
|
133
|
+
if user is None:
|
|
134
|
+
authorized_clients = []
|
|
135
|
+
else:
|
|
136
|
+
authorized_clients = user.get('authorized_clients', [])
|
|
137
|
+
|
|
138
|
+
if ALL_CLIENTS_RIGHTS in authorized_clients:
|
|
139
|
+
authorized_clients.remove(ALL_CLIENTS_RIGHTS)
|
|
140
|
+
clients_query = datastore_client.query()
|
|
141
|
+
clients_query.kind = CLIENTS_KIND
|
|
142
|
+
clients_query.keys_only()
|
|
143
|
+
authorized_clients = [client_entity.key.name for client_entity in clients_query.fetch()]
|
|
144
|
+
|
|
145
|
+
kwargs[CLIENTS_PARAM] = sorted(set(authorized_clients))
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
if asyncio.iscoroutinefunction(job_func):
|
|
149
|
+
func_response = await asyncio.wait_for(job_func(*args, **kwargs), timeout=timeout)
|
|
150
|
+
else:
|
|
151
|
+
# Synchronous function - wrap in executor for timeout handling
|
|
152
|
+
if timeout is not None:
|
|
153
|
+
loop = asyncio.get_event_loop()
|
|
154
|
+
func_response = await asyncio.wait_for(
|
|
155
|
+
loop.run_in_executor(None, lambda: job_func(*args, **kwargs)),
|
|
156
|
+
timeout=timeout
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
func_response = job_func(*args, **kwargs)
|
|
160
|
+
return func_response
|
|
161
|
+
except asyncio.TimeoutError:
|
|
162
|
+
return {'detail': 'Request Timeout'}, 504
|
|
163
|
+
except Exception as e:
|
|
164
|
+
return {'detail': f'Server Error: {str(e)}'}, 500
|
|
165
|
+
|
|
166
|
+
# Run the async execution in a new event loop
|
|
167
|
+
func_response = asyncio.run(async_execution())
|
|
147
168
|
|
|
148
169
|
end = time.time()
|
|
149
170
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|