pypomes-iam 0.3.5__tar.gz → 0.3.7__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.
Potentially problematic release.
This version of pypomes-iam might be problematic. Click here for more details.
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/PKG-INFO +1 -1
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/pyproject.toml +1 -1
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/src/pypomes_iam/iam_common.py +10 -1
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/src/pypomes_iam/iam_pomes.py +219 -199
- pypomes_iam-0.3.7/src/pypomes_iam/iam_services.py +294 -0
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/src/pypomes_iam/jusbr_pomes.py +23 -17
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/src/pypomes_iam/keycloak_pomes.py +23 -17
- pypomes_iam-0.3.7/src/pypomes_iam/provider_pomes.py +146 -0
- pypomes_iam-0.3.5/src/pypomes_iam/iam_services.py +0 -258
- pypomes_iam-0.3.5/src/pypomes_iam/provider_pomes.py +0 -139
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/.gitignore +0 -0
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/LICENSE +0 -0
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/README.md +0 -0
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/src/pypomes_iam/__init__.py +0 -0
- {pypomes_iam-0.3.5 → pypomes_iam-0.3.7}/src/pypomes_iam/token_pomes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_iam
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: A collection of Python pomes, penyeach (IAM modules)
|
|
5
5
|
Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-IAM
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-IAM/issues
|
|
@@ -5,6 +5,7 @@ from enum import StrEnum
|
|
|
5
5
|
from logging import Logger
|
|
6
6
|
from pypomes_core import TZ_LOCAL, exc_format
|
|
7
7
|
from pypomes_crypto import crypto_jwk_convert
|
|
8
|
+
from threading import Lock
|
|
8
9
|
from typing import Any, Final
|
|
9
10
|
|
|
10
11
|
|
|
@@ -16,7 +17,8 @@ class IamServer(StrEnum):
|
|
|
16
17
|
IAM_KEYCLOAK = "iam-keycloak"
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
# the logger for IAM operations
|
|
20
|
+
# the logger for IAM service operations
|
|
21
|
+
# (used exclusively at the HTTP endpoint - all other functions receive the lgger as parameter)
|
|
20
22
|
__IAM_LOGGER: Logger | None = None
|
|
21
23
|
|
|
22
24
|
# registry structure:
|
|
@@ -51,11 +53,18 @@ __IAM_LOGGER: Logger | None = None
|
|
|
51
53
|
# }
|
|
52
54
|
_IAM_SERVERS: Final[dict[IamServer, dict[str, Any]]] = {}
|
|
53
55
|
|
|
56
|
+
# the lock protecting the data in '_IAM_SERVER'
|
|
57
|
+
# (because it is 'Final' and set at declaration time, it can be accessed through simple imports)
|
|
58
|
+
_iam_lock: Final[Lock] = Lock()
|
|
59
|
+
|
|
54
60
|
|
|
55
61
|
def _get_logger() -> Logger | None:
|
|
56
62
|
"""
|
|
57
63
|
Retrieve the registered logger for *IAM* operations.
|
|
58
64
|
|
|
65
|
+
This function is invoked exclusively from the HTTP endpoints.
|
|
66
|
+
All other functions receive the logger as parameter.
|
|
67
|
+
|
|
59
68
|
:return: the registered logger for *IAM* operations.
|
|
60
69
|
"""
|
|
61
70
|
return __IAM_LOGGER
|
|
@@ -3,14 +3,13 @@ import requests
|
|
|
3
3
|
import secrets
|
|
4
4
|
import string
|
|
5
5
|
import sys
|
|
6
|
-
from cachetools import Cache
|
|
7
6
|
from datetime import datetime
|
|
8
7
|
from logging import Logger
|
|
9
8
|
from pypomes_core import TZ_LOCAL, exc_format
|
|
10
9
|
from typing import Any
|
|
11
10
|
|
|
12
11
|
from .iam_common import (
|
|
13
|
-
IamServer,
|
|
12
|
+
IamServer, _iam_lock,
|
|
14
13
|
_register_logger, _get_iam_users, _get_iam_registry,
|
|
15
14
|
_get_login_timeout, _get_user_data, _get_public_key
|
|
16
15
|
)
|
|
@@ -48,30 +47,34 @@ def user_login(iam_server: IamServer,
|
|
|
48
47
|
# build the user data
|
|
49
48
|
# ('oauth_state' is a randomly-generated string, thus 'user_data' is always a new entry)
|
|
50
49
|
oauth_state: str = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(16))
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
registry[
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
|
|
51
|
+
with _iam_lock:
|
|
52
|
+
# retrieve the user data from the IAM server's registry
|
|
53
|
+
user_data: dict[str, Any] = _get_user_data(iam_server=iam_server,
|
|
54
|
+
user_id=oauth_state,
|
|
55
|
+
errors=errors,
|
|
56
|
+
logger=logger)
|
|
57
|
+
if user_data:
|
|
58
|
+
user_data["login-id"] = user_id
|
|
59
|
+
timeout: int = _get_login_timeout(iam_server=iam_server,
|
|
60
|
+
errors=errors,
|
|
61
|
+
logger=logger)
|
|
62
|
+
if not errors:
|
|
63
|
+
user_data["login-expiration"] = int(datetime.now(tz=TZ_LOCAL).timestamp()) + timeout \
|
|
64
|
+
if timeout else None
|
|
65
|
+
redirect_uri: str = args.get("redirect-uri")
|
|
66
|
+
|
|
67
|
+
# build the login url
|
|
68
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
69
|
+
errors=errors,
|
|
70
|
+
logger=logger)
|
|
71
|
+
if registry:
|
|
72
|
+
registry["redirect-uri"] = redirect_uri
|
|
73
|
+
result = {"login-url": (f"{registry["base-url"]}/protocol/openid-connect/auth"
|
|
74
|
+
f"?response_type=code&scope=openid"
|
|
75
|
+
f"&client_id={registry["client-id"]}"
|
|
76
|
+
f"&redirect_uri={redirect_uri}"
|
|
77
|
+
f"&state={oauth_state}")}
|
|
75
78
|
return result
|
|
76
79
|
|
|
77
80
|
|
|
@@ -94,14 +97,15 @@ def user_logout(iam_server: IamServer,
|
|
|
94
97
|
user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
|
|
95
98
|
|
|
96
99
|
if user_id:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
users
|
|
103
|
-
|
|
104
|
-
logger
|
|
100
|
+
with _iam_lock:
|
|
101
|
+
# retrieve the data for all users in the IAM server's registry
|
|
102
|
+
users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
|
|
103
|
+
errors=errors,
|
|
104
|
+
logger=logger) or {}
|
|
105
|
+
if user_id in users:
|
|
106
|
+
users.pop(user_id)
|
|
107
|
+
if logger:
|
|
108
|
+
logger.debug(msg=f"User '{user_id}' removed from {iam_server}'s registry")
|
|
105
109
|
|
|
106
110
|
|
|
107
111
|
def user_token(iam_server: IamServer,
|
|
@@ -111,7 +115,7 @@ def user_token(iam_server: IamServer,
|
|
|
111
115
|
"""
|
|
112
116
|
Retrieve the authentication token for the user, from *iam_server*.
|
|
113
117
|
|
|
114
|
-
The user is identified by the attribute *user-id*, *user_id*, or
|
|
118
|
+
The user is identified by the attribute *user-id*, *user_id*, or *login*, provided in *args*.
|
|
115
119
|
|
|
116
120
|
:param iam_server: the reference registered *IAM* server
|
|
117
121
|
:param args: the arguments passed when requesting the service
|
|
@@ -127,56 +131,58 @@ def user_token(iam_server: IamServer,
|
|
|
127
131
|
|
|
128
132
|
err_msg: str | None = None
|
|
129
133
|
if user_id:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
134
|
+
with _iam_lock:
|
|
135
|
+
# retrieve the user data in the IAM server's registry
|
|
136
|
+
user_data: dict[str, Any] = _get_user_data(iam_server=iam_server,
|
|
137
|
+
user_id=user_id,
|
|
138
|
+
errors=errors,
|
|
139
|
+
logger=logger)
|
|
140
|
+
token: str = user_data["access-token"] if user_data else None
|
|
141
|
+
if token:
|
|
142
|
+
access_expiration: int = user_data.get("access-expiration")
|
|
143
|
+
now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
|
|
144
|
+
if now < access_expiration:
|
|
145
|
+
result = token
|
|
146
|
+
else:
|
|
147
|
+
# access token has expired
|
|
148
|
+
refresh_token: str = user_data["refresh-token"]
|
|
149
|
+
if refresh_token:
|
|
150
|
+
refresh_expiration = user_data["refresh-expiration"]
|
|
151
|
+
if now < refresh_expiration:
|
|
152
|
+
body_data: dict[str, str] = {
|
|
153
|
+
"grant_type": "refresh_token",
|
|
154
|
+
"refresh_token": refresh_token
|
|
155
|
+
}
|
|
156
|
+
now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
|
|
157
|
+
token_data: dict[str, Any] = __post_for_token(iam_server=iam_server,
|
|
158
|
+
body_data=body_data,
|
|
159
|
+
errors=errors,
|
|
160
|
+
logger=logger)
|
|
161
|
+
# validate and store the token data
|
|
162
|
+
if token_data:
|
|
163
|
+
token_info: tuple[str, str] = __validate_and_store(iam_server=iam_server,
|
|
164
|
+
user_data=user_data,
|
|
165
|
+
token_data=token_data,
|
|
166
|
+
now=now,
|
|
167
|
+
errors=errors,
|
|
168
|
+
logger=logger)
|
|
169
|
+
result = token_info[1]
|
|
170
|
+
else:
|
|
171
|
+
# refresh token is no longer valid
|
|
172
|
+
user_data["refresh-token"] = None
|
|
164
173
|
else:
|
|
165
|
-
# refresh token
|
|
166
|
-
|
|
174
|
+
# refresh token has expired
|
|
175
|
+
err_msg = "Access and refresh tokens expired"
|
|
176
|
+
if logger:
|
|
177
|
+
logger.error(msg=err_msg)
|
|
167
178
|
else:
|
|
168
|
-
|
|
169
|
-
err_msg = "Access and refresh tokens expired"
|
|
179
|
+
err_msg = "Access token expired, no refresh token available"
|
|
170
180
|
if logger:
|
|
171
181
|
logger.error(msg=err_msg)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
else:
|
|
177
|
-
err_msg = f"User '{user_id}' not authenticated"
|
|
178
|
-
if logger:
|
|
179
|
-
logger.error(msg=err_msg)
|
|
182
|
+
else:
|
|
183
|
+
err_msg = f"User '{user_id}' not authenticated"
|
|
184
|
+
if logger:
|
|
185
|
+
logger.error(msg=err_msg)
|
|
180
186
|
else:
|
|
181
187
|
err_msg = "User identification not provided"
|
|
182
188
|
if logger:
|
|
@@ -193,7 +199,11 @@ def login_callback(iam_server: IamServer,
|
|
|
193
199
|
errors: list[str] = None,
|
|
194
200
|
logger: Logger = None) -> tuple[str, str] | None:
|
|
195
201
|
"""
|
|
196
|
-
Entry point for the callback from *iam_server* via the front-end application, on authentication
|
|
202
|
+
Entry point for the callback from *iam_server* via the front-end application, on authentication operations.
|
|
203
|
+
|
|
204
|
+
The relevant arguments received are:
|
|
205
|
+
- *state*: used to enhance security during the authorization process, typically to provide *CSRF* protection
|
|
206
|
+
- *code*: the temporary authorization code, to be exchanged for the token
|
|
197
207
|
|
|
198
208
|
:param iam_server: the reference registered *IAM* server
|
|
199
209
|
:param args: the arguments passed when requesting the service
|
|
@@ -204,15 +214,13 @@ def login_callback(iam_server: IamServer,
|
|
|
204
214
|
# initialize the return variable
|
|
205
215
|
result: tuple[str, str] | None = None
|
|
206
216
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
# validate the OAuth2 state
|
|
217
|
+
with _iam_lock:
|
|
218
|
+
# retrieve the IAM server's registry and the data for all users therein
|
|
219
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
220
|
+
errors=errors,
|
|
221
|
+
logger=logger)
|
|
222
|
+
users: dict[str, dict[str, Any]] = (registry["cache"]["users"] or {}) if registry else {}
|
|
223
|
+
# retrieve the OAuth2 state
|
|
216
224
|
oauth_state: str = args.get("state")
|
|
217
225
|
user_data: dict[str, Any] | None = None
|
|
218
226
|
if oauth_state:
|
|
@@ -221,7 +229,7 @@ def login_callback(iam_server: IamServer,
|
|
|
221
229
|
user_data = data
|
|
222
230
|
break
|
|
223
231
|
|
|
224
|
-
# exchange 'code' for the token
|
|
232
|
+
# exchange 'code' received for the token
|
|
225
233
|
if user_data:
|
|
226
234
|
expiration: int = user_data["login-expiration"] or sys.maxsize
|
|
227
235
|
if int(datetime.now(tz=TZ_LOCAL).timestamp()) > expiration:
|
|
@@ -268,6 +276,15 @@ def token_exchange(iam_server: IamServer,
|
|
|
268
276
|
- client-id: identification for the reference user (aliases: 'client_id', 'login')
|
|
269
277
|
- token: the token to be exchanged
|
|
270
278
|
|
|
279
|
+
The typical data set returned contains the following attributes:
|
|
280
|
+
{
|
|
281
|
+
"token_type": "Bearer",
|
|
282
|
+
"access_token": <str>,
|
|
283
|
+
"expires_in": <number-of-seconds>,
|
|
284
|
+
"refresh_token": <str>,
|
|
285
|
+
"refesh_expires_in": <number-of-seconds>
|
|
286
|
+
}
|
|
287
|
+
|
|
271
288
|
:param iam_server: the reference registered *IAM* server
|
|
272
289
|
:param args: the arguments passed when requesting the service
|
|
273
290
|
:param errors: incidental errors
|
|
@@ -280,40 +297,41 @@ def token_exchange(iam_server: IamServer,
|
|
|
280
297
|
# obtain the user's identification
|
|
281
298
|
user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
|
|
282
299
|
|
|
283
|
-
#
|
|
300
|
+
# obtain the token to be exchanges
|
|
284
301
|
token: str = args.get("token")
|
|
285
302
|
|
|
286
303
|
if user_id and token:
|
|
287
304
|
# HAZARD: only 'IAM_KEYCLOAK' is currently supported
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
305
|
+
with _iam_lock:
|
|
306
|
+
# retrieve the IAM server's registry
|
|
307
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
308
|
+
errors=errors,
|
|
309
|
+
logger=logger)
|
|
310
|
+
if registry:
|
|
311
|
+
body_data: dict[str, str] = {
|
|
312
|
+
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
313
|
+
"subject_token": token,
|
|
314
|
+
"subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
|
|
315
|
+
"requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
|
|
316
|
+
"audience": registry["client-id"],
|
|
317
|
+
"subject_issuer": "oidc"
|
|
318
|
+
}
|
|
319
|
+
now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
|
|
320
|
+
token_data: dict[str, Any] = __post_for_token(iam_server=IamServer.IAM_KEYCLOAK,
|
|
321
|
+
body_data=body_data,
|
|
322
|
+
errors=errors,
|
|
323
|
+
logger=logger)
|
|
324
|
+
# validate and store the token data
|
|
325
|
+
if token_data:
|
|
326
|
+
user_data: dict[str, Any] = {}
|
|
327
|
+
result = __validate_and_store(iam_server=iam_server,
|
|
328
|
+
user_data=user_data,
|
|
329
|
+
token_data=token_data,
|
|
330
|
+
now=now,
|
|
331
|
+
errors=errors,
|
|
332
|
+
logger=logger)
|
|
315
333
|
else:
|
|
316
|
-
msg: str = "User identification
|
|
334
|
+
msg: str = "User identification or token not provided"
|
|
317
335
|
if logger:
|
|
318
336
|
logger.error(msg=msg)
|
|
319
337
|
if isinstance(errors, list):
|
|
@@ -353,7 +371,7 @@ def __post_for_token(iam_server: IamServer,
|
|
|
353
371
|
If the operation is successful, the token data is stored in the *IAM* server's registry, and returned.
|
|
354
372
|
Otherwise, *errors* will contain the appropriate error message.
|
|
355
373
|
|
|
356
|
-
The typical data returned contains the following attributes:
|
|
374
|
+
The typical data set returned contains the following attributes:
|
|
357
375
|
{
|
|
358
376
|
"token_type": "Bearer",
|
|
359
377
|
"access_token": <str>,
|
|
@@ -371,52 +389,53 @@ def __post_for_token(iam_server: IamServer,
|
|
|
371
389
|
# initialize the return variable
|
|
372
390
|
result: dict[str, Any] | None = None
|
|
373
391
|
|
|
374
|
-
# PBTAIN THE iam SERVER'S REGISTRY
|
|
375
|
-
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
376
|
-
errors=errors,
|
|
377
|
-
logger=logger)
|
|
378
392
|
err_msg: str | None = None
|
|
379
|
-
|
|
380
|
-
#
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
#
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
393
|
+
with _iam_lock:
|
|
394
|
+
# retrieve the IAM server's registry
|
|
395
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
396
|
+
errors=errors,
|
|
397
|
+
logger=logger)
|
|
398
|
+
if registry:
|
|
399
|
+
# complete the data to send in body of request
|
|
400
|
+
body_data["client_id"] = registry["client-id"]
|
|
401
|
+
client_secret: str = registry["client-secret"]
|
|
402
|
+
if client_secret:
|
|
403
|
+
body_data["client_secret"] = client_secret
|
|
404
|
+
|
|
405
|
+
# obtain the token
|
|
406
|
+
url: str = registry["base-url"] + "/protocol/openid-connect/token"
|
|
407
|
+
if logger:
|
|
408
|
+
logger.debug(msg=f"POST '{url}', data {json.dumps(obj=body_data,
|
|
409
|
+
ensure_ascii=False)}")
|
|
410
|
+
try:
|
|
411
|
+
# typical return on a token request:
|
|
412
|
+
# {
|
|
413
|
+
# "token_type": "Bearer",
|
|
414
|
+
# "access_token": <str>,
|
|
415
|
+
# "expires_in": <number-of-seconds>,
|
|
416
|
+
# "refresh_token": <str>,
|
|
417
|
+
# "refesh_expires_in": <number-of-seconds>
|
|
418
|
+
# }
|
|
419
|
+
response: requests.Response = requests.post(url=url,
|
|
420
|
+
data=body_data)
|
|
421
|
+
if response.status_code == 200:
|
|
422
|
+
# request succeeded
|
|
423
|
+
if logger:
|
|
424
|
+
logger.debug(msg=f"POST success, status {response.status_code}")
|
|
425
|
+
result = response.json()
|
|
426
|
+
else:
|
|
427
|
+
# request resulted in error
|
|
428
|
+
err_msg = f"POST failure, status {response.status_code}, reason '{response.reason}'"
|
|
429
|
+
if hasattr(response, "content") and response.content:
|
|
430
|
+
err_msg += f", content '{response.content}'"
|
|
431
|
+
if logger:
|
|
432
|
+
logger.error(msg=err_msg)
|
|
433
|
+
except Exception as e:
|
|
434
|
+
# the operation raised an exception
|
|
435
|
+
err_msg = exc_format(exc=e,
|
|
436
|
+
exc_info=sys.exc_info())
|
|
412
437
|
if logger:
|
|
413
438
|
logger.error(msg=err_msg)
|
|
414
|
-
except Exception as e:
|
|
415
|
-
# the operation raised an exception
|
|
416
|
-
err_msg = exc_format(exc=e,
|
|
417
|
-
exc_info=sys.exc_info())
|
|
418
|
-
if logger:
|
|
419
|
-
logger.error(msg=err_msg)
|
|
420
439
|
|
|
421
440
|
if err_msg and isinstance(errors, list):
|
|
422
441
|
errors.append(err_msg)
|
|
@@ -452,38 +471,39 @@ def __validate_and_store(iam_server: IamServer,
|
|
|
452
471
|
# initialize the return variable
|
|
453
472
|
result: tuple[str, str] | None = None
|
|
454
473
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
474
|
+
with _iam_lock:
|
|
475
|
+
# retrieve the IAM server's registry
|
|
476
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
477
|
+
errors=errors,
|
|
478
|
+
logger=logger)
|
|
479
|
+
if registry:
|
|
480
|
+
token: str = token_data.get("access_token")
|
|
481
|
+
user_data["access-token"] = token
|
|
482
|
+
# keep current refresh token if a new one is not provided
|
|
483
|
+
if token_data.get("refresh_token"):
|
|
484
|
+
user_data["refresh-token"] = token_data.get("refresh_token")
|
|
485
|
+
user_data["access-expiration"] = now + token_data.get("expires_in")
|
|
486
|
+
refresh_exp: int = user_data.get("refresh_expires_in")
|
|
487
|
+
user_data["refresh-expiration"] = (now + refresh_exp) if refresh_exp else sys.maxsize
|
|
488
|
+
public_key: str = _get_public_key(iam_server=iam_server,
|
|
489
|
+
errors=errors,
|
|
490
|
+
logger=logger)
|
|
491
|
+
if public_key:
|
|
492
|
+
recipient_attr = registry["recipient_attr"]
|
|
493
|
+
login_id = user_data.pop("login-id", None)
|
|
494
|
+
claims: dict[str, dict[str, Any]] = token_validate(token=token,
|
|
495
|
+
issuer=registry["base-url"],
|
|
496
|
+
recipient_id=login_id,
|
|
497
|
+
recipient_attr=recipient_attr,
|
|
498
|
+
public_key=public_key,
|
|
499
|
+
errors=errors,
|
|
500
|
+
logger=logger)
|
|
501
|
+
if claims:
|
|
502
|
+
users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
|
|
503
|
+
errors=errors,
|
|
504
|
+
logger=logger)
|
|
505
|
+
if users:
|
|
506
|
+
user_id: str = login_id if login_id else claims["payload"][recipient_attr]
|
|
507
|
+
users[user_id] = user_data
|
|
508
|
+
result = (user_id, token)
|
|
489
509
|
return result
|