pypomes-iam 0.7.2__py3-none-any.whl → 0.7.6__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/iam_actions.py +51 -8
- pypomes_iam/iam_services.py +1 -0
- {pypomes_iam-0.7.2.dist-info → pypomes_iam-0.7.6.dist-info}/METADATA +1 -1
- {pypomes_iam-0.7.2.dist-info → pypomes_iam-0.7.6.dist-info}/RECORD +6 -6
- {pypomes_iam-0.7.2.dist-info → pypomes_iam-0.7.6.dist-info}/WHEEL +0 -0
- {pypomes_iam-0.7.2.dist-info → pypomes_iam-0.7.6.dist-info}/licenses/LICENSE +0 -0
pypomes_iam/iam_actions.py
CHANGED
|
@@ -26,6 +26,7 @@ def action_login(iam_server: IamServer,
|
|
|
26
26
|
These are the expected attributes in *args*:
|
|
27
27
|
- user-id: optional, identifies the reference user (alias: 'login')
|
|
28
28
|
- redirect-uri: a parameter to be added to the query part of the returned URL
|
|
29
|
+
-target-idp: optionally, identify a target identity provider for the login operation
|
|
29
30
|
|
|
30
31
|
If provided, the user identification will be validated against the authorization data
|
|
31
32
|
returned by *iam_server* upon login. On success, the appropriate URL for invoking
|
|
@@ -43,9 +44,14 @@ def action_login(iam_server: IamServer,
|
|
|
43
44
|
# obtain the optional user's identification
|
|
44
45
|
user_id: str = args.get("user-id") or args.get("login")
|
|
45
46
|
|
|
47
|
+
# obtain the optional target identity provider
|
|
48
|
+
target_idp: str = args.get("target-idp")
|
|
49
|
+
|
|
46
50
|
# build the user data
|
|
47
51
|
# ('oauth_state' is a randomly-generated string, thus 'user_data' is always a new entry)
|
|
48
52
|
oauth_state: str = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(16))
|
|
53
|
+
if target_idp:
|
|
54
|
+
oauth_state += f"idp={target_idp}"
|
|
49
55
|
|
|
50
56
|
with _iam_lock:
|
|
51
57
|
# retrieve the user data from the IAM server's registry
|
|
@@ -75,6 +81,10 @@ def action_login(iam_server: IamServer,
|
|
|
75
81
|
f"&client_id={registry[IamParam.CLIENT_ID]}"
|
|
76
82
|
f"&redirect_uri={redirect_uri}"
|
|
77
83
|
f"&state={oauth_state}")
|
|
84
|
+
if target_idp:
|
|
85
|
+
# HAZARD: the name 'kc_idp_hint' is Keycloak-specific
|
|
86
|
+
result += f"&kc_idp_hint={target_idp}"
|
|
87
|
+
|
|
78
88
|
return result
|
|
79
89
|
|
|
80
90
|
|
|
@@ -240,6 +250,10 @@ def action_callback(iam_server: IamServer,
|
|
|
240
250
|
if int(datetime.now(tz=TZ_LOCAL).timestamp()) > expiration:
|
|
241
251
|
errors.append("Operation timeout")
|
|
242
252
|
else:
|
|
253
|
+
pos: int = oauth_state.rfind("idp=")
|
|
254
|
+
target_idp: str = oauth_state[pos+4:] if pos > 0 else None
|
|
255
|
+
target_iam = IamServer(target_idp) if target_idp in IamServer else None
|
|
256
|
+
target_data: dict[str, Any] = user_data.copy() if target_iam else None
|
|
243
257
|
users.pop(oauth_state)
|
|
244
258
|
code: str = args.get("code")
|
|
245
259
|
header_data: dict[str, str] = {
|
|
@@ -264,6 +278,33 @@ def action_callback(iam_server: IamServer,
|
|
|
264
278
|
now=now,
|
|
265
279
|
errors=errors,
|
|
266
280
|
logger=logger)
|
|
281
|
+
if target_iam:
|
|
282
|
+
if logger:
|
|
283
|
+
logger.debug(msg=f"Requesting to IAM server '{iam_server}' "
|
|
284
|
+
f"the token issued by '{target_iam}' ")
|
|
285
|
+
registry: dict[str, Any] = _get_iam_registry(iam_server,
|
|
286
|
+
errors=errors,
|
|
287
|
+
logger=logger)
|
|
288
|
+
url: str = f"{registry[IamParam.URL_BASE]}/realms/{registry[IamParam.CLIENT_REALM]}"
|
|
289
|
+
url += f"/broker/{target_idp}/token"
|
|
290
|
+
header_data: dict[str, str] = {
|
|
291
|
+
"Authorization": f"Bearer {result[1]}",
|
|
292
|
+
"Content-Type": "application/json"
|
|
293
|
+
}
|
|
294
|
+
token_data = __get_for_data(url=url,
|
|
295
|
+
header_data=header_data,
|
|
296
|
+
params=None,
|
|
297
|
+
errors=errors,
|
|
298
|
+
logger=logger)
|
|
299
|
+
if not errors:
|
|
300
|
+
token_info: tuple[str, str] = __validate_and_store(iam_server=target_iam,
|
|
301
|
+
user_data=target_data,
|
|
302
|
+
token_data=token_data,
|
|
303
|
+
now=now,
|
|
304
|
+
errors=errors,
|
|
305
|
+
logger=logger)
|
|
306
|
+
if token_info and logger:
|
|
307
|
+
logger.debug(msg=f"Token obtained: {json.dumps(obj=token_info)}")
|
|
267
308
|
else:
|
|
268
309
|
msg: str = f"State '{oauth_state}' not found in {iam_server}'s registry"
|
|
269
310
|
if logger:
|
|
@@ -451,13 +492,13 @@ def __assert_link(iam_server: IamServer,
|
|
|
451
492
|
logger.debug(msg="Creating an association between identifications "
|
|
452
493
|
f"'{user_id}' and '{token_sub}' in IAM server {iam_server}")
|
|
453
494
|
url += f"/{provider_name}"
|
|
454
|
-
|
|
495
|
+
json_data: dict[str, Any] = {
|
|
455
496
|
"userId": token_sub,
|
|
456
497
|
"userName": user_id
|
|
457
498
|
}
|
|
458
|
-
|
|
499
|
+
__post_json(url=url,
|
|
459
500
|
header_data=header_data,
|
|
460
|
-
|
|
501
|
+
json_data=json_data,
|
|
461
502
|
errors=errors,
|
|
462
503
|
logger=logger)
|
|
463
504
|
|
|
@@ -646,27 +687,27 @@ def __get_for_data(url: str,
|
|
|
646
687
|
return result
|
|
647
688
|
|
|
648
689
|
|
|
649
|
-
def
|
|
690
|
+
def __post_json(url: str,
|
|
650
691
|
header_data: dict[str, str],
|
|
651
|
-
|
|
692
|
+
json_data: dict[str, Any],
|
|
652
693
|
errors: list[str] | None,
|
|
653
694
|
logger: Logger | None) -> None:
|
|
654
695
|
"""
|
|
655
696
|
Submit a *POST* request to *url*.
|
|
656
697
|
|
|
657
698
|
:param header_data: the data to send in the header of the request
|
|
658
|
-
:param
|
|
699
|
+
:param json_data: the JSON data to send in the request
|
|
659
700
|
:param errors: incidental errors
|
|
660
701
|
:param logger: optional logger
|
|
661
702
|
"""
|
|
662
703
|
# log the POST
|
|
663
704
|
if logger:
|
|
664
|
-
logger.debug(msg=f"POST {url}, {json.dumps(obj=
|
|
705
|
+
logger.debug(msg=f"POST {url}, {json.dumps(obj=json_data,
|
|
665
706
|
ensure_ascii=False)}")
|
|
666
707
|
try:
|
|
667
708
|
response: requests.Response = requests.post(url=url,
|
|
668
709
|
headers=header_data,
|
|
669
|
-
|
|
710
|
+
json=json_data)
|
|
670
711
|
if response.status_code >= 400:
|
|
671
712
|
# request failed, report the problem
|
|
672
713
|
msg = f"POST failure, status {response.status_code}, reason {response.reason}"
|
|
@@ -839,6 +880,8 @@ def __validate_and_store(iam_server: IamServer,
|
|
|
839
880
|
# initialize the return variable
|
|
840
881
|
result: tuple[str, str] | None = None
|
|
841
882
|
|
|
883
|
+
if logger:
|
|
884
|
+
logger.debug(msg=f"Validating and storing the token")
|
|
842
885
|
with _iam_lock:
|
|
843
886
|
# retrieve the IAM server's registry
|
|
844
887
|
registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
|
pypomes_iam/iam_services.py
CHANGED
|
@@ -120,6 +120,7 @@ def service_login() -> Response:
|
|
|
120
120
|
These are the expected request parameters:
|
|
121
121
|
- user-id: optional, identifies the reference user (alias: 'login')
|
|
122
122
|
- redirect-uri: a parameter to be added to the query part of the returned URL
|
|
123
|
+
-target-idp: optionally, identify a target identity provider for the login operation
|
|
123
124
|
|
|
124
125
|
If provided, the user identification will be validated against the authorization data
|
|
125
126
|
returned by *iam_server* upon login. On success, the following JSON, containing the appropriate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_iam
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.6
|
|
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
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
pypomes_iam/__init__.py,sha256=_6tSFfjuU-5p6TAMqNLHSL6IQmaJMSYuEW-TG3ybhTI,1044
|
|
2
|
-
pypomes_iam/iam_actions.py,sha256=
|
|
2
|
+
pypomes_iam/iam_actions.py,sha256=zoxAzcw9fBTMEt-y5INaw7Wjfa1R5o-z_ORxvo4kqGU,45612
|
|
3
3
|
pypomes_iam/iam_common.py,sha256=ki_-m6fqJqUbGjgTD41r9zaE-FOXgA_c_tLisIYYTfU,15457
|
|
4
4
|
pypomes_iam/iam_pomes.py,sha256=_kLnrZG25XhJsIv3wqDl_2sIJ2ho_2TIMKrPCyPmA7Q,7362
|
|
5
|
-
pypomes_iam/iam_services.py,sha256=
|
|
5
|
+
pypomes_iam/iam_services.py,sha256=HFK_ihY1n7I4JGptAwV44MxHMPsGLDU5ElsaFOqUDcc,15915
|
|
6
6
|
pypomes_iam/provider_pomes.py,sha256=3mMj5LQs53YEINUEOfFBAxOwOP3aOR_szlE4daEBLK0,10523
|
|
7
7
|
pypomes_iam/token_pomes.py,sha256=K4nSAotKUoHIE2s3ltc_nVimlNeKS9tnD-IlslkAvkk,6626
|
|
8
|
-
pypomes_iam-0.7.
|
|
9
|
-
pypomes_iam-0.7.
|
|
10
|
-
pypomes_iam-0.7.
|
|
11
|
-
pypomes_iam-0.7.
|
|
8
|
+
pypomes_iam-0.7.6.dist-info/METADATA,sha256=b6eajrnQCM0TsdjAbz1H4xf9EgrGV0ii_phYm51nOQI,661
|
|
9
|
+
pypomes_iam-0.7.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
pypomes_iam-0.7.6.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
|
|
11
|
+
pypomes_iam-0.7.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|