pypomes-iam 0.3.4__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of pypomes-iam might be problematic. Click here for more details.
- pypomes_iam/iam_common.py +17 -104
- pypomes_iam/iam_pomes.py +325 -142
- pypomes_iam/iam_services.py +110 -71
- pypomes_iam/jusbr_pomes.py +23 -17
- pypomes_iam/keycloak_pomes.py +23 -17
- pypomes_iam/provider_pomes.py +66 -59
- pypomes_iam/token_pomes.py +1 -1
- {pypomes_iam-0.3.4.dist-info → pypomes_iam-0.3.6.dist-info}/METADATA +1 -1
- pypomes_iam-0.3.6.dist-info/RECORD +12 -0
- pypomes_iam-0.3.4.dist-info/RECORD +0 -12
- {pypomes_iam-0.3.4.dist-info → pypomes_iam-0.3.6.dist-info}/WHEEL +0 -0
- {pypomes_iam-0.3.4.dist-info → pypomes_iam-0.3.6.dist-info}/licenses/LICENSE +0 -0
pypomes_iam/iam_services.py
CHANGED
|
@@ -3,8 +3,14 @@ from flask import Request, Response, request, jsonify
|
|
|
3
3
|
from logging import Logger
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from .iam_common import
|
|
7
|
-
|
|
6
|
+
from .iam_common import (
|
|
7
|
+
IamServer, _iam_lock,
|
|
8
|
+
_get_logger, _get_iam_server
|
|
9
|
+
)
|
|
10
|
+
from .iam_pomes import (
|
|
11
|
+
user_login, user_logout,
|
|
12
|
+
user_token, token_exchange, login_callback
|
|
13
|
+
)
|
|
8
14
|
|
|
9
15
|
|
|
10
16
|
# @flask_app.route(rule=<login_endpoint>, # JUSBR_ENDPOINT_LOGIN
|
|
@@ -28,19 +34,20 @@ def service_login() -> Response:
|
|
|
28
34
|
# log the request
|
|
29
35
|
logger.debug(msg=_log_init(request=request))
|
|
30
36
|
|
|
31
|
-
# retrieve the IAM server
|
|
32
37
|
errors: list[str] = []
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
with _iam_lock:
|
|
39
|
+
# retrieve the IAM server
|
|
40
|
+
iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
|
|
41
|
+
errors=errors,
|
|
42
|
+
logger=logger)
|
|
43
|
+
if iam_server:
|
|
44
|
+
# obtain the login URL
|
|
45
|
+
login_data: dict[str, str] = user_login(iam_server=iam_server,
|
|
46
|
+
args=request.args,
|
|
47
|
+
errors=errors,
|
|
48
|
+
logger=logger)
|
|
49
|
+
if login_data:
|
|
50
|
+
result = jsonify(login_data)
|
|
44
51
|
|
|
45
52
|
if errors:
|
|
46
53
|
result = Response("; ".join(errors))
|
|
@@ -74,17 +81,18 @@ def service_logout() -> Response:
|
|
|
74
81
|
# log the request
|
|
75
82
|
logger.debug(msg=_log_init(request=request))
|
|
76
83
|
|
|
77
|
-
# retrieve the IAM server
|
|
78
84
|
errors: list[str] = []
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
with _iam_lock:
|
|
86
|
+
# retrieve the IAM server
|
|
87
|
+
iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
|
|
88
|
+
errors=errors,
|
|
89
|
+
logger=logger)
|
|
90
|
+
if iam_server:
|
|
91
|
+
# logout the user
|
|
92
|
+
user_logout(iam_server=iam_server,
|
|
93
|
+
args=request.args,
|
|
94
|
+
errors=errors,
|
|
95
|
+
logger=logger)
|
|
88
96
|
if errors:
|
|
89
97
|
result = Response("; ".join(errors))
|
|
90
98
|
result.status_code = 400
|
|
@@ -106,10 +114,11 @@ def service_callback() -> Response:
|
|
|
106
114
|
"""
|
|
107
115
|
Entry point for the callback from JusBR on authentication operation.
|
|
108
116
|
|
|
109
|
-
This callback is
|
|
110
|
-
|
|
117
|
+
This callback is invoked from a front-end application after a successful login at the
|
|
118
|
+
*IAM* server's login page, forwarding the data received. In a typical OAuth2 flow faction,
|
|
119
|
+
this data is then used to effectively obtain the token from the *IAM* server.
|
|
111
120
|
|
|
112
|
-
:return: the
|
|
121
|
+
:return: the *Response* containing the reference user identification and the token, or *BAD REQUEST*
|
|
113
122
|
"""
|
|
114
123
|
# retrieve the operations's logger
|
|
115
124
|
logger: Logger = _get_logger()
|
|
@@ -117,18 +126,19 @@ def service_callback() -> Response:
|
|
|
117
126
|
# log the request
|
|
118
127
|
logger.debug(msg=_log_init(request=request))
|
|
119
128
|
|
|
120
|
-
# retrieve the IAM server
|
|
121
129
|
errors: list[str] = []
|
|
122
130
|
token_data: tuple[str, str] | None = None
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
with _iam_lock:
|
|
132
|
+
# retrieve the IAM server
|
|
133
|
+
iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
|
|
134
|
+
errors=errors,
|
|
135
|
+
logger=logger)
|
|
136
|
+
if iam_server:
|
|
137
|
+
# process the callback operation
|
|
138
|
+
token_data = login_callback(iam_server=iam_server,
|
|
139
|
+
args=request.args,
|
|
140
|
+
errors=errors,
|
|
141
|
+
logger=logger)
|
|
132
142
|
result: Response
|
|
133
143
|
if errors:
|
|
134
144
|
result = jsonify({"errors": "; ".join(errors)})
|
|
@@ -136,10 +146,8 @@ def service_callback() -> Response:
|
|
|
136
146
|
if logger:
|
|
137
147
|
logger.error(msg=json.dumps(obj=result))
|
|
138
148
|
else:
|
|
139
|
-
result = jsonify({
|
|
140
|
-
|
|
141
|
-
"access-token": token_data[1]})
|
|
142
|
-
|
|
149
|
+
result = jsonify({"user-id": token_data[0],
|
|
150
|
+
"access-token": token_data[1]})
|
|
143
151
|
# log the response
|
|
144
152
|
if logger:
|
|
145
153
|
logger.debug(msg=f"Response {result}")
|
|
@@ -148,14 +156,14 @@ def service_callback() -> Response:
|
|
|
148
156
|
|
|
149
157
|
|
|
150
158
|
# @flask_app.route(rule=<token_endpoint>, # JUSBR_ENDPOINT_TOKEN
|
|
151
|
-
# @flask_app.route(rule=<token_endpoint>, # KEYCLOAK_ENDPOINT_TOKEN
|
|
152
159
|
# methods=["GET"])
|
|
160
|
+
# @flask_app.route(rule=<token_endpoint>, # KEYCLOAK_ENDPOINT_TOKEN
|
|
153
161
|
# methods=["GET"])
|
|
154
162
|
def service_token() -> Response:
|
|
155
163
|
"""
|
|
156
|
-
Entry point for retrieving token from the *IAM* server.
|
|
164
|
+
Entry point for retrieving a token from the *IAM* server.
|
|
157
165
|
|
|
158
|
-
:return: the
|
|
166
|
+
:return: the *Response* containing the user reference identification and the token, or *BAD REQUEST*
|
|
159
167
|
"""
|
|
160
168
|
# retrieve the operations's logger
|
|
161
169
|
logger: Logger = _get_logger()
|
|
@@ -163,26 +171,38 @@ def service_token() -> Response:
|
|
|
163
171
|
# log the request
|
|
164
172
|
logger.debug(msg=_log_init(request=request))
|
|
165
173
|
|
|
166
|
-
#
|
|
174
|
+
# obtain the user's identification
|
|
175
|
+
args: dict[str, Any] = request.args
|
|
176
|
+
user_id: str = args.get("user-id") or args.get("user_id") or args.get("login")
|
|
177
|
+
|
|
167
178
|
errors: list[str] = []
|
|
168
|
-
iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
|
|
169
|
-
errors=errors,
|
|
170
|
-
logger=logger)
|
|
171
|
-
# retrieve the token
|
|
172
179
|
token: str | None = None
|
|
173
|
-
if
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
if user_id:
|
|
181
|
+
with _iam_lock:
|
|
182
|
+
# retrieve the IAM server
|
|
183
|
+
iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
|
|
184
|
+
errors=errors,
|
|
185
|
+
logger=logger)
|
|
186
|
+
if iam_server:
|
|
187
|
+
# retrieve the token
|
|
188
|
+
errors: list[str] = []
|
|
189
|
+
token: str = user_token(iam_server=iam_server,
|
|
190
|
+
args=args,
|
|
191
|
+
errors=errors,
|
|
192
|
+
logger=logger)
|
|
193
|
+
else:
|
|
194
|
+
msg: str = "User identification not provided"
|
|
195
|
+
errors.append(msg)
|
|
196
|
+
if logger:
|
|
197
|
+
logger.error(msg=msg)
|
|
198
|
+
|
|
179
199
|
result: Response
|
|
180
200
|
if errors:
|
|
181
201
|
result = Response("; ".join(errors))
|
|
182
202
|
result.status_code = 400
|
|
183
203
|
else:
|
|
184
|
-
result = jsonify({"
|
|
185
|
-
|
|
204
|
+
result = jsonify({"user-id": user_id,
|
|
205
|
+
"token": token})
|
|
186
206
|
# log the response
|
|
187
207
|
if logger:
|
|
188
208
|
logger.debug(msg=f"Response {result}")
|
|
@@ -196,26 +216,45 @@ def service_exchange() -> Response:
|
|
|
196
216
|
"""
|
|
197
217
|
Entry point for requesting the *IAM* server to exchange the token.
|
|
198
218
|
|
|
199
|
-
This is currently
|
|
219
|
+
This is currently limited to the *KEYCLOAK* server. The token itself is stored in *KEYCLOAK*'s registry.
|
|
220
|
+
The expected parameters in the request are:
|
|
221
|
+
- client-id: identification for the reference user (aliases: 'client_id', 'login')
|
|
222
|
+
- token: the token to be exchanged
|
|
223
|
+
|
|
224
|
+
If the exchange is successful, the token data is stored in the *IAM* server's registry, and returned.
|
|
225
|
+
Otherwise, *errors* will contain the appropriate error message.
|
|
226
|
+
|
|
227
|
+
The typical *Response* returned contains the following attributes:
|
|
228
|
+
{
|
|
229
|
+
"token_type": "Bearer",
|
|
230
|
+
"access_token": <str>,
|
|
231
|
+
"expires_in": <number-of-seconds>,
|
|
232
|
+
"refresh_token": <str>,
|
|
233
|
+
"refesh_expires_in": <number-of-seconds>
|
|
234
|
+
}
|
|
200
235
|
|
|
201
|
-
:return: the
|
|
236
|
+
:return: the *Response* containing the token data, or *UNAUTHORIZED*
|
|
202
237
|
"""
|
|
203
238
|
# retrieve the operations's logger
|
|
204
239
|
logger: Logger = _get_logger()
|
|
240
|
+
if logger:
|
|
241
|
+
# log the request
|
|
242
|
+
logger.debug(msg=_log_init(request=request))
|
|
205
243
|
|
|
206
|
-
# retrieve the IAM server (currently, only 'Keycloak' is supported)
|
|
207
244
|
errors: list[str] = []
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
245
|
+
with _iam_lock:
|
|
246
|
+
# retrieve the IAM server (currently, only 'IAM_KEYCLOAK' is supported)
|
|
247
|
+
iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
|
|
248
|
+
errors=errors,
|
|
249
|
+
logger=logger)
|
|
250
|
+
# exchange the token
|
|
251
|
+
token_data: dict[str, Any] | None = None
|
|
252
|
+
if iam_server:
|
|
253
|
+
errors: list[str] = []
|
|
254
|
+
token_data = token_exchange(iam_server=iam_server,
|
|
255
|
+
args=request.args,
|
|
256
|
+
errors=errors,
|
|
257
|
+
logger=logger)
|
|
219
258
|
result: Response
|
|
220
259
|
if errors:
|
|
221
260
|
result = Response("; ".join(errors))
|
pypomes_iam/jusbr_pomes.py
CHANGED
|
@@ -7,7 +7,7 @@ from pypomes_core import (
|
|
|
7
7
|
)
|
|
8
8
|
from typing import Any, Final
|
|
9
9
|
|
|
10
|
-
from .iam_common import _IAM_SERVERS, IamServer
|
|
10
|
+
from .iam_common import _IAM_SERVERS, IamServer, _iam_lock
|
|
11
11
|
from .iam_pomes import user_token
|
|
12
12
|
|
|
13
13
|
JUSBR_CLIENT_ID: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_CLIENT_ID")
|
|
@@ -65,18 +65,19 @@ def jusbr_setup(flask_app: Flask,
|
|
|
65
65
|
# configure the JusBR registry
|
|
66
66
|
cache: Cache = FIFOCache(maxsize=1048576)
|
|
67
67
|
cache["users"] = {}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
with _iam_lock:
|
|
69
|
+
_IAM_SERVERS[IamServer.IAM_JUSRBR] = {
|
|
70
|
+
"client-id": client_id,
|
|
71
|
+
"client-secret": client_secret,
|
|
72
|
+
"client-timeout": client_timeout,
|
|
73
|
+
"recipient-attr": recipient_attribute,
|
|
74
|
+
"base-url": base_url,
|
|
75
|
+
"pk-expiration": sys.maxsize,
|
|
76
|
+
"pk-lifetime": public_key_lifetime,
|
|
77
|
+
"cache": cache,
|
|
78
|
+
"logger": logger,
|
|
79
|
+
"redirect-uri": None
|
|
80
|
+
}
|
|
80
81
|
|
|
81
82
|
# establish the endpoints
|
|
82
83
|
if login_endpoint:
|
|
@@ -112,9 +113,14 @@ def jusbr_get_token(user_id: str,
|
|
|
112
113
|
:param logger: optional logger
|
|
113
114
|
:return: the uthentication tokem
|
|
114
115
|
"""
|
|
116
|
+
# declare the return variable
|
|
117
|
+
result: str
|
|
118
|
+
|
|
115
119
|
# retrieve the token
|
|
116
120
|
args: dict[str, Any] = {"user-id": user_id}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
with _iam_lock:
|
|
122
|
+
result = user_token(iam_server=IamServer.IAM_JUSRBR,
|
|
123
|
+
args=args,
|
|
124
|
+
errors=errors,
|
|
125
|
+
logger=logger)
|
|
126
|
+
return result
|
pypomes_iam/keycloak_pomes.py
CHANGED
|
@@ -7,7 +7,7 @@ from pypomes_core import (
|
|
|
7
7
|
)
|
|
8
8
|
from typing import Any, Final
|
|
9
9
|
|
|
10
|
-
from .iam_common import _IAM_SERVERS, IamServer
|
|
10
|
+
from .iam_common import _IAM_SERVERS, IamServer, _iam_lock
|
|
11
11
|
from .iam_pomes import user_token
|
|
12
12
|
|
|
13
13
|
KEYCLOAK_CLIENT_ID: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_CLIENT_ID")
|
|
@@ -74,18 +74,19 @@ def keycloak_setup(flask_app: Flask,
|
|
|
74
74
|
# configure the Keycloak registry
|
|
75
75
|
cache: Cache = FIFOCache(maxsize=1048576)
|
|
76
76
|
cache["users"] = {}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
with _iam_lock:
|
|
78
|
+
_IAM_SERVERS[IamServer.IAM_KEYCLOAK] = {
|
|
79
|
+
"client-id": client_id,
|
|
80
|
+
"client-secret": client_secret,
|
|
81
|
+
"client-timeout": client_timeout,
|
|
82
|
+
"recipient-attr": recipient_attribute,
|
|
83
|
+
"base-url": f"{base_url}/realms/{realm}",
|
|
84
|
+
"pk-expiration": sys.maxsize,
|
|
85
|
+
"pk-lifetime": public_key_lifetime,
|
|
86
|
+
"cache": cache,
|
|
87
|
+
"logger": logger,
|
|
88
|
+
"redirect-uri": None
|
|
89
|
+
}
|
|
89
90
|
|
|
90
91
|
# establish the endpoints
|
|
91
92
|
if login_endpoint:
|
|
@@ -126,9 +127,14 @@ def keycloak_get_token(user_id: str,
|
|
|
126
127
|
:param logger: optional logger
|
|
127
128
|
:return: the uthentication tokem
|
|
128
129
|
"""
|
|
130
|
+
# declare the return variable
|
|
131
|
+
result: str
|
|
132
|
+
|
|
129
133
|
# retrieve the token
|
|
130
134
|
args: dict[str, Any] = {"user-id": user_id}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
with _iam_lock:
|
|
136
|
+
result = user_token(iam_server=IamServer.IAM_KEYCLOAK,
|
|
137
|
+
args=args,
|
|
138
|
+
errors=errors,
|
|
139
|
+
logger=logger)
|
|
140
|
+
return result
|
pypomes_iam/provider_pomes.py
CHANGED
|
@@ -4,7 +4,8 @@ from base64 import b64encode
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from logging import Logger
|
|
6
6
|
from pypomes_core import TZ_LOCAL, exc_format
|
|
7
|
-
from
|
|
7
|
+
from threading import Lock
|
|
8
|
+
from typing import Any, Final
|
|
8
9
|
|
|
9
10
|
# structure:
|
|
10
11
|
# {
|
|
@@ -19,7 +20,11 @@ from typing import Any
|
|
|
19
20
|
# "expiration": <timestamp>
|
|
20
21
|
# }
|
|
21
22
|
# }
|
|
22
|
-
_provider_registry: dict[str, dict[str, Any]] = {}
|
|
23
|
+
_provider_registry: Final[dict[str, dict[str, Any]]] = {}
|
|
24
|
+
|
|
25
|
+
# the lock protecting the data in '_provider_registry'
|
|
26
|
+
# (because it is 'Final' and set at declaration time, it can be accessed through simple imports)
|
|
27
|
+
_provider_lock: Final[Lock] = Lock()
|
|
23
28
|
|
|
24
29
|
|
|
25
30
|
def provider_register(provider_id: str,
|
|
@@ -48,18 +53,19 @@ def provider_register(provider_id: str,
|
|
|
48
53
|
:param headers_data: optional key-value pairs to be added to the request headers
|
|
49
54
|
:param body_data: optional key-value pairs to be added to the request body
|
|
50
55
|
"""
|
|
51
|
-
global _provider_registry
|
|
56
|
+
global _provider_registry
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
with _provider_lock:
|
|
59
|
+
_provider_registry[provider_id] = {
|
|
60
|
+
"url": auth_url,
|
|
61
|
+
"user": auth_user,
|
|
62
|
+
"pwd": auth_pwd,
|
|
63
|
+
"custom-auth": custom_auth,
|
|
64
|
+
"headers-data": headers_data,
|
|
65
|
+
"body-data": body_data,
|
|
66
|
+
"token": None,
|
|
67
|
+
"expiration": datetime.now(tz=TZ_LOCAL).timestamp()
|
|
68
|
+
}
|
|
63
69
|
|
|
64
70
|
|
|
65
71
|
def provider_get_token(provider_id: str,
|
|
@@ -78,53 +84,54 @@ def provider_get_token(provider_id: str,
|
|
|
78
84
|
result: str | None = None
|
|
79
85
|
|
|
80
86
|
err_msg: str | None = None
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
enc_bytes: bytes = b64encode(f"{user}:{pwd}".encode())
|
|
95
|
-
headers_data["Authorization"] = f"Basic {enc_bytes.decode()}"
|
|
96
|
-
url: str = provider.get("url")
|
|
97
|
-
try:
|
|
98
|
-
# typical return on a token request:
|
|
99
|
-
# {
|
|
100
|
-
# "token_type": "Bearer",
|
|
101
|
-
# "access_token": <str>,
|
|
102
|
-
# "expires_in": <number-of-seconds>,
|
|
103
|
-
# optional data:
|
|
104
|
-
# "refresh_token": <str>,
|
|
105
|
-
# "refresh_expires_in": <number-of-seconds>
|
|
106
|
-
# }
|
|
107
|
-
response: requests.Response = requests.post(url=url,
|
|
108
|
-
data=body_data,
|
|
109
|
-
headers=headers_data,
|
|
110
|
-
timeout=None)
|
|
111
|
-
if response.status_code < 200 or response.status_code >= 300:
|
|
112
|
-
# request resulted in error, report the problem
|
|
113
|
-
err_msg = (f"POST '{url}': failed, "
|
|
114
|
-
f"status {response.status_code}, reason '{response.reason}'")
|
|
87
|
+
with _provider_lock:
|
|
88
|
+
provider: dict[str, Any] = _provider_registry.get(provider_id)
|
|
89
|
+
if provider:
|
|
90
|
+
now: float = datetime.now(tz=TZ_LOCAL).timestamp()
|
|
91
|
+
if now > provider.get("expiration"):
|
|
92
|
+
user: str = provider.get("user")
|
|
93
|
+
pwd: str = provider.get("pwd")
|
|
94
|
+
headers_data: dict[str, str] = provider.get("headers-data") or {}
|
|
95
|
+
body_data: dict[str, str] = provider.get("body-data") or {}
|
|
96
|
+
custom_auth: tuple[str, str] = provider.get("custom-auth")
|
|
97
|
+
if custom_auth:
|
|
98
|
+
body_data[custom_auth[0]] = user
|
|
99
|
+
body_data[custom_auth[1]] = pwd
|
|
115
100
|
else:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
101
|
+
enc_bytes: bytes = b64encode(f"{user}:{pwd}".encode())
|
|
102
|
+
headers_data["Authorization"] = f"Basic {enc_bytes.decode()}"
|
|
103
|
+
url: str = provider.get("url")
|
|
104
|
+
try:
|
|
105
|
+
# typical return on a token request:
|
|
106
|
+
# {
|
|
107
|
+
# "token_type": "Bearer",
|
|
108
|
+
# "access_token": <str>,
|
|
109
|
+
# "expires_in": <number-of-seconds>,
|
|
110
|
+
# optional data:
|
|
111
|
+
# "refresh_token": <str>,
|
|
112
|
+
# "refresh_expires_in": <number-of-seconds>
|
|
113
|
+
# }
|
|
114
|
+
response: requests.Response = requests.post(url=url,
|
|
115
|
+
data=body_data,
|
|
116
|
+
headers=headers_data,
|
|
117
|
+
timeout=None)
|
|
118
|
+
if response.status_code < 200 or response.status_code >= 300:
|
|
119
|
+
# request resulted in error, report the problem
|
|
120
|
+
err_msg = (f"POST '{url}': failed, "
|
|
121
|
+
f"status {response.status_code}, reason '{response.reason}'")
|
|
122
|
+
else:
|
|
123
|
+
reply: dict[str, Any] = response.json()
|
|
124
|
+
provider["token"] = reply.get("access_token")
|
|
125
|
+
provider["expiration"] = now + int(reply.get("expires_in"))
|
|
126
|
+
if logger:
|
|
127
|
+
logger.debug(msg=f"POST '{url}': status {response.status_code}")
|
|
128
|
+
except Exception as e:
|
|
129
|
+
# the operation raised an exception
|
|
130
|
+
err_msg = exc_format(exc=e,
|
|
131
|
+
exc_info=sys.exc_info())
|
|
132
|
+
err_msg = f"POST '{url}': error, '{err_msg}'"
|
|
133
|
+
else:
|
|
134
|
+
err_msg: str = f"Provider '{provider_id}' not registered"
|
|
128
135
|
|
|
129
136
|
if err_msg:
|
|
130
137
|
if isinstance(errors, list):
|
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.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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pypomes_iam/__init__.py,sha256=H7rUCaUEJBLNJv2rtdmBxwcAB28OItdEPenpv_UEOVw,965
|
|
2
|
+
pypomes_iam/iam_common.py,sha256=f74FUDcnMM2cgzJg-AF17GwCKwbfoezS8LppwxYwPys,10049
|
|
3
|
+
pypomes_iam/iam_pomes.py,sha256=gvDpgff6arB4_Y8AAf6QH2CEWRmdy-kcnQLyD0hx4Y4,23966
|
|
4
|
+
pypomes_iam/iam_services.py,sha256=Ae_hLz5luRjK-l_rhBcuuY03Ov7n7o67UYgBb5rbBys,10002
|
|
5
|
+
pypomes_iam/jusbr_pomes.py,sha256=0qbjJ6EGnlx17K-4Lqh5XkfH58y0joVZiD6HykbwpoE,5823
|
|
6
|
+
pypomes_iam/keycloak_pomes.py,sha256=5ZfpncofF20C1IB5ndO31vfrvfa8Ffy7FJxkGoKKoQQ,6836
|
|
7
|
+
pypomes_iam/provider_pomes.py,sha256=3Rui68hmj8zwY0tnw4aWurz-yQ-niacJFQpi6nWzh-M,6355
|
|
8
|
+
pypomes_iam/token_pomes.py,sha256=1g6PMNNMbmdwLrsvSXvpO8-zdRhso1IFnwAyndNmV4Q,5332
|
|
9
|
+
pypomes_iam-0.3.6.dist-info/METADATA,sha256=q53TFkBnU4mUAZgsJ_r_730kASXLiIyCwW_5mkFz8TU,694
|
|
10
|
+
pypomes_iam-0.3.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
+
pypomes_iam-0.3.6.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
|
|
12
|
+
pypomes_iam-0.3.6.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
pypomes_iam/__init__.py,sha256=H7rUCaUEJBLNJv2rtdmBxwcAB28OItdEPenpv_UEOVw,965
|
|
2
|
-
pypomes_iam/iam_common.py,sha256=IWH9DVykF7K-Z9Sn3oP7To9_I2TkO2AzjVod238zUWc,13645
|
|
3
|
-
pypomes_iam/iam_pomes.py,sha256=g06NSz3r1qv4LzDpjQ9iozdVyabidt7qLEocQRv1yns,15230
|
|
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.4.dist-info/METADATA,sha256=wt98InTB4_MY_-JQHDs9ZTZ1hb2T5MbJtAkduCUopNo,694
|
|
10
|
-
pypomes_iam-0.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
-
pypomes_iam-0.3.4.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
|
|
12
|
-
pypomes_iam-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|