usso 0.25.0__tar.gz → 0.25.1__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.
Files changed (28) hide show
  1. {usso-0.25.0/src/usso.egg-info → usso-0.25.1}/PKG-INFO +2 -2
  2. {usso-0.25.0 → usso-0.25.1}/pyproject.toml +3 -2
  3. {usso-0.25.0 → usso-0.25.1}/src/usso/core.py +53 -26
  4. {usso-0.25.0 → usso-0.25.1}/src/usso/fastapi/integration.py +2 -1
  5. {usso-0.25.0 → usso-0.25.1/src/usso.egg-info}/PKG-INFO +2 -2
  6. {usso-0.25.0 → usso-0.25.1}/src/usso.egg-info/SOURCES.txt +0 -2
  7. usso-0.25.0/src/usso/fastapi/auth_middleware.py +0 -87
  8. usso-0.25.0/src/usso/package_data.dat +0 -0
  9. {usso-0.25.0 → usso-0.25.1}/LICENSE.txt +0 -0
  10. {usso-0.25.0 → usso-0.25.1}/README.md +0 -0
  11. {usso-0.25.0 → usso-0.25.1}/setup.cfg +0 -0
  12. {usso-0.25.0 → usso-0.25.1}/src/usso/__init__.py +0 -0
  13. {usso-0.25.0 → usso-0.25.1}/src/usso/api.py +0 -0
  14. {usso-0.25.0 → usso-0.25.1}/src/usso/async_api.py +0 -0
  15. {usso-0.25.0 → usso-0.25.1}/src/usso/async_session.py +0 -0
  16. {usso-0.25.0 → usso-0.25.1}/src/usso/b64tools.py +0 -0
  17. {usso-0.25.0 → usso-0.25.1}/src/usso/django/__init__.py +0 -0
  18. {usso-0.25.0 → usso-0.25.1}/src/usso/django/middleware.py +0 -0
  19. {usso-0.25.0 → usso-0.25.1}/src/usso/exceptions.py +0 -0
  20. {usso-0.25.0 → usso-0.25.1}/src/usso/fastapi/__init__.py +0 -0
  21. {usso-0.25.0 → usso-0.25.1}/src/usso/session.py +0 -0
  22. {usso-0.25.0 → usso-0.25.1}/src/usso.egg-info/dependency_links.txt +0 -0
  23. {usso-0.25.0 → usso-0.25.1}/src/usso.egg-info/entry_points.txt +0 -0
  24. {usso-0.25.0 → usso-0.25.1}/src/usso.egg-info/requires.txt +1 -1
  25. {usso-0.25.0 → usso-0.25.1}/src/usso.egg-info/top_level.txt +0 -0
  26. {usso-0.25.0 → usso-0.25.1}/tests/test_api.py +0 -0
  27. {usso-0.25.0 → usso-0.25.1}/tests/test_core.py +0 -0
  28. {usso-0.25.0 → usso-0.25.1}/tests/test_simple.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.25.0
3
+ Version: 0.25.1
4
4
  Summary: A plug-and-play client for integrating universal single sign-on (SSO) with Python frameworks, enabling secure and seamless authentication across microservices.
5
5
  Author-email: Mahdi Kiani <mahdikiany@gmail.com>
6
6
  Maintainer-email: Mahdi Kiani <mahdikiany@gmail.com>
@@ -46,10 +46,10 @@ Requires-Dist: pydantic>=2
46
46
  Requires-Dist: requests>=2.26.0
47
47
  Requires-Dist: pyjwt[crypto]
48
48
  Requires-Dist: singleton_package
49
+ Requires-Dist: cachetools
49
50
  Provides-Extra: fastapi
50
51
  Requires-Dist: fastapi>=0.65.0; extra == "fastapi"
51
52
  Requires-Dist: uvicorn[standard]>=0.13.0; extra == "fastapi"
52
- Requires-Dist: cachetools; extra == "fastapi"
53
53
  Provides-Extra: django
54
54
  Requires-Dist: Django>=3.2; extra == "django"
55
55
  Provides-Extra: dev
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "usso"
7
- version = "0.25.0"
7
+ version = "0.25.1"
8
8
  description = "A plug-and-play client for integrating universal single sign-on (SSO) with Python frameworks, enabling secure and seamless authentication across microservices."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -32,8 +32,9 @@ dependencies = [
32
32
  "requests>=2.26.0",
33
33
  "pyjwt[crypto]",
34
34
  "singleton_package",
35
+ "cachetools",
35
36
  ]
36
- optional-dependencies = {"fastapi" = ["fastapi>=0.65.0", "uvicorn[standard]>=0.13.0", "cachetools"],"django" = ["Django>=3.2"],"dev" = ["check-manifest"],"test" = ["coverage"]}
37
+ optional-dependencies = {"fastapi" = ["fastapi>=0.65.0", "uvicorn[standard]>=0.13.0"],"django" = ["Django>=3.2"],"dev" = ["check-manifest"],"test" = ["coverage"]}
37
38
 
38
39
  [project.urls]
39
40
  "Homepage" = "https://github.com/ussoio/usso-python"
@@ -1,8 +1,8 @@
1
+ import json
1
2
  import logging
2
3
  import os
3
4
  import uuid
4
5
  from functools import lru_cache
5
- from typing import Optional, Tuple
6
6
 
7
7
  import cachetools.func
8
8
  import jwt
@@ -142,33 +142,60 @@ class JWTConfig(BaseModel):
142
142
  return decode_token(self.secret, token, algorithms=[self.type])
143
143
 
144
144
 
145
- class Usso(metaclass=Singleton):
146
- def __init__(self, jwks_url: str | None = None):
147
- if jwks_url is None:
148
- jwks_url = os.getenv("USSO_JWKS_URL")
149
- self.jwks_url = jwks_url
145
+ class Usso:
146
+
147
+ def __init__(
148
+ self,
149
+ *,
150
+ jwt_config: str | dict | JWTConfig | None = None,
151
+ jwt_configs: list[str] | list[dict] | list[JWTConfig] | None = None,
152
+ ):
153
+ if jwt_config is None and jwt_configs is None:
154
+ jwt_config = os.getenv("USSO_JWT_CONFIG")
155
+
156
+ if jwt_config is None and jwt_configs is None:
157
+ jwk_url = os.getenv("USSO_JWK_URL") or os.getenv("USSO_JWKS_URL")
158
+ if not jwk_url:
159
+ self.jwt_configs = [JWTConfig(jwk_url=jwk_url)]
160
+ return
161
+
162
+ raise ValueError(
163
+ "\n".join(
164
+ [
165
+ "Either jwt_config or jwt_configs must be provided",
166
+ "or set the environment variable USSO_JWT_CONFIG or USSO_JWK_URL",
167
+ ]
168
+ )
169
+ )
170
+
171
+ def _get_config(jwt_config):
172
+ if isinstance(jwt_config, str):
173
+ jwt_config = json.loads(jwt_config)
174
+ if isinstance(jwt_config, dict):
175
+ jwt_config = JWTConfig(**jwt_config)
176
+ return jwt_config
150
177
 
151
- def get_jwk_keys(self):
152
- return get_jwk_keys(self.jwks_url)
178
+ if isinstance(jwt_config, str | dict | JWTConfig):
179
+ jwt_config = [_get_config(jwt_config)]
180
+ elif isinstance(jwt_config, list):
181
+ jwt_config = [_get_config(j) for j in jwt_config]
153
182
 
154
- def get_authorization_scheme_param(
155
- self, authorization_header_value: Optional[str]
156
- ) -> Tuple[str, str]:
157
- return get_authorization_scheme_param(authorization_header_value)
183
+ # self.jwk_url = jwt_config
184
+ self.jwt_configs = jwt_config
158
185
 
159
186
  def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
160
187
  """Return the user associated with a token value."""
161
- user_data = decode_token_jwk(self.jwks_url, token, **kwargs)
162
- if user_data.token_type.lower() != kwargs.get("token_type", "access"):
163
- raise USSOException(status_code=401, error="invalid_token_type")
164
- return user_data
165
-
166
- def user_data_from_token_none(self, token: str, **kwargs) -> UserData | None:
167
- try:
168
- return self.user_data_from_token(token, **kwargs)
169
- except USSOException:
170
- # logger.error(str(e))
171
- return None
172
- except Exception:
173
- # logger.error(str(e))
174
- return None
188
+ exp = None
189
+ for jwk_config in self.jwt_configs:
190
+ try:
191
+ return jwk_config.decode(token)
192
+ except USSOException as e:
193
+ exp = e
194
+
195
+ if kwargs.get("raise_exception", True):
196
+ if exp:
197
+ raise exp
198
+ raise USSOException(
199
+ status_code=401,
200
+ error="unauthorized",
201
+ )
@@ -3,9 +3,10 @@ import logging
3
3
  from fastapi import Request, WebSocket
4
4
  from starlette.status import HTTP_401_UNAUTHORIZED
5
5
 
6
- from usso.core import UserData, Usso
7
6
  from usso.exceptions import USSOException
8
7
 
8
+ from ..core import UserData, Usso
9
+
9
10
  logger = logging.getLogger("usso")
10
11
 
11
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.25.0
3
+ Version: 0.25.1
4
4
  Summary: A plug-and-play client for integrating universal single sign-on (SSO) with Python frameworks, enabling secure and seamless authentication across microservices.
5
5
  Author-email: Mahdi Kiani <mahdikiany@gmail.com>
6
6
  Maintainer-email: Mahdi Kiani <mahdikiany@gmail.com>
@@ -46,10 +46,10 @@ Requires-Dist: pydantic>=2
46
46
  Requires-Dist: requests>=2.26.0
47
47
  Requires-Dist: pyjwt[crypto]
48
48
  Requires-Dist: singleton_package
49
+ Requires-Dist: cachetools
49
50
  Provides-Extra: fastapi
50
51
  Requires-Dist: fastapi>=0.65.0; extra == "fastapi"
51
52
  Requires-Dist: uvicorn[standard]>=0.13.0; extra == "fastapi"
52
- Requires-Dist: cachetools; extra == "fastapi"
53
53
  Provides-Extra: django
54
54
  Requires-Dist: Django>=3.2; extra == "django"
55
55
  Provides-Extra: dev
@@ -8,7 +8,6 @@ src/usso/async_session.py
8
8
  src/usso/b64tools.py
9
9
  src/usso/core.py
10
10
  src/usso/exceptions.py
11
- src/usso/package_data.dat
12
11
  src/usso/session.py
13
12
  src/usso.egg-info/PKG-INFO
14
13
  src/usso.egg-info/SOURCES.txt
@@ -19,7 +18,6 @@ src/usso.egg-info/top_level.txt
19
18
  src/usso/django/__init__.py
20
19
  src/usso/django/middleware.py
21
20
  src/usso/fastapi/__init__.py
22
- src/usso/fastapi/auth_middleware.py
23
21
  src/usso/fastapi/integration.py
24
22
  tests/test_api.py
25
23
  tests/test_core.py
@@ -1,87 +0,0 @@
1
- import json
2
- import logging
3
- import os
4
-
5
- from fastapi import Request, WebSocket
6
- from starlette.status import HTTP_401_UNAUTHORIZED
7
-
8
- from usso.exceptions import USSOException
9
-
10
- from ..core import JWTConfig, UserData
11
- from .integration import get_request_token
12
-
13
- logger = logging.getLogger("usso")
14
-
15
-
16
- class Usso:
17
-
18
- def __init__(
19
- self,
20
- jwt_config: (
21
- str | dict | JWTConfig | list[str] | list[dict] | list[JWTConfig] | None
22
- ) = None,
23
- ):
24
- if jwt_config is None:
25
- self.jwk_url = os.getenv("USSO_JWK_URL")
26
- self.jwt_configs = [JWTConfig(jwk_url=self.jwk_url)]
27
- return
28
-
29
- def _get_config(jwt_config):
30
- if isinstance(jwt_config, str):
31
- jwt_config = json.loads(jwt_config)
32
- if isinstance(jwt_config, dict):
33
- jwt_config = JWTConfig(**jwt_config)
34
- return jwt_config
35
-
36
- if isinstance(jwt_config, str | dict | JWTConfig):
37
- jwt_config = [_get_config(jwt_config)]
38
- elif isinstance(jwt_config, list):
39
- jwt_config = [_get_config(j) for j in jwt_config]
40
-
41
- # self.jwk_url = jwt_config
42
- self.jwt_configs = jwt_config
43
-
44
- def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
45
- """Return the user associated with a token value."""
46
- exp = None
47
- for jwk_config in self.jwt_configs:
48
- try:
49
- return jwk_config.decode(token)
50
- except USSOException as e:
51
- exp = e
52
-
53
- if kwargs.get("raise_exception", True):
54
- if exp:
55
- raise exp
56
- raise USSOException(
57
- status_code=HTTP_401_UNAUTHORIZED,
58
- error="unauthorized",
59
- )
60
-
61
- async def jwt_access_security(self, request: Request, **kwargs) -> UserData | None:
62
- """Return the user associated with a token value."""
63
- token = get_request_token(request)
64
- if token:
65
- return self.user_data_from_token(token)
66
-
67
- if kwargs.get("raise_exception", True):
68
- raise USSOException(
69
- status_code=HTTP_401_UNAUTHORIZED,
70
- error="unauthorized",
71
- )
72
- return None
73
-
74
- async def jwt_access_security_ws(
75
- self, websocket: WebSocket, **kwargs
76
- ) -> UserData | None:
77
- """Return the user associated with a token value."""
78
- token = get_request_token(websocket)
79
- if token:
80
- return self.user_data_from_token(token)
81
-
82
- if kwargs.get("raise_exception", True):
83
- raise USSOException(
84
- status_code=HTTP_401_UNAUTHORIZED,
85
- error="unauthorized",
86
- )
87
- return None
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -2,6 +2,7 @@ pydantic>=2
2
2
  requests>=2.26.0
3
3
  pyjwt[crypto]
4
4
  singleton_package
5
+ cachetools
5
6
 
6
7
  [dev]
7
8
  check-manifest
@@ -12,7 +13,6 @@ Django>=3.2
12
13
  [fastapi]
13
14
  fastapi>=0.65.0
14
15
  uvicorn[standard]>=0.13.0
15
- cachetools
16
16
 
17
17
  [test]
18
18
  coverage
File without changes
File without changes
File without changes