usso 0.24.11__py3-none-any.whl → 0.24.12__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.
usso/async_session.py CHANGED
@@ -1,21 +1,51 @@
1
1
  from contextlib import asynccontextmanager
2
- from datetime import datetime
2
+ from datetime import datetime, timedelta
3
3
 
4
4
  import aiohttp
5
5
  import jwt
6
6
 
7
7
 
8
8
  class AsyncUssoSession:
9
- def __init__(self, sso_refresh_url: str, refresh_token: str | None = None):
9
+ def __init__(
10
+ self,
11
+ sso_refresh_url: str,
12
+ refresh_token: str | None = None,
13
+ api_key: str | None = None,
14
+ ):
10
15
  self.sso_refresh_url = sso_refresh_url
11
- self.refresh_token = refresh_token
16
+ self._refresh_token = refresh_token
12
17
  self.access_token = None
13
18
  self.session = None # This will hold the aiohttp session
19
+ self.api_key = api_key
20
+
21
+ @property
22
+ def refresh_token(self):
23
+ decoded_token = jwt.decode(
24
+ self._refresh_token, options={"verify_signature": False}
25
+ )
26
+ exp = decoded_token.get("exp", datetime.now() + timedelta(days=1))
27
+ if exp < datetime.now():
28
+ self._refresh_token = None
29
+
30
+ return self._refresh_token
31
+
32
+ async def _refresh_api(self):
33
+ async with aiohttp.ClientSession() as session:
34
+ async with session.get(
35
+ f"{self.sso_refresh_url}/api",
36
+ headers={"x-api-key": self.api_key},
37
+ ) as response:
38
+ response.raise_for_status()
39
+ data: dict = await response.json()
40
+ self._refresh_token = data.get("token", {}).get("refresh_token")
14
41
 
15
42
  async def _refresh(self):
16
- if not self.refresh_token:
43
+ if not self.refresh_token and not self.api_key:
17
44
  raise ValueError("Refresh token not provided or invalid.")
18
45
 
46
+ if self.api_key and not self.refresh_token:
47
+ self._refresh_api()
48
+
19
49
  async with aiohttp.ClientSession() as session:
20
50
  async with session.post(
21
51
  self.sso_refresh_url,
usso/core.py CHANGED
@@ -64,23 +64,11 @@ class Usso(metaclass=Singleton):
64
64
  scheme, _, param = authorization_header_value.partition(" ")
65
65
  return scheme, param
66
66
 
67
- def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
68
- """Return the user associated with a token value."""
67
+ def decode_token(self, key, token: str, **kwargs) -> dict:
69
68
  try:
70
- # header = jwt.get_unverified_header(token)
71
- # jwks_url = header["jwk_url"]
72
- jwks_client = self.get_jwks_keys()
73
- signing_key = jwks_client.get_signing_key_from_jwt(token)
74
- decoded = jwt.decode(
75
- token,
76
- signing_key.key,
77
- algorithms=["RS256"],
78
- )
69
+ decoded = jwt.decode(token, key, algorithms=["RS256"])
79
70
  if decoded["token_type"] != "access":
80
- raise USSOException(
81
- status_code=401,
82
- error="invalid_token_type",
83
- )
71
+ raise USSOException(status_code=401, error="invalid_token_type")
84
72
  decoded["token"] = token
85
73
  return UserData(**decoded)
86
74
  except jwt.exceptions.ExpiredSignatureError:
@@ -91,31 +79,30 @@ class Usso(metaclass=Singleton):
91
79
  raise USSOException(status_code=401, error="invalid_signature")
92
80
  except jwt.exceptions.InvalidAlgorithmError:
93
81
  if kwargs.get("raise_exception", True):
94
- raise USSOException(
95
- status_code=401,
96
- error="invalid_algorithm",
97
- )
82
+ raise USSOException(status_code=401, error="invalid_algorithm")
98
83
  except jwt.exceptions.InvalidIssuedAtError:
99
84
  if kwargs.get("raise_exception", True):
100
- raise USSOException(
101
- status_code=401,
102
- error="invalid_issued_at",
103
- )
85
+ raise USSOException(status_code=401, error="invalid_issued_at")
104
86
  except jwt.exceptions.InvalidTokenError:
105
87
  if kwargs.get("raise_exception", True):
106
- raise USSOException(
107
- status_code=401,
108
- error="invalid_token",
109
- )
88
+ raise USSOException(status_code=401, error="invalid_token")
110
89
  except jwt.exceptions.InvalidKeyError:
111
90
  if kwargs.get("raise_exception", True):
112
- raise USSOException(
113
- status_code=401,
114
- error="invalid_key",
115
- )
91
+ raise USSOException(status_code=401, error="invalid_key")
116
92
  except USSOException as e:
117
93
  if kwargs.get("raise_exception", True):
118
94
  raise e
95
+ except Exception as e:
96
+ if kwargs.get("raise_exception", True):
97
+ raise USSOException(status_code=401, error="error", message=str(e))
98
+ logger.error(e)
99
+
100
+ def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
101
+ """Return the user associated with a token value."""
102
+ try:
103
+ jwks_client = self.get_jwks_keys()
104
+ signing_key = jwks_client.get_signing_key_from_jwt(token)
105
+ return self.decode_token(signing_key.key, token, **kwargs)
119
106
  except Exception as e:
120
107
  if kwargs.get("raise_exception", True):
121
108
  raise USSOException(
@@ -73,15 +73,45 @@ class Usso:
73
73
  scheme, _, param = authorization_header_value.partition(" ")
74
74
  return scheme, param
75
75
 
76
+ def decode_token(self, key, token: str, **kwargs) -> dict:
77
+ try:
78
+ decoded = jwt.decode(token, key, algorithms=["RS256"])
79
+ if decoded["token_type"] != "access":
80
+ raise USSOException(status_code=401, error="invalid_token_type")
81
+ decoded["token"] = token
82
+ return UserData(**decoded)
83
+ except jwt.exceptions.ExpiredSignatureError:
84
+ if kwargs.get("raise_exception", True):
85
+ raise USSOException(status_code=401, error="expired_signature")
86
+ except jwt.exceptions.InvalidSignatureError:
87
+ if kwargs.get("raise_exception", True):
88
+ raise USSOException(status_code=401, error="invalid_signature")
89
+ except jwt.exceptions.InvalidAlgorithmError:
90
+ if kwargs.get("raise_exception", True):
91
+ raise USSOException(status_code=401, error="invalid_algorithm")
92
+ except jwt.exceptions.InvalidIssuedAtError:
93
+ if kwargs.get("raise_exception", True):
94
+ raise USSOException(status_code=401, error="invalid_issued_at")
95
+ except jwt.exceptions.InvalidTokenError:
96
+ if kwargs.get("raise_exception", True):
97
+ raise USSOException(status_code=401, error="invalid_token")
98
+ except jwt.exceptions.InvalidKeyError:
99
+ if kwargs.get("raise_exception", True):
100
+ raise USSOException(status_code=401, error="invalid_key")
101
+ except USSOException as e:
102
+ if kwargs.get("raise_exception", True):
103
+ raise e
104
+ except Exception as e:
105
+ if kwargs.get("raise_exception", True):
106
+ raise USSOException(status_code=401, error="error", message=str(e))
107
+ logger.error(e)
108
+
76
109
  def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
77
110
  """Return the user associated with a token value."""
78
111
  try:
79
112
  decoded = self.jwk_url.decode(token)
80
113
  if decoded["token_type"] != "access":
81
- raise USSOException(
82
- status_code=401,
83
- error="invalid_token_type",
84
- )
114
+ raise USSOException(status_code=401, error="invalid_token_type")
85
115
  decoded["token"] = token
86
116
  return UserData(**decoded)
87
117
  except jwt.exceptions.ExpiredSignatureError:
@@ -92,45 +122,25 @@ class Usso:
92
122
  raise USSOException(status_code=401, error="invalid_signature")
93
123
  except jwt.exceptions.InvalidAlgorithmError:
94
124
  if kwargs.get("raise_exception", True):
95
- raise USSOException(
96
- status_code=401,
97
- error="invalid_algorithm",
98
- )
125
+ raise USSOException(status_code=401, error="invalid_algorithm")
99
126
  except jwt.exceptions.InvalidIssuedAtError:
100
127
  if kwargs.get("raise_exception", True):
101
- raise USSOException(
102
- status_code=401,
103
- error="invalid_issued_at",
104
- )
128
+ raise USSOException(status_code=401, error="invalid_issued_at")
105
129
  except jwt.exceptions.InvalidTokenError:
106
130
  if kwargs.get("raise_exception", True):
107
- raise USSOException(
108
- status_code=401,
109
- error="invalid_token",
110
- )
131
+ raise USSOException(status_code=401, error="invalid_token")
111
132
  except jwt.exceptions.InvalidKeyError:
112
133
  if kwargs.get("raise_exception", True):
113
- raise USSOException(
114
- status_code=401,
115
- error="invalid_key",
116
- )
134
+ raise USSOException(status_code=401, error="invalid_key")
117
135
  except KeyError as e:
118
136
  if kwargs.get("raise_exception", True):
119
- raise USSOException(
120
- status_code=401,
121
- error="key_error",
122
- message=str(e),
123
- )
137
+ raise USSOException(status_code=401, error="key_error", message=str(e))
124
138
  except USSOException as e:
125
139
  if kwargs.get("raise_exception", True):
126
140
  raise e
127
141
  except Exception as e:
128
142
  if kwargs.get("raise_exception", True):
129
- raise USSOException(
130
- status_code=401,
131
- error="error",
132
- message=str(e),
133
- )
143
+ raise USSOException(status_code=401, error="error", message=str(e))
134
144
  logger.error(e)
135
145
 
136
146
  async def jwt_access_security(self, request: Request) -> UserData | None:
usso/session.py CHANGED
@@ -1,19 +1,49 @@
1
- from datetime import datetime
1
+ from datetime import datetime, timedelta
2
2
 
3
3
  import jwt
4
4
  import requests
5
5
 
6
6
 
7
7
  class UssoSession:
8
- def __init__(self, sso_refresh_url: str, refresh_token: str | None = None):
8
+
9
+ def __init__(
10
+ self,
11
+ sso_refresh_url: str,
12
+ refresh_token: str | None = None,
13
+ api_key: str | None = None,
14
+ ):
9
15
  self.sso_refresh_url = sso_refresh_url
10
- self.refresh_token = refresh_token
16
+ self._refresh_token = refresh_token
11
17
  self.session = requests.Session()
12
18
  self.access_token = None
19
+ self.api_key = api_key
20
+
21
+ @property
22
+ def refresh_token(self):
23
+ decoded_token = jwt.decode(
24
+ self._refresh_token, options={"verify_signature": False}
25
+ )
26
+ exp = decoded_token.get("exp", datetime.now() + timedelta(days=1))
27
+ if exp < datetime.now():
28
+ self._refresh_token = None
29
+
30
+ return self._refresh_token
31
+
32
+ def _refresh_api(self):
33
+ response = requests.get(
34
+ f"{self.sso_refresh_url}/api",
35
+ headers={"x-api-key": self.api_key},
36
+ )
37
+ response.raise_for_status()
38
+ data = response.json()
39
+ self._refresh_token = data.get("token", {}).get("refresh_token")
13
40
 
14
41
  def _refresh(self):
15
- if not self.refresh_token:
42
+ if not self.refresh_token and not self.api_key:
16
43
  return
44
+
45
+ if self.api_key and not self.refresh_token:
46
+ self._refresh_api()
17
47
 
18
48
  response = requests.post(
19
49
  self.sso_refresh_url,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.24.11
3
+ Version: 0.24.12
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>
@@ -1,20 +1,20 @@
1
1
  usso/__init__.py,sha256=NnOS_S1a-JKTOlGe1nw-kCL3m0y82mA2mDraus7BQ2o,120
2
2
  usso/api.py,sha256=xlDq2nZNpq3mhAvqIbGEfANHNjJpPquSeULBfS7iMJw,5094
3
3
  usso/async_api.py,sha256=rb-Xh5oudmZrPYM_iH_B75b5Z0Fvi1V1uurdcKE51w0,5551
4
- usso/async_session.py,sha256=EPHT0wjwGuRg3NLvtUlLNSVZCgvAvRyUGx21XBsEBHk,3028
4
+ usso/async_session.py,sha256=whaxQjR1tkarOljknrhNyPAS5sHvYasBszvd0_MoN3Q,4015
5
5
  usso/b64tools.py,sha256=HGQ0E59vzjrQo2-4jrcY03ebtTaYwTtCZ7KgJaEmxO0,610
6
- usso/core.py,sha256=m6Y-g70FuPYZM3AMtsEVVToQkYrf4WwNVH8C4HZRzl8,4103
6
+ usso/core.py,sha256=cOpETK_gGVsUJT0EeIebOGLEbF8vHVET-_I-8QxOCyE,3977
7
7
  usso/exceptions.py,sha256=hawOAuVbvQtjgRfwp1KFZ4SmV7fh720y5Gom9JVA8W8,504
8
8
  usso/package_data.dat,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- usso/session.py,sha256=S3dFXzar0Pcwxj5TGqadKwGdmzmzgp4H2W3brfOwJ6A,1184
9
+ usso/session.py,sha256=4KFePzs9gjtoPOpcrKR8A-GWtUF3zhVBAAWzKaA3lm8,2055
10
10
  usso/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  usso/django/middleware.py,sha256=EEEpHvMQ6QiWw2HY8zQ2Aec0RCATcLWsCKeyiPWJKio,3245
12
12
  usso/fastapi/__init__.py,sha256=0EcdOzb4f3yu9nILIdGWnlyUz-0VaVX2az1e3f2BusI,201
13
- usso/fastapi/auth_middleware.py,sha256=5JnDHvBM_xfasSHpBIFlrxFsZTLS2AhMuvyzr0tyI8k,6323
13
+ usso/fastapi/auth_middleware.py,sha256=DYrNPy_9FIV1amRuafoJtgGMi8uE0FPmSKBUGP79GNo,7616
14
14
  usso/fastapi/integration.py,sha256=VAUWaa7ChQ1jTtn8A136VgyG6t2kDo5pGK-3RgmNDVs,1669
15
- usso-0.24.11.dist-info/LICENSE.txt,sha256=ceC9ZJOV9H6CtQDcYmHOS46NA3dHJ_WD4J9blH513pc,1081
16
- usso-0.24.11.dist-info/METADATA,sha256=q-FE19C5UYkURUE1vqgifDzb52Dxf1irEWjyhwiijYg,4275
17
- usso-0.24.11.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
18
- usso-0.24.11.dist-info/entry_points.txt,sha256=4Zgpm5ELaAWPf0jPGJFz1_X69H7un8ycT3WdGoJ0Vvk,35
19
- usso-0.24.11.dist-info/top_level.txt,sha256=g9Jf6h1Oyidh0vPiFni7UHInTJjSvu6cUalpLTIvthg,5
20
- usso-0.24.11.dist-info/RECORD,,
15
+ usso-0.24.12.dist-info/LICENSE.txt,sha256=ceC9ZJOV9H6CtQDcYmHOS46NA3dHJ_WD4J9blH513pc,1081
16
+ usso-0.24.12.dist-info/METADATA,sha256=3ZTqFGl6CCBk-YIXYsDy6IECFv1nAbdhWKI-s1aEUD8,4275
17
+ usso-0.24.12.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
18
+ usso-0.24.12.dist-info/entry_points.txt,sha256=4Zgpm5ELaAWPf0jPGJFz1_X69H7un8ycT3WdGoJ0Vvk,35
19
+ usso-0.24.12.dist-info/top_level.txt,sha256=g9Jf6h1Oyidh0vPiFni7UHInTJjSvu6cUalpLTIvthg,5
20
+ usso-0.24.12.dist-info/RECORD,,
File without changes