pypomes-iam 0.3.3__py3-none-any.whl → 0.3.5__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.
- pypomes_iam/__init__.py +1 -1
- pypomes_iam/iam_common.py +7 -103
- pypomes_iam/iam_pomes.py +224 -61
- pypomes_iam/iam_services.py +18 -3
- pypomes_iam/token_pomes.py +1 -1
- {pypomes_iam-0.3.3.dist-info → pypomes_iam-0.3.5.dist-info}/METADATA +1 -1
- pypomes_iam-0.3.5.dist-info/RECORD +12 -0
- pypomes_iam-0.3.3.dist-info/RECORD +0 -12
- {pypomes_iam-0.3.3.dist-info → pypomes_iam-0.3.5.dist-info}/WHEEL +0 -0
- {pypomes_iam-0.3.3.dist-info → pypomes_iam-0.3.5.dist-info}/licenses/LICENSE +0 -0
pypomes_iam/__init__.py
CHANGED
pypomes_iam/iam_common.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import requests
|
|
3
2
|
import sys
|
|
4
|
-
from cachetools import Cache
|
|
5
3
|
from datetime import datetime
|
|
6
4
|
from enum import StrEnum
|
|
7
5
|
from logging import Logger
|
|
@@ -175,11 +173,10 @@ def _get_user_data(iam_server: IamServer,
|
|
|
175
173
|
# initialize the return variable
|
|
176
174
|
result: dict[str, Any] | None = None
|
|
177
175
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if
|
|
182
|
-
users: dict[str, dict[str, Any]] = cache.get("users")
|
|
176
|
+
users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
|
|
177
|
+
errors=errors,
|
|
178
|
+
logger=logger)
|
|
179
|
+
if users:
|
|
183
180
|
result = users.get(user_id)
|
|
184
181
|
if not result:
|
|
185
182
|
result = {
|
|
@@ -256,9 +253,9 @@ def _get_iam_registry(iam_server: IamServer,
|
|
|
256
253
|
return result
|
|
257
254
|
|
|
258
255
|
|
|
259
|
-
def
|
|
256
|
+
def _get_iam_users(iam_server: IamServer,
|
|
260
257
|
errors: list[str] | None,
|
|
261
|
-
logger: Logger | None) ->
|
|
258
|
+
logger: Logger | None) -> dict[str, dict[str, Any]]:
|
|
262
259
|
"""
|
|
263
260
|
Retrieve the cache storage in *iam_server*'s registry.
|
|
264
261
|
|
|
@@ -270,97 +267,4 @@ def _get_iam_cache(iam_server: IamServer,
|
|
|
270
267
|
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
271
268
|
errors=errors,
|
|
272
269
|
logger=logger)
|
|
273
|
-
return registry["cache"] if registry else None
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def _post_for_token(iam_server: IamServer,
|
|
277
|
-
body_data: dict[str, Any],
|
|
278
|
-
errors: list[str] | None,
|
|
279
|
-
logger: Logger | None) -> dict[str, Any] | None:
|
|
280
|
-
"""
|
|
281
|
-
Send a POST request to obtain the authentication token data, and return the data received.
|
|
282
|
-
|
|
283
|
-
For token acquisition, *body_data* will have the attributes:
|
|
284
|
-
- "grant_type": "authorization_code"
|
|
285
|
-
- "code": <16-character-random-code>
|
|
286
|
-
- "redirect_uri": <redirect-uri>
|
|
287
|
-
|
|
288
|
-
For token refresh, *body_data* will have the attributes:
|
|
289
|
-
- "grant_type": "refresh_token"
|
|
290
|
-
- "refresh_token": <current-refresh-token>
|
|
291
|
-
|
|
292
|
-
For token exchange, *body_data* will have the attributes:
|
|
293
|
-
- "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
294
|
-
- "subject_token": <token-to-be-exchanged>,
|
|
295
|
-
- "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
|
|
296
|
-
- "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
|
|
297
|
-
- "audience": <client-id>,
|
|
298
|
-
- "subject_issuer": "oidc"
|
|
299
|
-
|
|
300
|
-
These attributes are then added to *body_data*:
|
|
301
|
-
- "client_id": <client-id>,
|
|
302
|
-
- "client_secret": <client-secret>,
|
|
303
|
-
|
|
304
|
-
If the operation is successful, the token data is stored in the registry.
|
|
305
|
-
Otherwise, *errors* will contain the appropriate error message.
|
|
306
|
-
|
|
307
|
-
:param iam_server: the reference registered *IAM* server
|
|
308
|
-
:param body_data: the data to send in the body of the request
|
|
309
|
-
:param errors: incidental errors
|
|
310
|
-
:param logger: optional logger
|
|
311
|
-
:return: the access token obtained, or *None* if error
|
|
312
|
-
"""
|
|
313
|
-
# initialize the return variable
|
|
314
|
-
result: dict[str, Any] | None = None
|
|
315
|
-
|
|
316
|
-
# PBTAIN THE iam SERVER'S REGISTRY
|
|
317
|
-
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
318
|
-
errors=errors,
|
|
319
|
-
logger=logger)
|
|
320
|
-
err_msg: str | None = None
|
|
321
|
-
if registry:
|
|
322
|
-
# complete the data to send in body of request
|
|
323
|
-
body_data["client_id"] = registry["client-id"]
|
|
324
|
-
client_secret: str = registry["client-secret"]
|
|
325
|
-
if client_secret:
|
|
326
|
-
body_data["client_secret"] = client_secret
|
|
327
|
-
|
|
328
|
-
# obtain the token
|
|
329
|
-
url: str = registry["base-url"] + "/protocol/openid-connect/token"
|
|
330
|
-
if logger:
|
|
331
|
-
logger.debug(msg=f"POST '{url}', data {json.dumps(obj=body_data,
|
|
332
|
-
ensure_ascii=False)}")
|
|
333
|
-
try:
|
|
334
|
-
# typical return on a token request:
|
|
335
|
-
# {
|
|
336
|
-
# "token_type": "Bearer",
|
|
337
|
-
# "access_token": <str>,
|
|
338
|
-
# "expires_in": <number-of-seconds>,
|
|
339
|
-
# "refresh_token": <str>,
|
|
340
|
-
# "refesh_expires_in": <number-of-seconds>
|
|
341
|
-
# }
|
|
342
|
-
response: requests.Response = requests.post(url=url,
|
|
343
|
-
data=body_data)
|
|
344
|
-
if response.status_code == 200:
|
|
345
|
-
# request succeeded
|
|
346
|
-
if logger:
|
|
347
|
-
logger.debug(msg=f"POST success, status {response.status_code}")
|
|
348
|
-
result = response.json()
|
|
349
|
-
else:
|
|
350
|
-
# request resulted in error
|
|
351
|
-
err_msg = f"POST failure, status {response.status_code}, reason '{response.reason}'"
|
|
352
|
-
if hasattr(response, "content") and response.content:
|
|
353
|
-
err_msg += f", content '{response.content}'"
|
|
354
|
-
if logger:
|
|
355
|
-
logger.error(msg=err_msg)
|
|
356
|
-
except Exception as e:
|
|
357
|
-
# the operation raised an exception
|
|
358
|
-
err_msg = exc_format(exc=e,
|
|
359
|
-
exc_info=sys.exc_info())
|
|
360
|
-
if logger:
|
|
361
|
-
logger.error(msg=err_msg)
|
|
362
|
-
|
|
363
|
-
if err_msg and isinstance(errors, list):
|
|
364
|
-
errors.append(err_msg)
|
|
365
|
-
|
|
366
|
-
return result
|
|
270
|
+
return registry["cache"]["users"] if registry else None
|
pypomes_iam/iam_pomes.py
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import requests
|
|
1
3
|
import secrets
|
|
2
4
|
import string
|
|
3
5
|
import sys
|
|
4
6
|
from cachetools import Cache
|
|
5
7
|
from datetime import datetime
|
|
6
8
|
from logging import Logger
|
|
7
|
-
from pypomes_core import TZ_LOCAL
|
|
9
|
+
from pypomes_core import TZ_LOCAL, exc_format
|
|
8
10
|
from typing import Any
|
|
9
11
|
|
|
10
12
|
from .iam_common import (
|
|
11
13
|
IamServer,
|
|
12
|
-
_register_logger,
|
|
13
|
-
_get_iam_cache, _get_iam_registry,
|
|
14
|
+
_register_logger, _get_iam_users, _get_iam_registry,
|
|
14
15
|
_get_login_timeout, _get_user_data, _get_public_key
|
|
15
16
|
)
|
|
17
|
+
from .token_pomes import token_validate
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
def register_logger(logger: Logger) -> None:
|
|
@@ -93,15 +95,13 @@ def user_logout(iam_server: IamServer,
|
|
|
93
95
|
|
|
94
96
|
if user_id:
|
|
95
97
|
# retrieve the IAM server's cache storage
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if
|
|
100
|
-
users
|
|
101
|
-
if
|
|
102
|
-
|
|
103
|
-
if logger:
|
|
104
|
-
logger.debug(msg=f"User '{user_id}' removed from {iam_server}'s registry")
|
|
98
|
+
users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
|
|
99
|
+
errors=errors,
|
|
100
|
+
logger=logger) or {}
|
|
101
|
+
if user_id in users:
|
|
102
|
+
users.pop(user_id)
|
|
103
|
+
if logger:
|
|
104
|
+
logger.debug(msg=f"User '{user_id}' removed from {iam_server}'s registry")
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def user_token(iam_server: IamServer,
|
|
@@ -147,20 +147,20 @@ def user_token(iam_server: IamServer,
|
|
|
147
147
|
"grant_type": "refresh_token",
|
|
148
148
|
"refresh_token": refresh_token
|
|
149
149
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
|
|
151
|
+
token_data: dict[str, Any] = __post_for_token(iam_server=iam_server,
|
|
152
|
+
body_data=body_data,
|
|
153
|
+
errors=errors,
|
|
154
|
+
logger=logger)
|
|
155
|
+
# validate and store the token data
|
|
154
156
|
if token_data:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
user_data["refresh-expiration"] = (now + refresh_expiration) \
|
|
163
|
-
if refresh_expiration else sys.maxsize
|
|
157
|
+
token_info: tuple[str, str] = __validate_and_store(iam_server=iam_server,
|
|
158
|
+
user_data=user_data,
|
|
159
|
+
token_data=token_data,
|
|
160
|
+
now=now,
|
|
161
|
+
errors=errors,
|
|
162
|
+
logger=logger)
|
|
163
|
+
result = token_info[1]
|
|
164
164
|
else:
|
|
165
165
|
# refresh token is no longer valid
|
|
166
166
|
user_data["refresh-token"] = None
|
|
@@ -199,10 +199,8 @@ def login_callback(iam_server: IamServer,
|
|
|
199
199
|
:param args: the arguments passed when requesting the service
|
|
200
200
|
:param errors: incidental errors
|
|
201
201
|
:param logger: optional logger
|
|
202
|
-
:return: a tuple
|
|
202
|
+
:return: a tuple containing the reference user identification and the token obtained, or *None* if error
|
|
203
203
|
"""
|
|
204
|
-
from .token_pomes import token_validate
|
|
205
|
-
|
|
206
204
|
# initialize the return variable
|
|
207
205
|
result: tuple[str, str] | None = None
|
|
208
206
|
|
|
@@ -237,35 +235,18 @@ def login_callback(iam_server: IamServer,
|
|
|
237
235
|
"redirect_uri": registry["redirect-uri"]
|
|
238
236
|
}
|
|
239
237
|
now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
|
|
240
|
-
token_data: dict[str, Any] =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
#
|
|
238
|
+
token_data: dict[str, Any] = __post_for_token(iam_server=iam_server,
|
|
239
|
+
body_data=body_data,
|
|
240
|
+
errors=errors,
|
|
241
|
+
logger=logger)
|
|
242
|
+
# validate and store the token data
|
|
245
243
|
if token_data:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
user_data["refresh-expiration"] = (now + refresh_exp) if refresh_exp else sys.maxsize
|
|
253
|
-
public_key: str = _get_public_key(iam_server=iam_server,
|
|
254
|
-
errors=errors,
|
|
255
|
-
logger=logger)
|
|
256
|
-
if public_key:
|
|
257
|
-
recipient_attr = registry["recipient_attr"]
|
|
258
|
-
login_id = user_data.pop("login-id", None)
|
|
259
|
-
token_claims: dict[str, dict[str, Any]] = token_validate(token=token,
|
|
260
|
-
issuer=registry["base-url"],
|
|
261
|
-
recipient_id=login_id,
|
|
262
|
-
recipient_attr=recipient_attr,
|
|
263
|
-
public_key=public_key,
|
|
264
|
-
errors=errors,
|
|
265
|
-
logger=logger)
|
|
266
|
-
if token_claims:
|
|
267
|
-
token_user: str = token_claims["payload"].get(recipient_attr)
|
|
268
|
-
result = (token_user, token)
|
|
244
|
+
result = __validate_and_store(iam_server=iam_server,
|
|
245
|
+
user_data=user_data,
|
|
246
|
+
token_data=token_data,
|
|
247
|
+
now=now,
|
|
248
|
+
errors=errors,
|
|
249
|
+
logger=logger)
|
|
269
250
|
else:
|
|
270
251
|
msg: str = "Unknown state received"
|
|
271
252
|
if logger:
|
|
@@ -281,7 +262,11 @@ def token_exchange(iam_server: IamServer,
|
|
|
281
262
|
errors: list[str] = None,
|
|
282
263
|
logger: Logger = None) -> dict[str, Any]:
|
|
283
264
|
"""
|
|
284
|
-
|
|
265
|
+
Request *iam_server* to issue a token in exchange for the token obtained from another *IAM* server.
|
|
266
|
+
|
|
267
|
+
The expected parameters in *args* are:
|
|
268
|
+
- client-id: identification for the reference user (aliases: 'client_id', 'login')
|
|
269
|
+
- token: the token to be exchanged
|
|
285
270
|
|
|
286
271
|
:param iam_server: the reference registered *IAM* server
|
|
287
272
|
:param args: the arguments passed when requesting the service
|
|
@@ -312,10 +297,21 @@ def token_exchange(iam_server: IamServer,
|
|
|
312
297
|
"audience": registry["client-id"],
|
|
313
298
|
"subject_issuer": "oidc"
|
|
314
299
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
300
|
+
now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
|
|
301
|
+
token_data: dict[str, Any] = __post_for_token(iam_server=IamServer.IAM_KEYCLOAK,
|
|
302
|
+
body_data=body_data,
|
|
303
|
+
errors=errors,
|
|
304
|
+
logger=logger)
|
|
305
|
+
# validate and store the token data
|
|
306
|
+
if token_data:
|
|
307
|
+
user_data: dict[str, Any] = {}
|
|
308
|
+
result = __validate_and_store(iam_server=iam_server,
|
|
309
|
+
user_data=user_data,
|
|
310
|
+
token_data=token_data,
|
|
311
|
+
now=now,
|
|
312
|
+
errors=errors,
|
|
313
|
+
logger=logger)
|
|
314
|
+
|
|
319
315
|
else:
|
|
320
316
|
msg: str = "User identification and token must be provided"
|
|
321
317
|
if logger:
|
|
@@ -324,3 +320,170 @@ def token_exchange(iam_server: IamServer,
|
|
|
324
320
|
errors.append(msg)
|
|
325
321
|
|
|
326
322
|
return result
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def __post_for_token(iam_server: IamServer,
|
|
326
|
+
body_data: dict[str, Any],
|
|
327
|
+
errors: list[str] | None,
|
|
328
|
+
logger: Logger | None) -> dict[str, Any] | None:
|
|
329
|
+
"""
|
|
330
|
+
Send a POST request to obtain the authentication token data, and return the data received.
|
|
331
|
+
|
|
332
|
+
For token acquisition, *body_data* will have the attributes:
|
|
333
|
+
- "grant_type": "authorization_code"
|
|
334
|
+
- "code": <16-character-random-code>
|
|
335
|
+
- "redirect_uri": <redirect-uri>
|
|
336
|
+
|
|
337
|
+
For token refresh, *body_data* will have the attributes:
|
|
338
|
+
- "grant_type": "refresh_token"
|
|
339
|
+
- "refresh_token": <current-refresh-token>
|
|
340
|
+
|
|
341
|
+
For token exchange, *body_data* will have the attributes:
|
|
342
|
+
- "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
343
|
+
- "subject_token": <token-to-be-exchanged>,
|
|
344
|
+
- "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
|
|
345
|
+
- "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
|
|
346
|
+
- "audience": <client-id>,
|
|
347
|
+
- "subject_issuer": "oidc"
|
|
348
|
+
|
|
349
|
+
These attributes are then added to *body_data*:
|
|
350
|
+
- "client_id": <client-id>,
|
|
351
|
+
- "client_secret": <client-secret>,
|
|
352
|
+
|
|
353
|
+
If the operation is successful, the token data is stored in the *IAM* server's registry, and returned.
|
|
354
|
+
Otherwise, *errors* will contain the appropriate error message.
|
|
355
|
+
|
|
356
|
+
The typical data returned contains the following attributes:
|
|
357
|
+
{
|
|
358
|
+
"token_type": "Bearer",
|
|
359
|
+
"access_token": <str>,
|
|
360
|
+
"expires_in": <number-of-seconds>,
|
|
361
|
+
"refresh_token": <str>,
|
|
362
|
+
"refesh_expires_in": <number-of-seconds>
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
:param iam_server: the reference registered *IAM* server
|
|
366
|
+
:param body_data: the data to send in the body of the request
|
|
367
|
+
:param errors: incidental errors
|
|
368
|
+
:param logger: optional logger
|
|
369
|
+
:return: the token data, or *None* if error
|
|
370
|
+
"""
|
|
371
|
+
# initialize the return variable
|
|
372
|
+
result: dict[str, Any] | None = None
|
|
373
|
+
|
|
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
|
+
err_msg: str | None = None
|
|
379
|
+
if registry:
|
|
380
|
+
# complete the data to send in body of request
|
|
381
|
+
body_data["client_id"] = registry["client-id"]
|
|
382
|
+
client_secret: str = registry["client-secret"]
|
|
383
|
+
if client_secret:
|
|
384
|
+
body_data["client_secret"] = client_secret
|
|
385
|
+
|
|
386
|
+
# obtain the token
|
|
387
|
+
url: str = registry["base-url"] + "/protocol/openid-connect/token"
|
|
388
|
+
if logger:
|
|
389
|
+
logger.debug(msg=f"POST '{url}', data {json.dumps(obj=body_data,
|
|
390
|
+
ensure_ascii=False)}")
|
|
391
|
+
try:
|
|
392
|
+
# typical return on a token request:
|
|
393
|
+
# {
|
|
394
|
+
# "token_type": "Bearer",
|
|
395
|
+
# "access_token": <str>,
|
|
396
|
+
# "expires_in": <number-of-seconds>,
|
|
397
|
+
# "refresh_token": <str>,
|
|
398
|
+
# "refesh_expires_in": <number-of-seconds>
|
|
399
|
+
# }
|
|
400
|
+
response: requests.Response = requests.post(url=url,
|
|
401
|
+
data=body_data)
|
|
402
|
+
if response.status_code == 200:
|
|
403
|
+
# request succeeded
|
|
404
|
+
if logger:
|
|
405
|
+
logger.debug(msg=f"POST success, status {response.status_code}")
|
|
406
|
+
result = response.json()
|
|
407
|
+
else:
|
|
408
|
+
# request resulted in error
|
|
409
|
+
err_msg = f"POST failure, status {response.status_code}, reason '{response.reason}'"
|
|
410
|
+
if hasattr(response, "content") and response.content:
|
|
411
|
+
err_msg += f", content '{response.content}'"
|
|
412
|
+
if logger:
|
|
413
|
+
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
|
+
|
|
421
|
+
if err_msg and isinstance(errors, list):
|
|
422
|
+
errors.append(err_msg)
|
|
423
|
+
|
|
424
|
+
return result
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def __validate_and_store(iam_server: IamServer,
|
|
428
|
+
user_data: dict[str, Any],
|
|
429
|
+
token_data: dict[str, Any],
|
|
430
|
+
now: int,
|
|
431
|
+
errors: list[str] | None,
|
|
432
|
+
logger: Logger) -> tuple[str, str] | None:
|
|
433
|
+
"""
|
|
434
|
+
Validate and store the token data.
|
|
435
|
+
|
|
436
|
+
The typical *token_data* contains the following attributes:
|
|
437
|
+
{
|
|
438
|
+
"token_type": "Bearer",
|
|
439
|
+
"access_token": <str>,
|
|
440
|
+
"expires_in": <number-of-seconds>,
|
|
441
|
+
"refresh_token": <str>,
|
|
442
|
+
"refesh_expires_in": <number-of-seconds>
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
:param iam_server: the reference registered *IAM* server
|
|
446
|
+
:param user_data: the aurthentication data kepth in *iam_server*'s registry
|
|
447
|
+
:param token_data: the token data
|
|
448
|
+
:param errors: incidental errors
|
|
449
|
+
:param logger: optional logger
|
|
450
|
+
:return: tuple containing the user identification and the validated and stored token, or *None* if error
|
|
451
|
+
"""
|
|
452
|
+
# initialize the return variable
|
|
453
|
+
result: tuple[str, str] | None = None
|
|
454
|
+
|
|
455
|
+
# retrieve the IAM server's registry
|
|
456
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
|
457
|
+
errors=errors,
|
|
458
|
+
logger=logger)
|
|
459
|
+
if registry:
|
|
460
|
+
token: str = token_data.get("access_token")
|
|
461
|
+
user_data["access-token"] = token
|
|
462
|
+
# keep current refresh token if a new one is not provided
|
|
463
|
+
if token_data.get("refresh_token"):
|
|
464
|
+
user_data["refresh-token"] = token_data.get("refresh_token")
|
|
465
|
+
user_data["access-expiration"] = now + token_data.get("expires_in")
|
|
466
|
+
refresh_exp: int = user_data.get("refresh_expires_in")
|
|
467
|
+
user_data["refresh-expiration"] = (now + refresh_exp) if refresh_exp else sys.maxsize
|
|
468
|
+
public_key: str = _get_public_key(iam_server=iam_server,
|
|
469
|
+
errors=errors,
|
|
470
|
+
logger=logger)
|
|
471
|
+
if public_key:
|
|
472
|
+
recipient_attr = registry["recipient_attr"]
|
|
473
|
+
login_id = user_data.pop("login-id", None)
|
|
474
|
+
claims: dict[str, dict[str, Any]] = token_validate(token=token,
|
|
475
|
+
issuer=registry["base-url"],
|
|
476
|
+
recipient_id=login_id,
|
|
477
|
+
recipient_attr=recipient_attr,
|
|
478
|
+
public_key=public_key,
|
|
479
|
+
errors=errors,
|
|
480
|
+
logger=logger)
|
|
481
|
+
if claims:
|
|
482
|
+
users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
|
|
483
|
+
errors=errors,
|
|
484
|
+
logger=logger)
|
|
485
|
+
if users:
|
|
486
|
+
user_id: str = login_id if login_id else claims["payload"][recipient_attr]
|
|
487
|
+
users[user_id] = user_data
|
|
488
|
+
result = (user_id, token)
|
|
489
|
+
return result
|
pypomes_iam/iam_services.py
CHANGED
|
@@ -196,9 +196,24 @@ def service_exchange() -> Response:
|
|
|
196
196
|
"""
|
|
197
197
|
Entry point for requesting the *IAM* server to exchange the token.
|
|
198
198
|
|
|
199
|
-
This is currently
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
This is currently limited to the *KEYCLOAK* server. The token itself is stored in *KEYCLOAK*'s registry.
|
|
200
|
+
The expected parameters in the request are:
|
|
201
|
+
- client-id: identification for the reference user (aliases: 'client_id', 'login')
|
|
202
|
+
- token: the token to be exchanged
|
|
203
|
+
|
|
204
|
+
If the exchange is successful, the token data is stored in the *IAM* server's registry, and returned.
|
|
205
|
+
Otherwise, *errors* will contain the appropriate error message.
|
|
206
|
+
|
|
207
|
+
The typical *Response* returned contains the following attributes:
|
|
208
|
+
{
|
|
209
|
+
"token_type": "Bearer",
|
|
210
|
+
"access_token": <str>,
|
|
211
|
+
"expires_in": <number-of-seconds>,
|
|
212
|
+
"refresh_token": <str>,
|
|
213
|
+
"refesh_expires_in": <number-of-seconds>
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
:return: the response containing the token data, or *UNAUTHORIZED*
|
|
202
217
|
"""
|
|
203
218
|
# retrieve the operations's logger
|
|
204
219
|
logger: Logger = _get_logger()
|
pypomes_iam/token_pomes.py
CHANGED
|
@@ -40,7 +40,7 @@ def token_validate(token: str,
|
|
|
40
40
|
:param recipient_attr: attribute in the token's payload holding the expected subject's identification
|
|
41
41
|
:param errors: incidental error messages
|
|
42
42
|
:param logger: optional logger
|
|
43
|
-
:return: The token's claims (*header* and *payload*)
|
|
43
|
+
:return: The token's claims (*header* and *payload*), or *None* if error
|
|
44
44
|
"""
|
|
45
45
|
# initialize the return variable
|
|
46
46
|
result: dict[str, dict[str, Any]] | None = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_iam
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pypomes_iam/__init__.py,sha256=H7rUCaUEJBLNJv2rtdmBxwcAB28OItdEPenpv_UEOVw,965
|
|
2
|
+
pypomes_iam/iam_common.py,sha256=1NgXFTiD4qpbVqLfYsCfHrE0khEaczp-nR3AYXmzmvU,9608
|
|
3
|
+
pypomes_iam/iam_pomes.py,sha256=qmnHX88iaiMGaGeZfbs4VT-G_XMTpRT6wqRZeCOOKbQ,22294
|
|
4
|
+
pypomes_iam/iam_services.py,sha256=qdPPfwR9jIdGak-wr4t2NkdfhVaMqauBdvmVJvmFqyg,8914
|
|
5
|
+
pypomes_iam/jusbr_pomes.py,sha256=M47h_PUUgbCmFQyKz2sN1H9T00BC5v_oPgwl5ATWMSA,5625
|
|
6
|
+
pypomes_iam/keycloak_pomes.py,sha256=GtXJb4TZb-a_5b9ExYdJGetBcU1pEP96ONO6prA_vDo,6638
|
|
7
|
+
pypomes_iam/provider_pomes.py,sha256=eP8XzjTUEpwejTkO0wmDiqKjqbIEOzRNCR2ju5E15og,5856
|
|
8
|
+
pypomes_iam/token_pomes.py,sha256=1g6PMNNMbmdwLrsvSXvpO8-zdRhso1IFnwAyndNmV4Q,5332
|
|
9
|
+
pypomes_iam-0.3.5.dist-info/METADATA,sha256=fGRhn3H98wOkQSrxMh9FFTiheHez3TMIpX6R91wysoU,694
|
|
10
|
+
pypomes_iam-0.3.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
+
pypomes_iam-0.3.5.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
|
|
12
|
+
pypomes_iam-0.3.5.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
pypomes_iam/__init__.py,sha256=PRMMa9i1riAyzf2ikkz1Xb98zsOKKGgrpH1O9nxsJlc,952
|
|
2
|
-
pypomes_iam/iam_common.py,sha256=IWH9DVykF7K-Z9Sn3oP7To9_I2TkO2AzjVod238zUWc,13645
|
|
3
|
-
pypomes_iam/iam_pomes.py,sha256=mBFI7L0n_HW-F43SfqEYh320fIaMvbfLUyqjUTGW1U0,15229
|
|
4
|
-
pypomes_iam/iam_services.py,sha256=osqDptxCqL9eZPCRecBwtlS35YiMRvO7EIgdcyovSU4,8182
|
|
5
|
-
pypomes_iam/jusbr_pomes.py,sha256=M47h_PUUgbCmFQyKz2sN1H9T00BC5v_oPgwl5ATWMSA,5625
|
|
6
|
-
pypomes_iam/keycloak_pomes.py,sha256=GtXJb4TZb-a_5b9ExYdJGetBcU1pEP96ONO6prA_vDo,6638
|
|
7
|
-
pypomes_iam/provider_pomes.py,sha256=eP8XzjTUEpwejTkO0wmDiqKjqbIEOzRNCR2ju5E15og,5856
|
|
8
|
-
pypomes_iam/token_pomes.py,sha256=cfHdv2qYbsciY-3aEuDYUwCM479uMRSm2uwr4-hCaBQ,5345
|
|
9
|
-
pypomes_iam-0.3.3.dist-info/METADATA,sha256=BcVuINYnB1MELAb9OCxYuu-UAg2kp23aV-tYbNZCkpw,694
|
|
10
|
-
pypomes_iam-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
-
pypomes_iam-0.3.3.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
|
|
12
|
-
pypomes_iam-0.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|