python3-commons 0.8.30__py3-none-any.whl → 0.8.32__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.
python3_commons/auth.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from http import HTTPStatus
3
- from typing import Annotated, Sequence
3
+ from typing import Annotated, Any, Callable, Coroutine, Sequence, Type, TypeVar
4
4
 
5
5
  import aiohttp
6
6
  from fastapi import Depends, HTTPException
@@ -20,6 +20,9 @@ class TokenData(BaseModel):
20
20
  iss: str
21
21
 
22
22
 
23
+ T = TypeVar('T', bound=TokenData)
24
+
25
+
23
26
  OIDC_CONFIG_URL = f'{oidc_settings.authority_url}/.well-known/openid-configuration'
24
27
  _JWKS: dict | None = None
25
28
 
@@ -52,31 +55,36 @@ async def fetch_jwks(jwks_uri: str) -> dict:
52
55
  return await response.json()
53
56
 
54
57
 
55
- async def get_verified_token(
56
- authorization: Annotated[HTTPAuthorizationCredentials, Depends(bearer_security)],
57
- ) -> TokenData | None:
58
- """
59
- Verify the JWT access token using OIDC authority JWKS.
60
- """
61
- global _JWKS
58
+ def get_token_verifier(token_cls: Type[T]) -> Callable[[HTTPAuthorizationCredentials], Coroutine[Any, Any, T | None]]:
59
+ async def get_verified_token(
60
+ authorization: Annotated[HTTPAuthorizationCredentials, Depends(bearer_security)],
61
+ ) -> T | None:
62
+ """
63
+ Verify the JWT access token using OIDC authority JWKS.
64
+ """
65
+ global _JWKS
66
+
67
+ if not oidc_settings.enabled:
68
+ return None
62
69
 
63
- if not oidc_settings.enabled:
64
- return None
70
+ token = authorization.credentials
65
71
 
66
- token = authorization.credentials
72
+ try:
73
+ if not _JWKS:
74
+ openid_config = await fetch_openid_config()
75
+ _JWKS = await fetch_jwks(openid_config['jwks_uri'])
67
76
 
68
- try:
69
- if not _JWKS:
70
- openid_config = await fetch_openid_config()
71
- _JWKS = await fetch_jwks(openid_config['jwks_uri'])
77
+ if oidc_settings.client_id:
78
+ payload = jwt.decode(token, _JWKS, algorithms=['RS256'], audience=oidc_settings.client_id)
79
+ else:
80
+ payload = jwt.decode(token, _JWKS, algorithms=['RS256'])
72
81
 
73
- if oidc_settings.client_id:
74
- payload = jwt.decode(token, _JWKS, algorithms=['RS256'], audience=oidc_settings.client_id)
75
- else:
76
- payload = jwt.decode(token, _JWKS, algorithms=['RS256'])
82
+ token_data = token_cls(**payload)
77
83
 
78
- token_data = TokenData(**payload)
84
+ return token_data
85
+ except jwt.ExpiredSignatureError:
86
+ raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail='Token has expired')
87
+ except JWTError as e:
88
+ raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail=f'Token is invalid: {str(e)}')
79
89
 
80
- return token_data
81
- except JWTError as e:
82
- raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=f'Token is invalid: {str(e)}')
90
+ return get_verified_token
@@ -1,3 +1,5 @@
1
+ import uuid
2
+
1
3
  from pydantic import AwareDatetime
2
4
  from sqlalchemy import BIGINT, DateTime
3
5
  from sqlalchemy.dialects.postgresql import UUID
@@ -32,7 +34,7 @@ class BaseDBModel:
32
34
 
33
35
 
34
36
  class BaseDBUUIDModel:
35
- uid: Mapped[UUID] = mapped_column(UUID, primary_key=True, sort_order=-3)
37
+ uid: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, sort_order=-3)
36
38
  created_at: Mapped[AwareDatetime] = mapped_column(
37
39
  DateTime(timezone=True), nullable=False, server_default=UTCNow(), sort_order=-2
38
40
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-commons
3
- Version: 0.8.30
3
+ Version: 0.8.32
4
4
  Summary: Re-usable Python3 code
5
5
  Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
6
  License-Expression: GPL-3.0
@@ -1,7 +1,7 @@
1
1
  python3_commons/__init__.py,sha256=0KgaYU46H_IMKn-BuasoRN3C4Hi45KlkHHoPbU9cwiA,189
2
2
  python3_commons/api_client.py,sha256=LT7_YmnYVHK2ucKxIhUJCZrmxgfy-lfOxx08-R0WvW0,4505
3
3
  python3_commons/audit.py,sha256=osx2ywZXf-V0zOkrhlNgSyzCBvojXQwSYBQ4-ze1xiM,6249
4
- python3_commons/auth.py,sha256=Fw2pudSkMAploLV2iOh_1LQalnijrO5kNCJfvA9cQfg,2485
4
+ python3_commons/auth.py,sha256=vVaiJ5MHUMSbiLF6TIxe4dqVPhBlLttf940jjODL3a4,2934
5
5
  python3_commons/cache.py,sha256=lf27LTD4Z9Iqi5GaK8jH8UC0cL9sHH8wicZ88YDp6Mg,7725
6
6
  python3_commons/conf.py,sha256=JenspXyTqTlYeEb8X9Njfje1AiLCee23nm0k8zhYLfs,2283
7
7
  python3_commons/fs.py,sha256=wfLjybXndwLqNlOxTpm_HRJnuTcC4wbrHEOaEeCo9Wc,337
@@ -12,7 +12,7 @@ python3_commons/db/__init__.py,sha256=5nArsGm17e-pelpOwAeBKy2n_Py20XqklZsNgkcJ-D
12
12
  python3_commons/db/helpers.py,sha256=PY0h08aLiGx-J54wmP3GHPCgGCcLd60rayAUnR3aWdI,1742
13
13
  python3_commons/db/models/__init__.py,sha256=Utr5AJf1FwcrxNtdesgjq92WMK4zpK4VL_8z1JEkJw0,185
14
14
  python3_commons/db/models/auth.py,sha256=dmyD3BX7LVBgKiepPN-bxlY6J3PhcmUfVdQwhNR45fU,1187
15
- python3_commons/db/models/common.py,sha256=fVc-q0UKp3HqYPd99KNKlfMlQwMel1g81167UUx5Ils,1519
15
+ python3_commons/db/models/common.py,sha256=IwrVfMQhAkPqrPmPRkG9CAB0KRa6YG_0Mogs1aafAoA,1537
16
16
  python3_commons/db/models/rbac.py,sha256=7NNTUbS8whuPUHpm4oba_UWDdNiJlHrm8HBO7oGtk64,3185
17
17
  python3_commons/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  python3_commons/log/filters.py,sha256=fuyjXZAUm-i2MNrxvFYag8F8Rr27x8W8MdV3ke6miSs,175
@@ -21,9 +21,9 @@ python3_commons/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
21
21
  python3_commons/serializers/json.py,sha256=91UaXLGKGj0yPyrnuMeNrkG2GuPUgcgAsmIokUgEwpU,808
22
22
  python3_commons/serializers/msgpack.py,sha256=WrvaPE187shSK8zkH4UHHMimEZNMv9RaDSwsBE2HlCw,1269
23
23
  python3_commons/serializers/msgspec.py,sha256=5SS_wQXcrThPmCWjI7k1a_cHWLz46Jzn3pit89SYJGY,2038
24
- python3_commons-0.8.30.dist-info/licenses/AUTHORS.rst,sha256=3R9JnfjfjH5RoPWOeqKFJgxVShSSfzQPIrEr1nxIo9Q,90
25
- python3_commons-0.8.30.dist-info/licenses/LICENSE,sha256=xxILuojHm4fKQOrMHPSslbyy6WuKAN2RiG74HbrYfzM,34575
26
- python3_commons-0.8.30.dist-info/METADATA,sha256=wkDWtG3uM8iLKMbCVxLmdTWHD3iUnW3wAHbQvO_Jl1Q,1126
27
- python3_commons-0.8.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- python3_commons-0.8.30.dist-info/top_level.txt,sha256=lJI6sCBf68eUHzupCnn2dzG10lH3jJKTWM_hrN1cQ7M,16
29
- python3_commons-0.8.30.dist-info/RECORD,,
24
+ python3_commons-0.8.32.dist-info/licenses/AUTHORS.rst,sha256=3R9JnfjfjH5RoPWOeqKFJgxVShSSfzQPIrEr1nxIo9Q,90
25
+ python3_commons-0.8.32.dist-info/licenses/LICENSE,sha256=xxILuojHm4fKQOrMHPSslbyy6WuKAN2RiG74HbrYfzM,34575
26
+ python3_commons-0.8.32.dist-info/METADATA,sha256=Rb556zpK-HLmuPCZ7uBMz5t1XU2ADUVUGcVcmzhZHY8,1126
27
+ python3_commons-0.8.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ python3_commons-0.8.32.dist-info/top_level.txt,sha256=lJI6sCBf68eUHzupCnn2dzG10lH3jJKTWM_hrN1cQ7M,16
29
+ python3_commons-0.8.32.dist-info/RECORD,,