pypomes-jwt 1.1.0__py3-none-any.whl → 1.1.2__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 +3 -3
- pypomes_jwt/jwt_configuration.py +85 -0
- pypomes_jwt/jwt_pomes.py +16 -20
- pypomes_jwt/jwt_registry.py +31 -33
- {pypomes_jwt-1.1.0.dist-info → pypomes_jwt-1.1.2.dist-info}/METADATA +2 -2
- pypomes_jwt-1.1.2.dist-info/RECORD +8 -0
- pypomes_jwt/jwt_constants.py +0 -108
- pypomes_jwt-1.1.0.dist-info/RECORD +0 -8
- {pypomes_jwt-1.1.0.dist-info → pypomes_jwt-1.1.2.dist-info}/WHEEL +0 -0
- {pypomes_jwt-1.1.0.dist-info → pypomes_jwt-1.1.2.dist-info}/licenses/LICENSE +0 -0
pypomes_jwt/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from .
|
|
2
|
-
|
|
1
|
+
from .jwt_configuration import (
|
|
2
|
+
JwtConfig, JwtDbConfig
|
|
3
3
|
)
|
|
4
4
|
from .jwt_pomes import (
|
|
5
5
|
jwt_needed, jwt_verify_request,
|
|
@@ -10,7 +10,7 @@ from .jwt_pomes import (
|
|
|
10
10
|
|
|
11
11
|
__all__ = [
|
|
12
12
|
# jwt_constants
|
|
13
|
-
"
|
|
13
|
+
"JwtConfig", "JwtDbConfig",
|
|
14
14
|
# jwt_pomes
|
|
15
15
|
"jwt_needed", "jwt_verify_request",
|
|
16
16
|
"jwt_assert_account", "jwt_set_account", "jwt_remove_account",
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from cryptography.hazmat.primitives import serialization
|
|
2
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
3
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from pypomes_core import (
|
|
6
|
+
APP_PREFIX,
|
|
7
|
+
env_get_str, env_get_bytes, env_get_int
|
|
8
|
+
)
|
|
9
|
+
from pypomes_db import DbEngine, db_setup
|
|
10
|
+
from secrets import token_bytes
|
|
11
|
+
from sys import stderr
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# recommended: allow the encode and decode keys to be generated anew when app starts
|
|
15
|
+
_encoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_ENCODING_KEY",
|
|
16
|
+
encoding="base64url")
|
|
17
|
+
_decoding_key: bytes
|
|
18
|
+
# one of HS256, HS512, RS256, RS512
|
|
19
|
+
_default_algorithm: str = env_get_str(key=f"{APP_PREFIX}_JWT_DEFAULT_ALGORITHM",
|
|
20
|
+
def_value="RS256")
|
|
21
|
+
if _default_algorithm in ["HS256", "HS512"]:
|
|
22
|
+
if not _encoding_key:
|
|
23
|
+
_encoding_key = token_bytes(nbytes=32)
|
|
24
|
+
_decoding_key = _encoding_key
|
|
25
|
+
else:
|
|
26
|
+
_decoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_DECODING_KEY")
|
|
27
|
+
if not _encoding_key or not _decoding_key:
|
|
28
|
+
__priv_key: RSAPrivateKey = rsa.generate_private_key(public_exponent=65537,
|
|
29
|
+
key_size=2048)
|
|
30
|
+
_encoding_key = __priv_key.private_bytes(encoding=serialization.Encoding.PEM,
|
|
31
|
+
format=serialization.PrivateFormat.PKCS8,
|
|
32
|
+
encryption_algorithm=serialization.NoEncryption())
|
|
33
|
+
__pub_key: RSAPublicKey = __priv_key.public_key()
|
|
34
|
+
_decoding_key = __pub_key.public_bytes(encoding=serialization.Encoding.PEM,
|
|
35
|
+
format=serialization.PublicFormat.SubjectPublicKeyInfo)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class JwtConfig(Enum):
|
|
39
|
+
"""
|
|
40
|
+
Parameters for JWT token issuance.
|
|
41
|
+
"""
|
|
42
|
+
# recommended: between 5 min and 1 hour (set to 5 min)
|
|
43
|
+
ACCESS_MAX_AGE: int = env_get_int(key=f"{APP_PREFIX}_JWT_ACCESS_MAX_AGE",
|
|
44
|
+
def_value=300)
|
|
45
|
+
ACCOUNT_LIMIT: int = env_get_int(key=f"{APP_PREFIX}_JWT_ACCOUNT_LIMIT",
|
|
46
|
+
def_value=5)
|
|
47
|
+
ENCODING_KEY: bytes = _encoding_key
|
|
48
|
+
DECODING_KEY: bytes = _decoding_key
|
|
49
|
+
DEFAULT_ALGORITHM: str = _default_algorithm
|
|
50
|
+
# recommended: at least 2 hours (set to 24 hours)
|
|
51
|
+
REFRESH_MAX_AGE: int = env_get_int(key=f"{APP_PREFIX}_JWT_REFRESH_MAX_AGE",
|
|
52
|
+
def_value=86400)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class JwtDbConfig(Enum):
|
|
56
|
+
"""
|
|
57
|
+
Parameters for JWT databse connection.
|
|
58
|
+
"""
|
|
59
|
+
ENGINE: str = DbEngine(env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE"))
|
|
60
|
+
CLIENT: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_CLIENT") # for Oracle, only
|
|
61
|
+
DRIVER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_DRIVER") # for SQLServer, only
|
|
62
|
+
NAME: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_NAME")
|
|
63
|
+
HOST: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_HOST")
|
|
64
|
+
PORT: int = env_get_int(key=f"{APP_PREFIX}_JWT_DB_PORT")
|
|
65
|
+
USER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_USER")
|
|
66
|
+
PWD: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_PWD")
|
|
67
|
+
TABLE: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE")
|
|
68
|
+
COL_ACCOUNT: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ACCOUNT")
|
|
69
|
+
COL_ALGORITHM: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ALGORITHM")
|
|
70
|
+
COL_DECODER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_DECODER")
|
|
71
|
+
COL_KID: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_KID")
|
|
72
|
+
COL_TOKEN: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_TOKEN")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# define and validate the database engine
|
|
76
|
+
# noinspection PyTypeChecker
|
|
77
|
+
if not db_setup(engine=JwtDbConfig.ENGINE.value,
|
|
78
|
+
db_name=JwtDbConfig.NAME.value,
|
|
79
|
+
db_user=JwtDbConfig.USER.value,
|
|
80
|
+
db_pwd=JwtDbConfig.PWD.value,
|
|
81
|
+
db_host=JwtDbConfig.HOST.value,
|
|
82
|
+
db_port=JwtDbConfig.PORT.value,
|
|
83
|
+
db_client=JwtDbConfig.CLIENT.value,
|
|
84
|
+
db_driver=JwtDbConfig.DRIVER.value):
|
|
85
|
+
stderr.write("Invalid database parameters\n")
|
pypomes_jwt/jwt_pomes.py
CHANGED
|
@@ -9,9 +9,7 @@ from pypomes_db import (
|
|
|
9
9
|
)
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
-
from .
|
|
13
|
-
JwtParam, JwtDbParam, _JWT_CONFIG, _JWT_DB
|
|
14
|
-
)
|
|
12
|
+
from .jwt_configuration import JwtConfig, JwtDbConfig
|
|
15
13
|
from .jwt_registry import JwtRegistry
|
|
16
14
|
|
|
17
15
|
# the JWT registry
|
|
@@ -77,8 +75,8 @@ def jwt_assert_account(account_id: str) -> bool:
|
|
|
77
75
|
|
|
78
76
|
def jwt_set_account(account_id: str,
|
|
79
77
|
claims: dict[str, Any],
|
|
80
|
-
access_max_age: int =
|
|
81
|
-
refresh_max_age: int =
|
|
78
|
+
access_max_age: int = JwtConfig.ACCESS_MAX_AGE.value,
|
|
79
|
+
refresh_max_age: int = JwtConfig.REFRESH_MAX_AGE.value,
|
|
82
80
|
grace_interval: int = None,
|
|
83
81
|
logger: Logger = None) -> None:
|
|
84
82
|
"""
|
|
@@ -179,15 +177,13 @@ def jwt_validate_token(errors: list[str] | None,
|
|
|
179
177
|
elif token_kid and len(token_kid) > 1 and \
|
|
180
178
|
token_kid[0:1] in ["A", "R"] and token_kid[1:].isdigit():
|
|
181
179
|
# token was likely issued locally
|
|
182
|
-
where_data: dict[str, Any] = {
|
|
183
|
-
_JWT_DB[JwtDbParam.COL_KID]: int(token_kid[1:])
|
|
184
|
-
}
|
|
180
|
+
where_data: dict[str, Any] = {JwtDbConfig.COL_KID.value: int(token_kid[1:])}
|
|
185
181
|
if account_id:
|
|
186
|
-
where_data[
|
|
182
|
+
where_data[JwtDbConfig.COL_ACCOUNT.value] = account_id
|
|
187
183
|
recs: list[tuple[str]] = db_select(errors=op_errors,
|
|
188
|
-
sel_stmt=f"SELECT {
|
|
189
|
-
f"{
|
|
190
|
-
f"FROM {
|
|
184
|
+
sel_stmt=f"SELECT {JwtDbConfig.COL_ALGORITHM.value}, "
|
|
185
|
+
f"{JwtDbConfig.COL_DECODER.value} "
|
|
186
|
+
f"FROM {JwtDbConfig.TABLE.value}",
|
|
191
187
|
where_data=where_data,
|
|
192
188
|
logger=logger)
|
|
193
189
|
if recs:
|
|
@@ -201,8 +197,8 @@ def jwt_validate_token(errors: list[str] | None,
|
|
|
201
197
|
logger.error(msg="Token not in the database")
|
|
202
198
|
op_errors.append("Invalid token")
|
|
203
199
|
else:
|
|
204
|
-
token_alg =
|
|
205
|
-
token_decoder =
|
|
200
|
+
token_alg = JwtConfig.DEFAULT_ALGORITHM.value
|
|
201
|
+
token_decoder = JwtConfig.DECODING_KEY.value
|
|
206
202
|
|
|
207
203
|
# validate the token
|
|
208
204
|
if not op_errors:
|
|
@@ -282,10 +278,10 @@ def jwt_revoke_token(errors: list[str] | None,
|
|
|
282
278
|
op_errors.append("Invalid token")
|
|
283
279
|
else:
|
|
284
280
|
db_delete(errors=op_errors,
|
|
285
|
-
delete_stmt=f"DELETE FROM {
|
|
281
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
|
|
286
282
|
where_data={
|
|
287
|
-
|
|
288
|
-
|
|
283
|
+
JwtDbConfig.COL_KID.value: int(token_kid[1:]),
|
|
284
|
+
JwtDbConfig.COL_ACCOUNT.value: account_id
|
|
289
285
|
},
|
|
290
286
|
logger=logger)
|
|
291
287
|
if op_errors:
|
|
@@ -456,10 +452,10 @@ def jwt_refresh_tokens(errors: list[str] | None,
|
|
|
456
452
|
if db_conn:
|
|
457
453
|
# delete current refresh token
|
|
458
454
|
db_delete(errors=op_errors,
|
|
459
|
-
delete_stmt=f"DELETE FROM {
|
|
455
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
|
|
460
456
|
where_data={
|
|
461
|
-
|
|
462
|
-
|
|
457
|
+
JwtDbConfig.COL_KID.value: int(token_kid[1:]),
|
|
458
|
+
JwtDbConfig.COL_ACCOUNT.value: account_id
|
|
463
459
|
},
|
|
464
460
|
connection=db_conn,
|
|
465
461
|
committable=False,
|
pypomes_jwt/jwt_registry.py
CHANGED
|
@@ -12,9 +12,7 @@ from pypomes_db import (
|
|
|
12
12
|
from threading import Lock
|
|
13
13
|
from typing import Any
|
|
14
14
|
|
|
15
|
-
from .
|
|
16
|
-
JwtParam, JwtDbParam, _JWT_CONFIG, _JWT_DB
|
|
17
|
-
)
|
|
15
|
+
from .jwt_configuration import JwtConfig, JwtDbConfig
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
class JwtRegistry:
|
|
@@ -141,8 +139,8 @@ class JwtRegistry:
|
|
|
141
139
|
|
|
142
140
|
# remove from database
|
|
143
141
|
db_delete(errors=None,
|
|
144
|
-
delete_stmt=f"DELETE FROM {
|
|
145
|
-
where_data={
|
|
142
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.value}",
|
|
143
|
+
where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
|
|
146
144
|
logger=logger)
|
|
147
145
|
if logger:
|
|
148
146
|
if account_data:
|
|
@@ -216,8 +214,8 @@ class JwtRegistry:
|
|
|
216
214
|
tz=timezone.utc).isoformat()
|
|
217
215
|
# may raise an exception
|
|
218
216
|
return jwt.encode(payload=current_claims,
|
|
219
|
-
key=
|
|
220
|
-
algorithm=
|
|
217
|
+
key=JwtConfig.ENCODING_KEY.value,
|
|
218
|
+
algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
|
|
221
219
|
headers={"kid": nature})
|
|
222
220
|
|
|
223
221
|
def issue_tokens(self,
|
|
@@ -277,8 +275,8 @@ class JwtRegistry:
|
|
|
277
275
|
tz=timezone.utc).isoformat()
|
|
278
276
|
# may raise an exception
|
|
279
277
|
refresh_token: str = jwt.encode(payload=current_claims,
|
|
280
|
-
key=
|
|
281
|
-
algorithm=
|
|
278
|
+
key=JwtConfig.ENCODING_KEY.value,
|
|
279
|
+
algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
|
|
282
280
|
headers={"kid": "R0"})
|
|
283
281
|
|
|
284
282
|
# make sure to have a database connection
|
|
@@ -293,14 +291,14 @@ class JwtRegistry:
|
|
|
293
291
|
logger=logger)
|
|
294
292
|
# issue the definitive refresh token
|
|
295
293
|
refresh_token = jwt.encode(payload=current_claims,
|
|
296
|
-
key=
|
|
297
|
-
algorithm=
|
|
294
|
+
key=JwtConfig.ENCODING_KEY.value,
|
|
295
|
+
algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
|
|
298
296
|
headers={"kid": f"R{token_id}"})
|
|
299
297
|
# persist it
|
|
300
298
|
db_update(errors=errors,
|
|
301
|
-
update_stmt=f"UPDATE {
|
|
302
|
-
update_data={
|
|
303
|
-
where_data={
|
|
299
|
+
update_stmt=f"UPDATE {JwtDbConfig.TABLE.value}",
|
|
300
|
+
update_data={JwtDbConfig.COL_TOKEN.value: refresh_token},
|
|
301
|
+
where_data={JwtDbConfig.COL_KID.value: token_id},
|
|
304
302
|
connection=curr_conn,
|
|
305
303
|
committable=False,
|
|
306
304
|
logger=logger)
|
|
@@ -322,8 +320,8 @@ class JwtRegistry:
|
|
|
322
320
|
current_claims["exp"] = just_now + account_data.get("access-max-age")
|
|
323
321
|
# may raise an exception
|
|
324
322
|
access_token: str = jwt.encode(payload=current_claims,
|
|
325
|
-
key=
|
|
326
|
-
algorithm=
|
|
323
|
+
key=JwtConfig.ENCODING_KEY.value,
|
|
324
|
+
algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
|
|
327
325
|
headers={"kid": f"A{token_id}"})
|
|
328
326
|
# return the token data
|
|
329
327
|
return {
|
|
@@ -381,9 +379,9 @@ def _jwt_persist_token(account_id: str,
|
|
|
381
379
|
# noinspection PyTypeChecker
|
|
382
380
|
recs: list[tuple[int, str, str, str]] = \
|
|
383
381
|
db_select(errors=errors,
|
|
384
|
-
sel_stmt=f"SELECT {
|
|
385
|
-
f"FROM {
|
|
386
|
-
where_data={
|
|
382
|
+
sel_stmt=f"SELECT {JwtDbConfig.COL_KID.value}, {JwtDbConfig.COL_TOKEN.value} "
|
|
383
|
+
f"FROM {JwtDbConfig.TABLE.value}",
|
|
384
|
+
where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
|
|
387
385
|
connection=db_conn,
|
|
388
386
|
committable=False,
|
|
389
387
|
logger=logger)
|
|
@@ -424,8 +422,8 @@ def _jwt_persist_token(account_id: str,
|
|
|
424
422
|
# remove expired tokens from persistence
|
|
425
423
|
if expired:
|
|
426
424
|
db_delete(errors=errors,
|
|
427
|
-
delete_stmt=f"DELETE FROM {
|
|
428
|
-
where_data={
|
|
425
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
|
|
426
|
+
where_data={JwtDbConfig.COL_KID.value: expired},
|
|
429
427
|
connection=db_conn,
|
|
430
428
|
committable=False,
|
|
431
429
|
logger=logger)
|
|
@@ -435,11 +433,11 @@ def _jwt_persist_token(account_id: str,
|
|
|
435
433
|
logger.debug(msg=f"{len(expired)} tokens of account "
|
|
436
434
|
f"'{account_id}' removed from storage")
|
|
437
435
|
|
|
438
|
-
if 0 <
|
|
436
|
+
if 0 < JwtConfig.ACCOUNT_LIMIT.value <= len(recs) - len(expired):
|
|
439
437
|
# delete the oldest token to make way for the new one
|
|
440
438
|
db_delete(errors=errors,
|
|
441
|
-
delete_stmt=f"DELETE FROM {
|
|
442
|
-
where_data={
|
|
439
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
|
|
440
|
+
where_data={JwtDbConfig.COL_KID.value: oldest_id},
|
|
443
441
|
connection=db_conn,
|
|
444
442
|
committable=False,
|
|
445
443
|
logger=logger)
|
|
@@ -450,12 +448,12 @@ def _jwt_persist_token(account_id: str,
|
|
|
450
448
|
f"'{account_id}' removed from storage")
|
|
451
449
|
# persist token
|
|
452
450
|
db_insert(errors=errors,
|
|
453
|
-
insert_stmt=f"INSERT INTO {
|
|
451
|
+
insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE.value}",
|
|
454
452
|
insert_data={
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
453
|
+
JwtDbConfig.COL_ACCOUNT.value: account_id,
|
|
454
|
+
JwtDbConfig.COL_TOKEN.value: jwt_token,
|
|
455
|
+
JwtDbConfig.COL_ALGORITHM.value: JwtConfig.DEFAULT_ALGORITHM.value,
|
|
456
|
+
JwtDbConfig.COL_DECODER.value: urlsafe_b64encode(s=JwtConfig.DECODING_KEY.value).decode()
|
|
459
457
|
},
|
|
460
458
|
connection=db_conn,
|
|
461
459
|
committable=False,
|
|
@@ -467,13 +465,13 @@ def _jwt_persist_token(account_id: str,
|
|
|
467
465
|
# HAZARD: JWT_DB_COL_TOKEN's column type might prevent it for being used in a WHERE clause
|
|
468
466
|
where_clause: str | None = None
|
|
469
467
|
if existing_ids:
|
|
470
|
-
where_clause = f"{
|
|
468
|
+
where_clause = f"{JwtDbConfig.COL_KID.value} NOT IN {existing_ids}"
|
|
471
469
|
where_clause = where_clause.replace("[", "(", 1).replace("]", ")", 1)
|
|
472
470
|
reply: list[tuple[int]] = db_select(errors=errors,
|
|
473
|
-
sel_stmt=f"SELECT {
|
|
474
|
-
f"FROM {
|
|
471
|
+
sel_stmt=f"SELECT {JwtDbConfig.COL_KID.value} "
|
|
472
|
+
f"FROM {JwtDbConfig.TABLE.value}",
|
|
475
473
|
where_clause=where_clause,
|
|
476
|
-
where_data={
|
|
474
|
+
where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
|
|
477
475
|
require_count=1,
|
|
478
476
|
connection=db_conn,
|
|
479
477
|
committable=False,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_jwt
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.2
|
|
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
|
|
@@ -12,5 +12,5 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Requires-Dist: cryptography>=44.0.2
|
|
14
14
|
Requires-Dist: pyjwt>=2.10.1
|
|
15
|
-
Requires-Dist: pypomes-core>=1.9.
|
|
15
|
+
Requires-Dist: pypomes-core>=1.9.8
|
|
16
16
|
Requires-Dist: pypomes-db>=2.0.9
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pypomes_jwt/__init__.py,sha256=g4tjg7gt5_vwiHM_6-T6Ji4XYJ5py9RuzGmF2Z-qlXI,800
|
|
2
|
+
pypomes_jwt/jwt_configuration.py,sha256=GBkt8ISgcRYMh1FuTxUBWiKFACHHz-67mejSaPdiEsc,4172
|
|
3
|
+
pypomes_jwt/jwt_pomes.py,sha256=e-E-T_hkk_FNmpsndee8AhcuUWR775SIxo4YBqjCFDA,23290
|
|
4
|
+
pypomes_jwt/jwt_registry.py,sha256=7eWFEdzCMXjdxwR8nO_rqAeZ6SDf-WAEksDlfLPM_o4,23212
|
|
5
|
+
pypomes_jwt-1.1.2.dist-info/METADATA,sha256=nIpMJ0AN-R9XZNsbEBVAu9ueTCOSQj3LxDgAOQrLKRU,632
|
|
6
|
+
pypomes_jwt-1.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
+
pypomes_jwt-1.1.2.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
8
|
+
pypomes_jwt-1.1.2.dist-info/RECORD,,
|
pypomes_jwt/jwt_constants.py
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
from cryptography.hazmat.primitives import serialization
|
|
2
|
-
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
3
|
-
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
|
|
4
|
-
from enum import StrEnum
|
|
5
|
-
from pypomes_core import (
|
|
6
|
-
APP_PREFIX,
|
|
7
|
-
env_get_str, env_get_bytes, env_get_int
|
|
8
|
-
)
|
|
9
|
-
from pypomes_db import DbEngine, db_setup
|
|
10
|
-
from secrets import token_bytes
|
|
11
|
-
from sys import stderr
|
|
12
|
-
from typing import Any, Final
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class JwtParam(StrEnum):
|
|
16
|
-
"""
|
|
17
|
-
Parameters for JWT provider access.
|
|
18
|
-
"""
|
|
19
|
-
ACCESS_MAX_AGE = "access-max-age"
|
|
20
|
-
ACCOUNT_LIMIT = "account-limit"
|
|
21
|
-
DECODING_KEY = "decoding-key"
|
|
22
|
-
DEFAULT_ALGORITHM = "default-algorithm"
|
|
23
|
-
ENCODING_KEY = "encoding-key"
|
|
24
|
-
REFRESH_MAX_AGE = "refresh-max-age"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class JwtDbParam(StrEnum):
|
|
28
|
-
"""
|
|
29
|
-
Parameters for JWT databse connection.
|
|
30
|
-
"""
|
|
31
|
-
CLIENT = "client"
|
|
32
|
-
DRIVER = "driver"
|
|
33
|
-
ENGINE = "engine"
|
|
34
|
-
NAME = "name"
|
|
35
|
-
HOST = "host"
|
|
36
|
-
PORT = "port"
|
|
37
|
-
USER = "user"
|
|
38
|
-
PWD = "pwd"
|
|
39
|
-
TABLE = "table"
|
|
40
|
-
COL_ACCOUNT = "col-account"
|
|
41
|
-
COL_ALGORITHM = "col-algorithm"
|
|
42
|
-
COL_DECODER = "col-decoder"
|
|
43
|
-
COL_KID = "col-kid"
|
|
44
|
-
COL_TOKEN = "col-token"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# recommended: allow the encode and decode keys to be generated anew when app starts
|
|
48
|
-
__encoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_ENCODING_KEY",
|
|
49
|
-
encoding="base64url")
|
|
50
|
-
__decoding_key: bytes
|
|
51
|
-
# one of HS256, HS512, RS256, RS512
|
|
52
|
-
__default_algorithm: str = env_get_str(key=f"{APP_PREFIX}_JWT_DEFAULT_ALGORITHM",
|
|
53
|
-
def_value="RS256")
|
|
54
|
-
if __default_algorithm in ["HS256", "HS512"]:
|
|
55
|
-
if not __encoding_key:
|
|
56
|
-
__encoding_key = token_bytes(nbytes=32)
|
|
57
|
-
__decoding_key = __encoding_key
|
|
58
|
-
else:
|
|
59
|
-
__decoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_DECODING_KEY")
|
|
60
|
-
if not __encoding_key or not __decoding_key:
|
|
61
|
-
__priv_key: RSAPrivateKey = rsa.generate_private_key(public_exponent=65537,
|
|
62
|
-
key_size=2048)
|
|
63
|
-
__encoding_key = __priv_key.private_bytes(encoding=serialization.Encoding.PEM,
|
|
64
|
-
format=serialization.PrivateFormat.PKCS8,
|
|
65
|
-
encryption_algorithm=serialization.NoEncryption())
|
|
66
|
-
__pub_key: RSAPublicKey = __priv_key.public_key()
|
|
67
|
-
__decoding_key = __pub_key.public_bytes(encoding=serialization.Encoding.PEM,
|
|
68
|
-
format=serialization.PublicFormat.SubjectPublicKeyInfo)
|
|
69
|
-
|
|
70
|
-
_JWT_CONFIG: Final[dict[JwtParam, Any]] = {
|
|
71
|
-
# recommended: between 5 min and 1 hour (set to 5 min)
|
|
72
|
-
JwtParam.ACCESS_MAX_AGE: env_get_int(key=f"{APP_PREFIX}_JWT_ACCESS_MAX_AGE",
|
|
73
|
-
def_value=300),
|
|
74
|
-
JwtParam.ACCOUNT_LIMIT: env_get_int(key=f"{APP_PREFIX}_JWT_ACCOUNT_LIMIT"),
|
|
75
|
-
JwtParam.DECODING_KEY: __decoding_key,
|
|
76
|
-
JwtParam.DEFAULT_ALGORITHM: __default_algorithm,
|
|
77
|
-
JwtParam.ENCODING_KEY: __encoding_key,
|
|
78
|
-
# recommended: at least 2 hours (set to 24 hours)
|
|
79
|
-
JwtParam.REFRESH_MAX_AGE: env_get_int(key=f"{APP_PREFIX}_JWT_REFRESH_MAX_AGE",
|
|
80
|
-
def_value=86400)
|
|
81
|
-
}
|
|
82
|
-
_JWT_DB: Final[JwtDbParam, Any] = {
|
|
83
|
-
JwtDbParam.ENGINE: DbEngine(env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE")),
|
|
84
|
-
JwtDbParam.CLIENT: env_get_str(key=f"{APP_PREFIX}_JWT_DB_CLIENT"), # for Oracle, only
|
|
85
|
-
JwtDbParam.DRIVER: env_get_str(key=f"{APP_PREFIX}_JWT_DB_DRIVER"), # for SQLServer, only
|
|
86
|
-
JwtDbParam.NAME: env_get_str(key=f"{APP_PREFIX}_JWT_DB_NAME"),
|
|
87
|
-
JwtDbParam.HOST: env_get_str(key=f"{APP_PREFIX}_JWT_DB_HOST"),
|
|
88
|
-
JwtDbParam.PORT: env_get_int(key=f"{APP_PREFIX}_JWT_DB_PORT"),
|
|
89
|
-
JwtDbParam.USER: env_get_str(key=f"{APP_PREFIX}_JWT_DB_USER"),
|
|
90
|
-
JwtDbParam.PWD: env_get_str(key=f"{APP_PREFIX}_JWT_DB_PWD"),
|
|
91
|
-
JwtDbParam.TABLE: env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE"),
|
|
92
|
-
JwtDbParam.COL_ACCOUNT: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ACCOUNT"),
|
|
93
|
-
JwtDbParam.COL_ALGORITHM: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ALGORITHM"),
|
|
94
|
-
JwtDbParam.COL_DECODER: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_DECODER"),
|
|
95
|
-
JwtDbParam.COL_KID: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_KID"),
|
|
96
|
-
JwtDbParam.COL_TOKEN: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_TOKEN")
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
# define and validate the database engine
|
|
100
|
-
if not db_setup(engine=_JWT_DB[JwtDbParam.ENGINE],
|
|
101
|
-
db_name=_JWT_DB[JwtDbParam.NAME],
|
|
102
|
-
db_user=_JWT_DB[JwtDbParam.USER],
|
|
103
|
-
db_pwd=_JWT_DB[JwtDbParam.PWD],
|
|
104
|
-
db_host=_JWT_DB[JwtDbParam.HOST],
|
|
105
|
-
db_port=_JWT_DB[JwtDbParam.PORT],
|
|
106
|
-
db_client=_JWT_DB[JwtDbParam.CLIENT],
|
|
107
|
-
db_driver=_JWT_DB[JwtDbParam.DRIVER]):
|
|
108
|
-
stderr.write("Invalid database parameters\n")
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
pypomes_jwt/__init__.py,sha256=h6T8GEd2HX8mguRvSLiemE2FKC5rJnVnHipounnUT7U,792
|
|
2
|
-
pypomes_jwt/jwt_constants.py,sha256=5iPiDlO_D5DPUO90p8byiJZuvNlOeJYnDNety44dOVQ,4936
|
|
3
|
-
pypomes_jwt/jwt_pomes.py,sha256=SzieR_GPMaqWhoGT0T_zg17EGLdzPkVj9LoHEiqQt7Y,23394
|
|
4
|
-
pypomes_jwt/jwt_registry.py,sha256=CHIEjje1VROaxHmsSQxs1xCXF7E00Src55GHdzFvSzI,23352
|
|
5
|
-
pypomes_jwt-1.1.0.dist-info/METADATA,sha256=q3z3nivSzhSqRZ5wZDxVu6wDEKCh72pRiR8nRK7gRIg,632
|
|
6
|
-
pypomes_jwt-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
pypomes_jwt-1.1.0.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
8
|
-
pypomes_jwt-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|