pypomes-jwt 0.6.5__py3-none-any.whl → 0.6.7__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-jwt might be problematic. Click here for more details.
- pypomes_jwt/__init__.py +4 -4
- pypomes_jwt/jwt_data.py +13 -11
- pypomes_jwt/jwt_pomes.py +56 -60
- {pypomes_jwt-0.6.5.dist-info → pypomes_jwt-0.6.7.dist-info}/METADATA +1 -1
- pypomes_jwt-0.6.7.dist-info/RECORD +7 -0
- pypomes_jwt-0.6.5.dist-info/RECORD +0 -7
- {pypomes_jwt-0.6.5.dist-info → pypomes_jwt-0.6.7.dist-info}/WHEEL +0 -0
- {pypomes_jwt-0.6.5.dist-info → pypomes_jwt-0.6.7.dist-info}/licenses/LICENSE +0 -0
pypomes_jwt/__init__.py
CHANGED
|
@@ -5,8 +5,8 @@ from .jwt_pomes import (
|
|
|
5
5
|
JWT_ENDPOINT_URL,
|
|
6
6
|
JWT_ACCESS_MAX_AGE, JWT_REFRESH_MAX_AGE,
|
|
7
7
|
JWT_HS_SECRET_KEY, JWT_RSA_PRIVATE_KEY, JWT_RSA_PUBLIC_KEY,
|
|
8
|
-
jwt_needed, jwt_verify_request,
|
|
9
|
-
|
|
8
|
+
jwt_needed, jwt_verify_request, jwt_claims, jwt_token,
|
|
9
|
+
jwt_get_token_data, jwt_get_token_claims,
|
|
10
10
|
jwt_assert_access, jwt_set_access, jwt_remove_access
|
|
11
11
|
)
|
|
12
12
|
|
|
@@ -17,8 +17,8 @@ __all__ = [
|
|
|
17
17
|
"JWT_ENDPOINT_URL",
|
|
18
18
|
"JWT_ACCESS_MAX_AGE", "JWT_REFRESH_MAX_AGE",
|
|
19
19
|
"JWT_HS_SECRET_KEY", "JWT_RSA_PRIVATE_KEY", "JWT_RSA_PUBLIC_KEY",
|
|
20
|
-
"jwt_needed", "jwt_verify_request", "
|
|
21
|
-
"
|
|
20
|
+
"jwt_needed", "jwt_verify_request", "jwt_claims", "jwt_token",
|
|
21
|
+
"jwt_get_token_data", "jwt_get_token_claims",
|
|
22
22
|
"jwt_assert_access", "jwt_set_access", "jwt_remove_access"
|
|
23
23
|
]
|
|
24
24
|
|
pypomes_jwt/jwt_data.py
CHANGED
|
@@ -199,14 +199,14 @@ class JwtData:
|
|
|
199
199
|
result: dict[str, Any]
|
|
200
200
|
|
|
201
201
|
# obtain the item in storage
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
access_data: dict[str, Any] = self.get_access_data(account_id=account_id,
|
|
203
|
+
logger=logger)
|
|
204
204
|
# was the JWT data obtained ?
|
|
205
|
-
if
|
|
205
|
+
if access_data:
|
|
206
206
|
# yes, proceed
|
|
207
|
-
control_data: dict[str, Any] =
|
|
208
|
-
reserved_claims: dict[str, Any] =
|
|
209
|
-
custom_claims: dict[str, Any] =
|
|
207
|
+
control_data: dict[str, Any] = access_data.get("control-data")
|
|
208
|
+
reserved_claims: dict[str, Any] = access_data.get("reserved-claims")
|
|
209
|
+
custom_claims: dict[str, Any] = access_data.get("custom-claims")
|
|
210
210
|
if superceding_claims:
|
|
211
211
|
custom_claims = custom_claims.copy()
|
|
212
212
|
custom_claims.update(m=superceding_claims)
|
|
@@ -240,7 +240,7 @@ class JwtData:
|
|
|
240
240
|
raise RuntimeError(" - ".join(errors))
|
|
241
241
|
else:
|
|
242
242
|
# JWT service is being provided locally
|
|
243
|
-
claims: dict[str, Any] =
|
|
243
|
+
claims: dict[str, Any] = access_data.get("public-claims").copy()
|
|
244
244
|
claims.update(m=reserved_claims)
|
|
245
245
|
claims.update(m=custom_claims)
|
|
246
246
|
# may raise an exception
|
|
@@ -280,6 +280,7 @@ class JwtData:
|
|
|
280
280
|
:return: the token's claimset, or *None* if error
|
|
281
281
|
:raises InvalidTokenError: token is not valid
|
|
282
282
|
:raises ExpiredSignatureError: token has expired
|
|
283
|
+
:raises InvalidAlgorithmError: the specified algorithm is not recognized
|
|
283
284
|
"""
|
|
284
285
|
# declare the return variable
|
|
285
286
|
result: dict[str, Any]
|
|
@@ -287,14 +288,15 @@ class JwtData:
|
|
|
287
288
|
if logger:
|
|
288
289
|
logger.debug(msg=f"Retrieve claims for JWT token '{token}'")
|
|
289
290
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if
|
|
291
|
+
access_data: dict[str, Any] = self.get_access_data(access_token=token,
|
|
292
|
+
logger=logger)
|
|
293
|
+
if access_data:
|
|
294
|
+
control_data: dict[str, Any] = access_data.get("control-data")
|
|
293
295
|
if control_data.get("remote-provider"):
|
|
294
296
|
# provider is remote
|
|
295
297
|
result = control_data.get("custom-claims")
|
|
296
298
|
else:
|
|
297
|
-
# may raise
|
|
299
|
+
# may raise an exception
|
|
298
300
|
result = jwt.decode(jwt=token,
|
|
299
301
|
key=(control_data.get("hs-secret-key") or
|
|
300
302
|
control_data.get("rsa-public-key")),
|
pypomes_jwt/jwt_pomes.py
CHANGED
|
@@ -19,7 +19,6 @@ JWT_REFRESH_MAX_AGE: Final[int] = env_get_int(key=f"{APP_PREFIX}_JWT_REFRESH_MAX
|
|
|
19
19
|
def_value=43200)
|
|
20
20
|
JWT_HS_SECRET_KEY: Final[bytes] = env_get_bytes(key=f"{APP_PREFIX}_JWT_HS_SECRET_KEY",
|
|
21
21
|
def_value=token_bytes(nbytes=32))
|
|
22
|
-
# the endpoint must invoke 'jwt_service()' below
|
|
23
22
|
JWT_ENDPOINT_URL: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_ENDPOINT_URL")
|
|
24
23
|
|
|
25
24
|
# obtain a RSA private/public key pair
|
|
@@ -49,7 +48,7 @@ def jwt_needed(func: callable) -> callable:
|
|
|
49
48
|
"""
|
|
50
49
|
# ruff: noqa: ANN003
|
|
51
50
|
def wrapper(*args, **kwargs) -> Response:
|
|
52
|
-
response: Response = jwt_verify_request(request=request)
|
|
51
|
+
response: Response = jwt_verify_request(request=request)
|
|
53
52
|
return response if response else func(*args, **kwargs)
|
|
54
53
|
|
|
55
54
|
# prevent a rogue error ("View function mapping is overwriting an existing endpoint function")
|
|
@@ -137,42 +136,12 @@ def jwt_remove_access(account_id: str,
|
|
|
137
136
|
logger=logger)
|
|
138
137
|
|
|
139
138
|
|
|
140
|
-
def jwt_get_token(errors: list[str],
|
|
141
|
-
account_id: str,
|
|
142
|
-
logger: Logger = None) -> str:
|
|
143
|
-
"""
|
|
144
|
-
Obtain and return a JWT token for *account_id*.
|
|
145
|
-
|
|
146
|
-
:param errors: incidental error messages
|
|
147
|
-
:param account_id: the account identification
|
|
148
|
-
:param logger: optional logger
|
|
149
|
-
:return: the JWT token, or *None* if an error ocurred
|
|
150
|
-
"""
|
|
151
|
-
# inicialize the return variable
|
|
152
|
-
result: str | None = None
|
|
153
|
-
|
|
154
|
-
if logger:
|
|
155
|
-
logger.debug(msg=f"Obtain a JWT token for '{account_id}'")
|
|
156
|
-
|
|
157
|
-
try:
|
|
158
|
-
token_data: dict[str, Any] = __jwt_data.get_token_data(account_id=account_id,
|
|
159
|
-
logger=logger)
|
|
160
|
-
result = token_data.get("access_token")
|
|
161
|
-
if logger:
|
|
162
|
-
logger.debug(f"Token is '{result}'")
|
|
163
|
-
except Exception as e:
|
|
164
|
-
if logger:
|
|
165
|
-
logger.error(msg=str(e))
|
|
166
|
-
errors.append(str(e))
|
|
167
|
-
|
|
168
|
-
return result
|
|
169
|
-
|
|
170
|
-
|
|
171
139
|
def jwt_get_token_data(errors: list[str],
|
|
172
140
|
account_id: str,
|
|
141
|
+
superceding_claims: dict[str, Any] = None,
|
|
173
142
|
logger: Logger = None) -> dict[str, Any]:
|
|
174
143
|
"""
|
|
175
|
-
Obtain and return the JWT token associated with *account_id
|
|
144
|
+
Obtain and return the JWT token data associated with *account_id*.
|
|
176
145
|
|
|
177
146
|
Structure of the return data:
|
|
178
147
|
{
|
|
@@ -183,6 +152,7 @@ def jwt_get_token_data(errors: list[str],
|
|
|
183
152
|
|
|
184
153
|
:param errors: incidental error messages
|
|
185
154
|
:param account_id: the account identification
|
|
155
|
+
:param superceding_claims: if provided, may supercede registered custom claims
|
|
186
156
|
:param logger: optional logger
|
|
187
157
|
:return: the JWT token data, or *None* if error
|
|
188
158
|
"""
|
|
@@ -193,6 +163,7 @@ def jwt_get_token_data(errors: list[str],
|
|
|
193
163
|
logger.debug(msg=f"Retrieve JWT token data for '{account_id}'")
|
|
194
164
|
try:
|
|
195
165
|
result = __jwt_data.get_token_data(account_id=account_id,
|
|
166
|
+
superceding_claims=superceding_claims,
|
|
196
167
|
logger=logger)
|
|
197
168
|
if logger:
|
|
198
169
|
logger.debug(msg=f"Data is '{result}'")
|
|
@@ -213,7 +184,7 @@ def jwt_get_token_claims(errors: list[str],
|
|
|
213
184
|
:param errors: incidental error messages
|
|
214
185
|
:param token: the token to be inspected for claims
|
|
215
186
|
:param logger: optional logger
|
|
216
|
-
:return: the token's claimset, or
|
|
187
|
+
:return: the token's claimset, or *None* if error
|
|
217
188
|
"""
|
|
218
189
|
# initialize the return variable
|
|
219
190
|
result: dict[str, Any] | None = None
|
|
@@ -290,14 +261,54 @@ def jwt_verify_request(request: Request,
|
|
|
290
261
|
return result
|
|
291
262
|
|
|
292
263
|
|
|
293
|
-
def
|
|
294
|
-
|
|
295
|
-
|
|
264
|
+
def jwt_claims(token: str = None) -> Response:
|
|
265
|
+
"""
|
|
266
|
+
REST service entry point for retrieving the claims of a JWT token.
|
|
267
|
+
|
|
268
|
+
Structure of the return data:
|
|
269
|
+
{
|
|
270
|
+
"<claim-1>": <value-of-claim-1>,
|
|
271
|
+
...
|
|
272
|
+
"<claim-n>": <value-of-claim-n>
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
:param token: the JWT token
|
|
276
|
+
:return: a *Response* containing the requested JWT token claims, or reporting an error
|
|
277
|
+
"""
|
|
278
|
+
# declare the return variable
|
|
279
|
+
result: Response
|
|
280
|
+
|
|
281
|
+
# retrieve the token
|
|
282
|
+
# noinspection PyUnusedLocal
|
|
283
|
+
if not token:
|
|
284
|
+
token = request.values.get("token")
|
|
285
|
+
if not token:
|
|
286
|
+
with contextlib.suppress(Exception):
|
|
287
|
+
token = request.get_json().get("token")
|
|
288
|
+
|
|
289
|
+
# has the token been obtained ?
|
|
290
|
+
if token:
|
|
291
|
+
# yes, obtain the token data
|
|
292
|
+
try:
|
|
293
|
+
token_claims: dict[str, Any] = __jwt_data.get_token_claims(token=token)
|
|
294
|
+
result = jsonify(token_claims)
|
|
295
|
+
except Exception as e:
|
|
296
|
+
# claims extraction failed
|
|
297
|
+
result = Response(response=str(e),
|
|
298
|
+
status=400)
|
|
299
|
+
else:
|
|
300
|
+
# no, report the problem
|
|
301
|
+
result = Response(response="Invalid parameters",
|
|
302
|
+
status=400)
|
|
303
|
+
|
|
304
|
+
return result
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def jwt_token(service_params: dict[str, Any] = None) -> Response:
|
|
296
308
|
"""
|
|
297
|
-
|
|
309
|
+
REST service entry point for obtaining JWT tokens.
|
|
298
310
|
|
|
299
|
-
|
|
300
|
-
the invoker must send, as parameter *service_params* or in the body of the request:
|
|
311
|
+
The requester must send, as parameter *service_params* or in the body of the request:
|
|
301
312
|
{
|
|
302
313
|
"account-id": "<string>" - required account identification
|
|
303
314
|
"<custom-claim-key-1>": "<custom-claim-value-1>", - optional superceding custom claims
|
|
@@ -315,48 +326,33 @@ def jwt_service(account_id: str = None,
|
|
|
315
326
|
"expires_in": <seconds-to-expiration>
|
|
316
327
|
}
|
|
317
328
|
|
|
318
|
-
:param account_id: the account identification, alternatively passed in JSON
|
|
319
329
|
:param service_params: the optional JSON containing the request parameters (defaults to JSON in body)
|
|
320
|
-
:
|
|
321
|
-
:return: a *Response* containing the requested JWT token and its duration, or reporting an error
|
|
330
|
+
:return: a *Response* containing the requested JWT token data, or reporting an error
|
|
322
331
|
"""
|
|
323
332
|
# declare the return variable
|
|
324
333
|
result: Response
|
|
325
334
|
|
|
326
|
-
if logger:
|
|
327
|
-
logger.debug(msg="Service a JWT request")
|
|
328
|
-
|
|
329
335
|
# retrieve the parameters
|
|
330
336
|
# noinspection PyUnusedLocal
|
|
331
337
|
params: dict[str, Any] = service_params or {}
|
|
332
338
|
if not params:
|
|
333
339
|
with contextlib.suppress(Exception):
|
|
334
340
|
params = request.get_json()
|
|
335
|
-
|
|
336
|
-
account_id = params.pop("account-id", None)
|
|
341
|
+
account_id: str | None = params.pop("account-id", None)
|
|
337
342
|
|
|
338
343
|
# has the account been identified ?
|
|
339
344
|
if account_id:
|
|
340
|
-
# yes,
|
|
341
|
-
if logger:
|
|
342
|
-
logger.debug(msg=f"Account identification is '{account_id}'")
|
|
343
|
-
|
|
344
|
-
# obtain the token data
|
|
345
|
+
# yes, obtain the token data
|
|
345
346
|
try:
|
|
346
347
|
token_data: dict[str, Any] = __jwt_data.get_token_data(account_id=account_id,
|
|
347
|
-
superceding_claims=params
|
|
348
|
-
logger=logger)
|
|
348
|
+
superceding_claims=params)
|
|
349
349
|
result = jsonify(token_data)
|
|
350
350
|
except Exception as e:
|
|
351
351
|
# token validation failed
|
|
352
|
-
if logger:
|
|
353
|
-
logger.error(msg=str(e))
|
|
354
352
|
result = Response(response=str(e),
|
|
355
353
|
status=401)
|
|
356
354
|
else:
|
|
357
355
|
# no, report the problem
|
|
358
|
-
if logger:
|
|
359
|
-
logger.debug(msg=f"Invalid parameters {service_params}")
|
|
360
356
|
result = Response(response="Invalid parameters",
|
|
361
357
|
status=401)
|
|
362
358
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_jwt
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.7
|
|
4
4
|
Summary: A collection of Python pomes, penyeach (JWT module)
|
|
5
5
|
Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-JWT
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-JWT/issues
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
pypomes_jwt/__init__.py,sha256=CwpFtZEi1Yo1i4ulyR65yvo_fJpSRMJsXwzV75E3K0A,988
|
|
2
|
+
pypomes_jwt/jwt_data.py,sha256=icnNzfCBPN94z3saT_fhDSEpj_GGBeSW59ychNfkxA8,19680
|
|
3
|
+
pypomes_jwt/jwt_pomes.py,sha256=rhYoqD57yXayJoePdjbB3RfPAIg23o6YQKkdnD4tz0c,14222
|
|
4
|
+
pypomes_jwt-0.6.7.dist-info/METADATA,sha256=8j6R2ZgQXHbw7Wyziiv7BfGAQdlld2bGHcDL14ijpn4,599
|
|
5
|
+
pypomes_jwt-0.6.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
+
pypomes_jwt-0.6.7.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
7
|
+
pypomes_jwt-0.6.7.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
pypomes_jwt/__init__.py,sha256=m0USOMlGVUfofwukykKf6DAPq7CRn4SiY6CeNOOiqJ8,998
|
|
2
|
-
pypomes_jwt/jwt_data.py,sha256=skSwtbBemyanuWyngu0lq2Yw3-hONytt1AwXZpSlILg,19541
|
|
3
|
-
pypomes_jwt/jwt_pomes.py,sha256=pWYjCRKIcaG-yN64IgJ54L-YHw3Jhhnmsvb6xMipQsY,14515
|
|
4
|
-
pypomes_jwt-0.6.5.dist-info/METADATA,sha256=KZBLb8BEdIDaFQMoCxvkQ-ZBzIN97RaVXV49uAizNvo,599
|
|
5
|
-
pypomes_jwt-0.6.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
-
pypomes_jwt-0.6.5.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
7
|
-
pypomes_jwt-0.6.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|