usso 0.20.7__tar.gz → 0.21.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.20.7
3
+ Version: 0.21.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>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "usso"
7
- version = "0.20.7"
7
+ version = "0.21.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"
@@ -88,7 +88,9 @@ class UssoAPI(metaclass=Singleton):
88
88
  def get_users(self, **kwargs) -> list[UserData]:
89
89
  users_dict = self._request(endpoint="website/users", **kwargs)
90
90
 
91
- return [UserData(user_id=user.get("uid"), **user) for user in users_dict]
91
+ return [
92
+ UserData(user_id=user.get("uid"), **user) for user in users_dict
93
+ ]
92
94
 
93
95
  def get_user(self, user_id: str, **kwargs) -> UserData:
94
96
  user_dict = self._request(
@@ -144,7 +146,9 @@ class UssoAPI(metaclass=Singleton):
144
146
  return UserData(user_id=user_dict.get("uid"), **user_dict)
145
147
 
146
148
  def get_user_payload(self, user_id: str, **kwargs) -> dict:
147
- return self._request(endpoint=f"website/users/{user_id}/payload", **kwargs)
149
+ return self._request(
150
+ endpoint=f"website/users/{user_id}/payload", **kwargs
151
+ )
148
152
 
149
153
  def update_user_payload(
150
154
  self,
@@ -2,8 +2,11 @@ import base64
2
2
  import uuid
3
3
 
4
4
 
5
- def b64_encode_uuid(uuid_str):
6
- uuid_bytes = uuid.UUID(uuid_str).bytes
5
+ def b64_encode_uuid(uuid_str: uuid.UUID | str):
6
+ uuid_UUID = (
7
+ uuid_str if isinstance(uuid_str, uuid.UUID) else uuid.UUID(uuid_str)
8
+ )
9
+ uuid_bytes = uuid_UUID.bytes
7
10
  encoded_uuid = base64.urlsafe_b64encode(uuid_bytes).decode()
8
11
  return encoded_uuid
9
12
 
@@ -71,23 +71,46 @@ class Usso(metaclass=Singleton):
71
71
  signing_key.key,
72
72
  algorithms=["RS256"],
73
73
  )
74
+ if decoded["token_type"] != "access":
75
+ raise USSOException(
76
+ status_code=401,
77
+ error="invalid_token_type",
78
+ )
74
79
  decoded["token"] = token
75
-
80
+ return UserData(**decoded)
76
81
  except jwt.exceptions.ExpiredSignatureError:
77
82
  if kwargs.get("raise_exception"):
78
83
  raise USSOException(status_code=401, error="expired_signature")
79
- return None
80
84
  except jwt.exceptions.InvalidSignatureError:
81
85
  if kwargs.get("raise_exception"):
82
86
  raise USSOException(status_code=401, error="invalid_signature")
83
- return None
87
+ except jwt.exceptions.InvalidAlgorithmError:
88
+ if kwargs.get("raise_exception"):
89
+ raise USSOException(
90
+ status_code=401,
91
+ error="invalid_algorithm",
92
+ )
93
+ except jwt.exceptions.InvalidIssuedAtError:
94
+ if kwargs.get("raise_exception"):
95
+ raise USSOException(
96
+ status_code=401,
97
+ error="invalid_issued_at",
98
+ )
84
99
  except jwt.exceptions.InvalidTokenError:
85
100
  if kwargs.get("raise_exception"):
86
101
  raise USSOException(
87
102
  status_code=401,
88
103
  error="invalid_token",
89
104
  )
90
- return None
105
+ except jwt.exceptions.InvalidKeyError:
106
+ if kwargs.get("raise_exception"):
107
+ raise USSOException(
108
+ status_code=401,
109
+ error="invalid_key",
110
+ )
111
+ except USSOException as e:
112
+ if kwargs.get("raise_exception"):
113
+ raise e
91
114
  except Exception as e:
92
115
  if kwargs.get("raise_exception"):
93
116
  raise USSOException(
@@ -96,6 +119,3 @@ class Usso(metaclass=Singleton):
96
119
  message=str(e),
97
120
  )
98
121
  logger.error(e)
99
- return None
100
-
101
- return UserData(**decoded)
@@ -0,0 +1,35 @@
1
+ from datetime import datetime
2
+ import requests
3
+ import jwt
4
+
5
+
6
+ class UssoSession:
7
+ def __init__(self, sso_refresh_url: str, refresh_token: str | None = None):
8
+ self.sso_refresh_url = sso_refresh_url
9
+ self.refresh_token = refresh_token
10
+ self.session = requests.Session()
11
+ self.access_token = None
12
+
13
+ def _refresh(self):
14
+ if not self.refresh_token:
15
+ return
16
+
17
+ response = requests.post(
18
+ self.sso_refresh_url,
19
+ json={"refresh_token": f"{self.refresh_token}"},
20
+ )
21
+ response.raise_for_status()
22
+ return response.json()
23
+
24
+ def get_session(self):
25
+ if self.access_token:
26
+ decoded_token = jwt.decode(self.access_token, options={"verify_signature": False})
27
+ exp = datetime.fromtimestamp(decoded_token.get("exp"))
28
+ if exp < datetime.now():
29
+ self.access_token = None
30
+ if not self.access_token:
31
+ self.access_token = self._refresh()["access_token"]
32
+ self.session.headers.update(
33
+ {"Authorization": f"Bearer {self.access_token}"}
34
+ )
35
+ return self.session
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.20.7
3
+ Version: 0.21.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>
@@ -7,6 +7,7 @@ src/usso/b64tools.py
7
7
  src/usso/core.py
8
8
  src/usso/exceptions.py
9
9
  src/usso/package_data.dat
10
+ src/usso/session.py
10
11
  src/usso.egg-info/PKG-INFO
11
12
  src/usso.egg-info/SOURCES.txt
12
13
  src/usso.egg-info/dependency_links.txt
@@ -18,17 +18,16 @@ class TestAPI(unittest.TestCase):
18
18
  self.assertIsInstance(users, list)
19
19
  for user in users:
20
20
  self.assertIsInstance(user, UserData)
21
- return users
22
21
 
23
22
  def test_get_user(self):
24
- users = self.test_get_users()
23
+ usso_api = self.get_usso()
24
+ users = usso_api.get_users()
25
25
  if len(users) == 0:
26
26
  self.skipTest("No users found")
27
27
  user = users[0]
28
28
  usso_api = self.get_usso()
29
- user = usso_api.get_user(user["user_id"])
29
+ user = usso_api.get_user(user.user_id)
30
30
  self.assertIsInstance(user, UserData)
31
- return user
32
31
 
33
32
  def test_get_user_by_credentials(self):
34
33
  usso_api = self.get_usso()
@@ -43,13 +42,19 @@ class TestAPI(unittest.TestCase):
43
42
  }
44
43
  user = usso_api.get_user_by_credentials(cred)
45
44
  self.assertIsInstance(user, UserData)
46
- return user
47
45
 
48
46
  def test_create_user_by_credentials(self):
47
+ import requests
48
+
49
49
  usso_api = self.get_usso()
50
50
  telegram_id = os.getenv("TELEGRAM_ID")
51
51
  cred = {"auth_method": "telegram", "representor": telegram_id}
52
- usso_api.create_user_by_credentials(credentials=cred)
52
+ try:
53
+ usso_api.create_user_by_credentials(credentials=cred)
54
+ except requests.HTTPError as e:
55
+ if e.response.status_code == 400:
56
+ if e.response.json().get("error") == "already_exists":
57
+ self.skipTest("Credential already exists")
53
58
 
54
59
 
55
60
  if __name__ == "__main__":
@@ -8,9 +8,9 @@ import unittest
8
8
  class TestSimple(unittest.TestCase):
9
9
  def test_import(self):
10
10
  import usso
11
-
11
+
12
12
  usso.Usso()
13
- usso.UserData()
13
+ usso.UserData(user_id='123')
14
14
 
15
15
 
16
16
  if __name__ == "__main__":
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes