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 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, jwt_service,
9
- jwt_get_token_claims, jwt_get_token, jwt_get_token_data,
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", "jwt_service",
21
- "jwt_get_token_claims", "jwt_get_token", "jwt_get_token_data",
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
- item_data: dict[str, Any] = self.get_access_data(account_id=account_id,
203
- logger=logger)
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 item_data:
205
+ if access_data:
206
206
  # yes, proceed
207
- control_data: dict[str, Any] = item_data.get("control-data")
208
- reserved_claims: dict[str, Any] = item_data.get("reserved-claims")
209
- custom_claims: dict[str, Any] = item_data.get("custom-claims")
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] = item_data.get("public-claims").copy()
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
- control_data: dict[str, Any] = self.get_access_data(access_token=token,
291
- logger=logger)
292
- if control_data:
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 InvalidTokenError or ExpiredSignatureError
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) if JWT_ENDPOINT_URL else None
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*, along with its duration.
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 'None' if error
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 jwt_service(account_id: str = None,
294
- service_params: dict[str, Any] = None,
295
- logger: Logger = None) -> Response:
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
- Entry point for obtaining JWT tokens.
309
+ REST service entry point for obtaining JWT tokens.
298
310
 
299
- Access might be through direct invocation, or through a REST request. In either case,
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
- :param logger: optional logger
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
- if not account_id:
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, proceed
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.5
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,,