pypomes-jwt 1.0.3__py3-none-any.whl → 1.0.4__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/jwt_pomes.py CHANGED
@@ -4,7 +4,9 @@ from base64 import urlsafe_b64decode
4
4
  from flask import Request, Response, request
5
5
  from logging import Logger
6
6
  from pypomes_core import exc_format
7
- from pypomes_db import db_select, db_delete
7
+ from pypomes_db import (
8
+ db_connect, db_commit, db_rollback, db_select, db_delete
9
+ )
8
10
  from typing import Any
9
11
 
10
12
  from . import (
@@ -436,21 +438,57 @@ def jwt_refresh_tokens(errors: list[str] | None,
436
438
  # assert the refresh token
437
439
  if refresh_token:
438
440
  # is the refresh token valid ?
439
- account_claims = (jwt_validate_token(errors=op_errors,
440
- token=refresh_token,
441
- nature="R",
442
- account_id=account_id,
443
- logger=logger) or {}).get("payload")
444
- # if it is, revoke current refresh token
445
- if account_claims and jwt_revoke_token(errors=op_errors,
446
- account_id=account_id,
447
- token=refresh_token,
448
- logger=logger):
449
- # issue tokens
450
- result = jwt_issue_tokens(errors=op_errors,
451
- account_id=account_id,
452
- account_claims=account_claims,
441
+ token_claims: dict[str, Any] = jwt_validate_token(errors=op_errors,
442
+ token=refresh_token,
443
+ nature="R",
444
+ account_id=account_id,
445
+ logger=logger)
446
+ if token_claims:
447
+ # yes, proceed
448
+ token_kid: str = token_claims["header"].get("kid")
449
+
450
+ # start the database transaction
451
+ db_conn: Any = db_connect(errors=op_errors,
452
+ autocommit=False,
453
453
  logger=logger)
454
+ if db_conn:
455
+ # delete current refresh token
456
+ db_delete(errors=op_errors,
457
+ delete_stmt=f"DELETE FROM {JWT_DB_TABLE}",
458
+ where_data={
459
+ JWT_DB_COL_KID: int(token_kid[1:]),
460
+ JWT_DB_COL_ACCOUNT: account_id
461
+ },
462
+ connection=db_conn,
463
+ committable=False,
464
+ logger=logger)
465
+
466
+ # issue the token pair
467
+ if not op_errors:
468
+ try:
469
+ result = __jwt_registry.issue_tokens(account_id=account_id,
470
+ account_claims=token_claims.get("payload"),
471
+ db_conn=db_conn,
472
+ logger=logger)
473
+ if logger:
474
+ logger.debug(msg=f"Token pair was refreshed for account '{account_id}'")
475
+ except Exception as e:
476
+ # token issuing failed
477
+ exc_err: str = exc_format(exc=e,
478
+ exc_info=sys.exc_info())
479
+ if logger:
480
+ logger.error(msg=f"Error refreshing the token pair: {exc_err}")
481
+ op_errors.append(exc_err)
482
+
483
+ # conclude the transaction
484
+ if op_errors:
485
+ db_rollback(errors=op_errors,
486
+ connection=db_conn,
487
+ logger=logger)
488
+ else:
489
+ db_commit(errors=op_errors,
490
+ connection=db_conn,
491
+ logger=logger)
454
492
  else:
455
493
  # refresh token not found
456
494
  op_errors.append("Refresh token was not provided")
@@ -470,7 +508,8 @@ def jwt_get_claims(errors: list[str] | None,
470
508
  """
471
509
  Retrieve and return the claims set of a JWT *token*.
472
510
 
473
- Any valid JWT token may be provided in *token*, as this operation is not restricted to locally issued tokens.
511
+ Any well-constructed JWT token may be provided in *token*, as this operation is not restricted to
512
+ locally issued tokens. Note that neither the token's signature nor its expiration is verified.
474
513
 
475
514
  Structure of the returned data, for locally issued tokens:
476
515
  {
@@ -6,7 +6,8 @@ from datetime import datetime, timezone
6
6
  from logging import Logger
7
7
  from pypomes_core import str_random
8
8
  from pypomes_db import (
9
- db_connect, db_commit, db_select, db_insert, db_update, db_delete
9
+ db_connect, db_commit, db_rollback,
10
+ db_select, db_insert, db_update, db_delete
10
11
  )
11
12
  from threading import Lock
12
13
  from typing import Any
@@ -225,6 +226,7 @@ class JwtRegistry:
225
226
  def issue_tokens(self,
226
227
  account_id: str,
227
228
  account_claims: dict[str, Any] = None,
229
+ db_conn: Any = None,
228
230
  logger: Logger = None) -> dict[str, Any]:
229
231
  """
230
232
  Issue and return a JWT token pair associated with *account_id*.
@@ -232,6 +234,9 @@ class JwtRegistry:
232
234
  These claims are ignored, if specified in *account_claims*: *iat*, *exp*, *jti*, *nbf*, and *sub*.
233
235
  Other claims specified therein may supercede registered account-related claims.
234
236
 
237
+ If provided, *db_conn* indicates that this operation is part of a larger database transaction.
238
+ Otherwise, the database transaction's scope is limited to this operation.
239
+
235
240
  Structure of the return data:
236
241
  {
237
242
  "access-token": <jwt-token>,
@@ -242,6 +247,7 @@ class JwtRegistry:
242
247
 
243
248
  :param account_id: the account identification
244
249
  :param account_claims: if provided, may supercede registered account-related claims
250
+ :param db_conn: if provided, indicates that this operation is part of a larger database transaction
245
251
  :param logger: optional logger
246
252
  :return: the JWT token data
247
253
  :raises RuntimeError: invalid account id, or error accessing the token database
@@ -277,31 +283,41 @@ class JwtRegistry:
277
283
  key=JWT_ENCODING_KEY,
278
284
  algorithm=JWT_DEFAULT_ALGORITHM,
279
285
  headers={"kid": "R0"})
280
- # obtain a DB connection
281
- db_conn: Any = db_connect(errors=errors,
282
- logger=logger)
283
- # persist the candidate token (may raise an exception)
284
- token_id: int = _jwt_persist_token(account_id=account_id,
285
- jwt_token=refresh_token,
286
- db_conn=db_conn,
287
- logger=logger)
288
- # issue the definitive refresh token
289
- refresh_token = jwt.encode(payload=current_claims,
290
- key=JWT_ENCODING_KEY,
291
- algorithm=JWT_DEFAULT_ALGORITHM,
292
- headers={"kid": f"R{token_id}"})
293
- # persist it
294
- db_update(errors=errors,
295
- update_stmt=f"UPDATE {JWT_DB_TABLE}",
296
- update_data={JWT_DB_COL_TOKEN: refresh_token},
297
- where_data={JWT_DB_COL_KID: token_id},
298
- connection=db_conn,
299
- logger=logger)
300
- # commit the transaction
301
- if not errors:
302
- db_commit(errors=errors,
303
- connection=db_conn,
286
+
287
+ # make sure to have a database connection
288
+ curr_conn: Any = db_conn or db_connect(errors=errors,
289
+ autocommit=False,
290
+ logger=logger)
291
+ if curr_conn:
292
+ # persist the candidate token (may raise an exception)
293
+ token_id: int = _jwt_persist_token(account_id=account_id,
294
+ jwt_token=refresh_token,
295
+ db_conn=curr_conn,
296
+ logger=logger)
297
+ # issue the definitive refresh token
298
+ refresh_token = jwt.encode(payload=current_claims,
299
+ key=JWT_ENCODING_KEY,
300
+ algorithm=JWT_DEFAULT_ALGORITHM,
301
+ headers={"kid": f"R{token_id}"})
302
+ # persist it
303
+ db_update(errors=errors,
304
+ update_stmt=f"UPDATE {JWT_DB_TABLE}",
305
+ update_data={JWT_DB_COL_TOKEN: refresh_token},
306
+ where_data={JWT_DB_COL_KID: token_id},
307
+ connection=curr_conn,
308
+ committable=False,
304
309
  logger=logger)
310
+
311
+ # conclude the transaction
312
+ if not db_conn:
313
+ if errors:
314
+ db_rollback(errors=errors,
315
+ connection=curr_conn,
316
+ logger=logger)
317
+ else:
318
+ db_commit(errors=errors,
319
+ connection=curr_conn,
320
+ logger=logger)
305
321
  if errors:
306
322
  raise RuntimeError("; ".join(errors))
307
323
 
@@ -343,7 +359,7 @@ class JwtRegistry:
343
359
 
344
360
  def _jwt_persist_token(account_id: str,
345
361
  jwt_token: str,
346
- db_conn: Any = None,
362
+ db_conn: Any,
347
363
  logger: Logger = None) -> int:
348
364
  """
349
365
  Persist the given token, making sure that the account limit is adhered to.
@@ -352,8 +368,7 @@ def _jwt_persist_token(account_id: str,
352
368
  If a token's expiration timestamp is in the past, it is removed from storage. If the maximum number
353
369
  of active tokens for *account_id* has been reached, the oldest active one is alse removed,
354
370
  to make room for the new *jwt_token*.
355
-
356
- If *db_conn* is provided, then all DB operations will be carried out in the scope of a single transaction.
371
+ The provided database connection *db_conn* indicates that this operation is part of a larger transaction.
357
372
 
358
373
  :param account_id: the account identification
359
374
  :param jwt_token: the JWT token to persist
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypomes_jwt
3
- Version: 1.0.3
3
+ Version: 1.0.4
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,8 @@
1
+ pypomes_jwt/__init__.py,sha256=fLr_M8yXlcmSTNPMdJOJQlMmtaiK5YKh0vKjOp3z2E4,1446
2
+ pypomes_jwt/jwt_constants.py,sha256=IQV39AiZKGuU8XxZBgJ-KJZQZ_mmnxyOnRZeuxlqDRk,4045
3
+ pypomes_jwt/jwt_pomes.py,sha256=2LyjMMVkdPXeC7hMD52637e-LJoGbhKTb0Wqj6QXbTg,23049
4
+ pypomes_jwt/jwt_registry.py,sha256=xe8ApMSJ_I1gJeGPIMOqj1bgv6G0IDlqMX0M5zKiaYI,22463
5
+ pypomes_jwt-1.0.4.dist-info/METADATA,sha256=8Vef22_ykt_DQ0wkarlpV2YoXyV2TOdXJ2nOxIeBm30,632
6
+ pypomes_jwt-1.0.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ pypomes_jwt-1.0.4.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
8
+ pypomes_jwt-1.0.4.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- pypomes_jwt/__init__.py,sha256=fLr_M8yXlcmSTNPMdJOJQlMmtaiK5YKh0vKjOp3z2E4,1446
2
- pypomes_jwt/jwt_constants.py,sha256=IQV39AiZKGuU8XxZBgJ-KJZQZ_mmnxyOnRZeuxlqDRk,4045
3
- pypomes_jwt/jwt_pomes.py,sha256=0JvWQaVgGXMfvvck_ZI6EW5diech7DabBFYskPU7jmE,21215
4
- pypomes_jwt/jwt_registry.py,sha256=t2adiHGg04RRwrLvX2XUgRwOtwtH8p2Ir2uAbsc2CoQ,21593
5
- pypomes_jwt-1.0.3.dist-info/METADATA,sha256=ayr8d8ZmUyAHGDHKMeXNW0-zbhyU62HBZwdIj69nlM0,632
6
- pypomes_jwt-1.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- pypomes_jwt-1.0.3.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
8
- pypomes_jwt-1.0.3.dist-info/RECORD,,