pypomes-jwt 1.1.5__tar.gz → 1.1.7__tar.gz
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-1.1.5 → pypomes_jwt-1.1.7}/PKG-INFO +2 -2
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/pyproject.toml +2 -2
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/src/pypomes_jwt/jwt_pomes.py +17 -11
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/src/pypomes_jwt/jwt_registry.py +11 -16
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/.gitignore +0 -0
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/LICENSE +0 -0
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/README.md +0 -0
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/src/pypomes_jwt/__init__.py +0 -0
- {pypomes_jwt-1.1.5 → pypomes_jwt-1.1.7}/src/pypomes_jwt/jwt_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_jwt
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.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
|
|
@@ -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>=2.0.
|
|
15
|
+
Requires-Dist: pypomes-core>=2.0.5
|
|
16
16
|
Requires-Dist: pypomes-db>=2.1.1
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "pypomes_jwt"
|
|
9
|
-
version = "1.1.
|
|
9
|
+
version = "1.1.7"
|
|
10
10
|
authors = [
|
|
11
11
|
{ name="GT Nunes", email="wisecoder01@gmail.com" }
|
|
12
12
|
]
|
|
@@ -21,7 +21,7 @@ classifiers = [
|
|
|
21
21
|
dependencies = [
|
|
22
22
|
"PyJWT>=2.10.1",
|
|
23
23
|
"cryptography>=44.0.2",
|
|
24
|
-
"pypomes_core>=2.0.
|
|
24
|
+
"pypomes_core>=2.0.5",
|
|
25
25
|
"pypomes_db>=2.1.1"
|
|
26
26
|
]
|
|
27
27
|
|
|
@@ -38,6 +38,8 @@ def jwt_verify_request(request: Request) -> Response:
|
|
|
38
38
|
"""
|
|
39
39
|
Verify whether the HTTP *request* has the proper authorization, as per the JWT standard.
|
|
40
40
|
|
|
41
|
+
This implementation assumes that HTTP requests are handled with the *Flask* framework.
|
|
42
|
+
|
|
41
43
|
:param request: the *request* to be verified
|
|
42
44
|
:return: *None* if the *request* is valid, otherwise a *Response* reporting the error
|
|
43
45
|
"""
|
|
@@ -47,15 +49,19 @@ def jwt_verify_request(request: Request) -> Response:
|
|
|
47
49
|
# retrieve the authorization from the request header
|
|
48
50
|
auth_header: str = request.headers.get("Authorization")
|
|
49
51
|
|
|
50
|
-
#
|
|
52
|
+
# validate the authorization token
|
|
51
53
|
bad_token: bool = True
|
|
52
54
|
if auth_header and auth_header.startswith("Bearer "):
|
|
53
55
|
# yes, extract and validate the JWT access token
|
|
54
56
|
token: str = auth_header.split(" ")[1]
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
claims: dict[str, Any] = jwt_validate_token(errors=None,
|
|
58
|
+
token=token,
|
|
59
|
+
nature="A")
|
|
60
|
+
if claims:
|
|
61
|
+
login: str = request.values.get("login")
|
|
62
|
+
subject: str = claims["payload"].get("sub")
|
|
63
|
+
if not login or not subject or login == subject:
|
|
64
|
+
bad_token = False
|
|
59
65
|
|
|
60
66
|
# deny the authorization
|
|
61
67
|
if bad_token:
|
|
@@ -78,7 +84,7 @@ def jwt_set_account(account_id: str,
|
|
|
78
84
|
claims: dict[str, Any],
|
|
79
85
|
access_max_age: int = JwtConfig.ACCESS_MAX_AGE.value,
|
|
80
86
|
refresh_max_age: int = JwtConfig.REFRESH_MAX_AGE.value,
|
|
81
|
-
|
|
87
|
+
lead_interval: int = None,
|
|
82
88
|
logger: Logger = None) -> None:
|
|
83
89
|
"""
|
|
84
90
|
Establish the data needed to obtain JWT tokens for *account_id*.
|
|
@@ -92,7 +98,7 @@ def jwt_set_account(account_id: str,
|
|
|
92
98
|
:param claims: the JWT claimset, as key-value pairs
|
|
93
99
|
:param access_max_age: access token duration, in seconds
|
|
94
100
|
:param refresh_max_age: refresh token duration, in seconds
|
|
95
|
-
:param
|
|
101
|
+
:param lead_interval: optional time to wait for token to be valid, in seconds
|
|
96
102
|
:param logger: optional logger
|
|
97
103
|
"""
|
|
98
104
|
if logger:
|
|
@@ -103,7 +109,7 @@ def jwt_set_account(account_id: str,
|
|
|
103
109
|
claims=claims,
|
|
104
110
|
access_max_age=access_max_age,
|
|
105
111
|
refresh_max_age=max(refresh_max_age, access_max_age + 300),
|
|
106
|
-
|
|
112
|
+
lead_interval=lead_interval,
|
|
107
113
|
logger=logger)
|
|
108
114
|
|
|
109
115
|
|
|
@@ -302,7 +308,7 @@ def jwt_issue_token(errors: list[str] | None,
|
|
|
302
308
|
account_id: str,
|
|
303
309
|
nature: str,
|
|
304
310
|
duration: int,
|
|
305
|
-
|
|
311
|
+
lead_interval: int = None,
|
|
306
312
|
claims: dict[str, Any] = None,
|
|
307
313
|
logger: Logger = None) -> str:
|
|
308
314
|
"""
|
|
@@ -318,7 +324,7 @@ def jwt_issue_token(errors: list[str] | None,
|
|
|
318
324
|
:param nature: the token's nature, must be a single letter in the range *[B-Z]*, less *R*
|
|
319
325
|
:param duration: the number of seconds for the token to remain valid (at least 60 seconds)
|
|
320
326
|
:param claims: optional token's claims
|
|
321
|
-
:param
|
|
327
|
+
:param lead_interval: optional interval for the token to become active (in seconds)
|
|
322
328
|
:param logger: optional logger
|
|
323
329
|
:return: the JWT token data, or *None* if error
|
|
324
330
|
"""
|
|
@@ -334,7 +340,7 @@ def jwt_issue_token(errors: list[str] | None,
|
|
|
334
340
|
nature=nature,
|
|
335
341
|
duration=duration,
|
|
336
342
|
claims=claims,
|
|
337
|
-
|
|
343
|
+
lead_interval=lead_interval,
|
|
338
344
|
logger=logger)
|
|
339
345
|
if logger:
|
|
340
346
|
logger.debug(msg=f"Token is '{result}'")
|
|
@@ -26,7 +26,7 @@ class JwtRegistry:
|
|
|
26
26
|
<account-id>: {
|
|
27
27
|
"access-max-age": <int>, # defaults to JWT_ACCESS_MAX_AGE (in seconds)
|
|
28
28
|
"refresh-max-age": <int>, # defaults to JWT_REFRESH_MAX_AGE (in seconds)
|
|
29
|
-
"
|
|
29
|
+
"lead-interval": <int>, # time to wait for token to be valid, in seconds
|
|
30
30
|
"claims": {
|
|
31
31
|
"iss": <string>, # token'ss issuer
|
|
32
32
|
"birthdate": <string>, # subject's birth date
|
|
@@ -35,9 +35,6 @@ class JwtRegistry:
|
|
|
35
35
|
"name": <string>, # subject's name
|
|
36
36
|
"roles": <List[str]>, # subject roles
|
|
37
37
|
"nonce": <string>, # used to associate a Client session with a token
|
|
38
|
-
# output, only
|
|
39
|
-
"valid-from": <string>, # token's start (<YYYY-MM-DDThh:mm:ss+00:00>)
|
|
40
|
-
"valid-until": <string>, # token's finish (<YYYY-MM-DDThh:mm:ss+00:00>)
|
|
41
38
|
...
|
|
42
39
|
}
|
|
43
40
|
},
|
|
@@ -63,8 +60,6 @@ class JwtRegistry:
|
|
|
63
60
|
|
|
64
61
|
Account-related claims are optional claims, and convey information about the registered account they belong to.
|
|
65
62
|
Alhough they can be freely specified, these are some of the most commonly used claims:
|
|
66
|
-
"valid-from": <string> token's start (<YYYY-MM-DDThh:mm:ss+00:00>)
|
|
67
|
-
"valid-until": <string> token's finish (<YYYY-MM-DDThh:mm:ss+00.00>)
|
|
68
63
|
"birthdate": <string> subject's birth date
|
|
69
64
|
"email": <string> subject's email
|
|
70
65
|
"gender": <string> subject's gender
|
|
@@ -92,7 +87,7 @@ class JwtRegistry:
|
|
|
92
87
|
claims: dict[str, Any],
|
|
93
88
|
access_max_age: int,
|
|
94
89
|
refresh_max_age: int,
|
|
95
|
-
|
|
90
|
+
lead_interval: int | None,
|
|
96
91
|
logger: Logger = None) -> None:
|
|
97
92
|
"""
|
|
98
93
|
Add to storage the parameters needed to produce and validate JWT tokens for *account_id*.
|
|
@@ -105,7 +100,7 @@ class JwtRegistry:
|
|
|
105
100
|
:param claims: the JWT claimset, as key-value pairs
|
|
106
101
|
:param access_max_age: access token duration, in seconds (at least 60 seconds)
|
|
107
102
|
:param refresh_max_age: refresh token duration, in seconds (greater than *access_max_age*)
|
|
108
|
-
:param
|
|
103
|
+
:param lead_interval: time to wait for token to be valid, in seconds
|
|
109
104
|
:param logger: optional logger
|
|
110
105
|
"""
|
|
111
106
|
# build and store the access data for the account
|
|
@@ -114,7 +109,7 @@ class JwtRegistry:
|
|
|
114
109
|
self.access_registry[account_id] = {
|
|
115
110
|
"access-max-age": access_max_age,
|
|
116
111
|
"refresh-max-age": refresh_max_age,
|
|
117
|
-
"
|
|
112
|
+
"lead-interval": lead_interval,
|
|
118
113
|
"claims": claims or {}
|
|
119
114
|
}
|
|
120
115
|
if logger:
|
|
@@ -155,7 +150,7 @@ class JwtRegistry:
|
|
|
155
150
|
account_id: str,
|
|
156
151
|
nature: str,
|
|
157
152
|
duration: int,
|
|
158
|
-
|
|
153
|
+
lead_interval: int = None,
|
|
159
154
|
claims: dict[str, Any] = None,
|
|
160
155
|
logger: Logger = None) -> str:
|
|
161
156
|
"""
|
|
@@ -170,7 +165,7 @@ class JwtRegistry:
|
|
|
170
165
|
:param nature: the token's nature, must be a single letter in the range *[B-Z]*, less *R*
|
|
171
166
|
:param duration: the number of seconds for the token to remain valid (at least 60 seconds)
|
|
172
167
|
:param claims: optional token's claims
|
|
173
|
-
:param
|
|
168
|
+
:param lead_interval: optional interval for the token to become active (in seconds)
|
|
174
169
|
:param logger: optional logger
|
|
175
170
|
:return: the JWT token
|
|
176
171
|
:raises RuntimeError: invalid parameter
|
|
@@ -203,8 +198,8 @@ class JwtRegistry:
|
|
|
203
198
|
current_claims["sub"] = account_id
|
|
204
199
|
just_now: int = int(datetime.now(tz=timezone.utc).timestamp())
|
|
205
200
|
current_claims["iat"] = just_now
|
|
206
|
-
if
|
|
207
|
-
current_claims["nbf"] = just_now +
|
|
201
|
+
if lead_interval:
|
|
202
|
+
current_claims["nbf"] = just_now + lead_interval
|
|
208
203
|
current_claims["exp"] = just_now + duration
|
|
209
204
|
|
|
210
205
|
# may raise an exception
|
|
@@ -256,9 +251,9 @@ class JwtRegistry:
|
|
|
256
251
|
|
|
257
252
|
just_now: int = int(datetime.now(tz=timezone.utc).timestamp())
|
|
258
253
|
current_claims["iat"] = just_now
|
|
259
|
-
|
|
260
|
-
if
|
|
261
|
-
current_claims["nbf"] = just_now +
|
|
254
|
+
lead_interval = account_data.get("lead-interval")
|
|
255
|
+
if lead_interval:
|
|
256
|
+
current_claims["nbf"] = just_now + lead_interval
|
|
262
257
|
|
|
263
258
|
# issue a candidate refresh token first, and persist it
|
|
264
259
|
current_claims["exp"] = just_now + account_data.get("refresh-max-age")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|