dj-jwt-auth 1.6.0__tar.gz → 1.7.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. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/PKG-INFO +6 -1
  2. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/dj_jwt_auth.egg-info/PKG-INFO +6 -1
  3. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/config.py +4 -1
  4. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/exceptions.py +6 -0
  5. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/middleware.py +3 -0
  6. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/user.py +7 -7
  7. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/setup.cfg +2 -1
  8. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/tests/test.py +24 -4
  9. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/MANIFEST.in +0 -0
  10. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/README.md +0 -0
  11. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/dj_jwt_auth.egg-info/SOURCES.txt +0 -0
  12. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/dj_jwt_auth.egg-info/dependency_links.txt +0 -0
  13. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/dj_jwt_auth.egg-info/requires.txt +0 -0
  14. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/dj_jwt_auth.egg-info/top_level.txt +0 -0
  15. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/__init__.py +0 -0
  16. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/pkce.py +0 -0
  17. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/roles.py +0 -0
  18. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/settings.py +0 -0
  19. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/templates/admin/login.html +0 -0
  20. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/templates/django-jwt-index.html +0 -0
  21. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/urls.py +0 -0
  22. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/utils.py +0 -0
  23. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/django_jwt/views.py +0 -0
  24. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/pyproject.toml +0 -0
  25. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/setup.py +0 -0
  26. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/tests/__init__.py +0 -0
  27. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/tests/models.py +0 -0
  28. {dj-jwt-auth-1.6.0 → dj_jwt_auth-1.7.1}/tests/urls.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dj-jwt-auth
3
- Version: 1.6.0
3
+ Version: 1.7.1
4
4
  Summary: A Django package for JSON Web Token validation and verification. Using PyJWT.
5
5
  Home-page: https://www.example.com/
6
6
  Author: Konstantin Seleznev
@@ -17,10 +17,15 @@ Classifier: Programming Language :: Python :: 3 :: Only
17
17
  Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
20
21
  Classifier: Topic :: Internet :: WWW/HTTP
21
22
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
22
23
  Requires-Python: >=3.8
23
24
  Description-Content-Type: text/markdown
25
+ Requires-Dist: Django>=3.0
26
+ Requires-Dist: pyjwt>=2.5.0
27
+ Requires-Dist: requests>=2.28.1
28
+ Requires-Dist: cryptography>=36.0.2
24
29
 
25
30
  # Django-JWT
26
31
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dj-jwt-auth
3
- Version: 1.6.0
3
+ Version: 1.7.1
4
4
  Summary: A Django package for JSON Web Token validation and verification. Using PyJWT.
5
5
  Home-page: https://www.example.com/
6
6
  Author: Konstantin Seleznev
@@ -17,10 +17,15 @@ Classifier: Programming Language :: Python :: 3 :: Only
17
17
  Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
20
21
  Classifier: Topic :: Internet :: WWW/HTTP
21
22
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
22
23
  Requires-Python: >=3.8
23
24
  Description-Content-Type: text/markdown
25
+ Requires-Dist: Django>=3.0
26
+ Requires-Dist: pyjwt>=2.5.0
27
+ Requires-Dist: requests>=2.28.1
28
+ Requires-Dist: cryptography>=36.0.2
24
29
 
25
30
  # Django-JWT
26
31
 
@@ -6,7 +6,7 @@ import requests
6
6
  from jwt.algorithms import ECAlgorithm, RSAAlgorithm
7
7
 
8
8
  from django_jwt import settings
9
- from django_jwt.exceptions import ConfigException
9
+ from django_jwt.exceptions import AlgorithmNotSupportedException, ConfigException
10
10
 
11
11
 
12
12
  def ensure_well_known(url: str) -> str:
@@ -24,6 +24,9 @@ class Config:
24
24
  if not self.route:
25
25
  raise ConfigException("OIDC_CONFIG_ROUTES is not set")
26
26
 
27
+ if alg not in self.route:
28
+ raise AlgorithmNotSupportedException(f"Algorithm {alg} is not supported")
29
+
27
30
  response = requests.get(ensure_well_known(self.route[alg]))
28
31
  response.raise_for_status()
29
32
  return response.json()
@@ -8,3 +8,9 @@ class BadRequestException(Exception):
8
8
  """Base class for exceptions in this module."""
9
9
 
10
10
  pass
11
+
12
+
13
+ class AlgorithmNotSupportedException(Exception):
14
+ """Base class for exceptions in this module."""
15
+
16
+ pass
@@ -5,6 +5,7 @@ from django.http import JsonResponse
5
5
  from django.utils.deprecation import MiddlewareMixin
6
6
  from jwt import ExpiredSignatureError
7
7
 
8
+ from django_jwt.exceptions import AlgorithmNotSupportedException
8
9
  from django_jwt.user import UserHandler
9
10
  from django_jwt.utils import oidc_handler
10
11
 
@@ -27,6 +28,8 @@ class JWTAuthMiddleware(MiddlewareMixin):
27
28
  try:
28
29
  info = oidc_handler.decode_token(raw_token)
29
30
  request.user = request._cached_user = UserHandler(info, request, raw_token).get_user()
31
+ except AlgorithmNotSupportedException as exc:
32
+ return JsonResponse(status=HTTPStatus.UNAUTHORIZED.value, data={"detail": str(exc)})
30
33
  except ExpiredSignatureError:
31
34
  return JsonResponse(status=HTTPStatus.UNAUTHORIZED.value, data={"detail": "expired token"})
32
35
  except UnicodeDecodeError as exc:
@@ -1,8 +1,7 @@
1
- from datetime import datetime
1
+ from datetime import datetime, timezone
2
2
  from functools import cache
3
3
  from logging import getLogger
4
4
 
5
- import pytz
6
5
  from django.contrib.auth import get_user_model
7
6
  from django.contrib.auth.models import Group, Permission
8
7
  from django.http.request import HttpRequest
@@ -10,7 +9,7 @@ from django.http.request import HttpRequest
10
9
  from django_jwt import settings
11
10
  from django_jwt.utils import oidc_handler
12
11
 
13
- utc = pytz.UTC
12
+ utc = timezone.utc
14
13
  log = getLogger(__name__)
15
14
 
16
15
  model = get_user_model()
@@ -32,7 +31,7 @@ class UserHandler:
32
31
 
33
32
  modified_at = payload.get(settings.OIDC_TOKEN_MODIFIED_FIELD, None)
34
33
  if modified_at and isinstance(modified_at, int):
35
- self.modified_at = utc.localize(datetime.fromtimestamp(modified_at))
34
+ self.modified_at = datetime.fromtimestamp(modified_at, utc)
36
35
 
37
36
  self.on_create = settings.OIDC_USER_ON_CREATE
38
37
  self.on_update = settings.OIDC_USER_ON_UPDATE
@@ -61,8 +60,9 @@ class UserHandler:
61
60
  def _create_new_user(self) -> model:
62
61
  """Create new user if user is not found in database even by email."""
63
62
 
64
- user = model.objects.create(**self.kwargs)
65
- if self.on_create:
63
+ email = self.kwargs.pop("email")
64
+ user, created = model.objects.get_or_create(email=email, defaults=self.kwargs)
65
+ if created and self.on_create:
66
66
  self.on_create(user, self.request, self.payload)
67
67
  return user
68
68
 
@@ -81,7 +81,7 @@ class UserHandler:
81
81
  user_modified_at = getattr(user, settings.OIDC_USER_MODIFIED_FIELD, None)
82
82
  if user_modified_at:
83
83
  if not user_modified_at.tzinfo:
84
- user_modified_at = utc.localize(user_modified_at)
84
+ user_modified_at = user_modified_at.replace(tzinfo=utc)
85
85
  is_modified = user_modified_at < self.modified_at
86
86
 
87
87
  log.info(
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = dj-jwt-auth
3
- version = 1.6.0
3
+ version = 1.7.1
4
4
  description = A Django package for JSON Web Token validation and verification. Using PyJWT.
5
5
  long_description = file: README.md
6
6
  url = https://www.example.com/
@@ -19,6 +19,7 @@ classifiers =
19
19
  Programming Language :: Python :: 3.9
20
20
  Programming Language :: Python :: 3.10
21
21
  Programming Language :: Python :: 3.11
22
+ Programming Language :: Python :: 3.12
22
23
  Topic :: Internet :: WWW/HTTP
23
24
  Topic :: Internet :: WWW/HTTP :: Dynamic Content
24
25
 
@@ -1,8 +1,7 @@
1
- from datetime import datetime
1
+ from datetime import datetime, timezone
2
2
  from http import HTTPStatus
3
3
  from unittest.mock import Mock, patch
4
4
 
5
- import pytz
6
5
  from django.contrib.auth import get_user_model
7
6
  from django.contrib.auth.models import Group, Permission
8
7
  from django.test import TestCase
@@ -10,11 +9,13 @@ from django.urls import reverse
10
9
  from jwt.api_jwt import ExpiredSignatureError
11
10
 
12
11
  from django_jwt import settings
12
+ from django_jwt.config import config
13
+ from django_jwt.exceptions import ConfigException
13
14
  from django_jwt.middleware import JWTAuthMiddleware
14
15
  from django_jwt.roles import ROLE
15
16
  from django_jwt.user import role_handler
16
17
 
17
- utc = pytz.UTC
18
+ utc = timezone.utc
18
19
  access_token_payload = {
19
20
  "sub": "1234",
20
21
  "updated_at": 2687276498,
@@ -185,7 +186,7 @@ class OIDCHandlerTest(TestCase):
185
186
  - don't call userdata if updated_at is not changed
186
187
  """
187
188
 
188
- updated_at = utc.localize(datetime.fromtimestamp(access_token_payload["updated_at"]))
189
+ updated_at = datetime.fromtimestamp(access_token_payload["updated_at"], utc)
189
190
  user = User.objects.create(kc_id="1234", first_name="", last_name="", username="")
190
191
 
191
192
  self.middleware.process_request(self.request)
@@ -201,6 +202,25 @@ class OIDCHandlerTest(TestCase):
201
202
  # self.assertEqual(user_info.call_count, 1)
202
203
 
203
204
 
205
+ @patch("django_jwt.utils.get_alg", return_value="HS256")
206
+ class ConfigTest(TestCase):
207
+ def setUp(self):
208
+ self.middleware = JWTAuthMiddleware(get_response=lambda x: x)
209
+ self.request = Mock()
210
+ self.request.META = {"HTTP_AUTHORIZATION": "Bearer Token"}
211
+
212
+ @patch.object(config, "route", {})
213
+ def test_empty_routes(self, *_):
214
+ with self.assertRaises(ConfigException):
215
+ self.middleware.process_request(self.request)
216
+
217
+ @patch.object(config, "route", {"ES256": "http://localhost:8080"})
218
+ def test_not_supported_alg(self, *_):
219
+ response = self.middleware.process_request(self.request)
220
+ self.assertEqual(HTTPStatus.UNAUTHORIZED.value, response.status_code)
221
+ self.assertEqual(b'{"detail": "Algorithm HS256 is not supported"}', response.content)
222
+
223
+
204
224
  class RolesTest(TestCase):
205
225
  def setUp(self) -> None:
206
226
  self.user = User.objects.create(username="user")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes