Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/rest_framework_simplejwt/authentication.py: 72%
68 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from django.contrib.auth import get_user_model
2from django.utils.translation import gettext_lazy as _
3from rest_framework import HTTP_HEADER_ENCODING, authentication
5from .exceptions import AuthenticationFailed, InvalidToken, TokenError
6from .settings import api_settings
8AUTH_HEADER_TYPES = api_settings.AUTH_HEADER_TYPES
10if not isinstance(api_settings.AUTH_HEADER_TYPES, (list, tuple)): 10 ↛ 11line 10 didn't jump to line 11, because the condition on line 10 was never true
11 AUTH_HEADER_TYPES = (AUTH_HEADER_TYPES,)
13AUTH_HEADER_TYPE_BYTES = {h.encode(HTTP_HEADER_ENCODING) for h in AUTH_HEADER_TYPES}
16class JWTAuthentication(authentication.BaseAuthentication):
17 """
18 An authentication plugin that authenticates requests through a JSON web
19 token provided in a request header.
20 """
22 www_authenticate_realm = "api"
23 media_type = "application/json"
25 def __init__(self, *args, **kwargs):
26 super().__init__(*args, **kwargs)
27 self.user_model = get_user_model()
29 def authenticate(self, request):
30 header = self.get_header(request)
31 if header is None:
32 return None
34 raw_token = self.get_raw_token(header)
35 if raw_token is None: 35 ↛ 36line 35 didn't jump to line 36, because the condition on line 35 was never true
36 return None
38 validated_token = self.get_validated_token(raw_token)
40 return self.get_user(validated_token), validated_token
42 def authenticate_header(self, request):
43 return '{} realm="{}"'.format(
44 AUTH_HEADER_TYPES[0],
45 self.www_authenticate_realm,
46 )
48 def get_header(self, request):
49 """
50 Extracts the header containing the JSON web token from the given
51 request.
52 """
53 header = request.META.get(api_settings.AUTH_HEADER_NAME)
55 if isinstance(header, str):
56 # Work around django test client oddness
57 header = header.encode(HTTP_HEADER_ENCODING)
59 return header
61 def get_raw_token(self, header):
62 """
63 Extracts an unvalidated JSON web token from the given "Authorization"
64 header value.
65 """
66 parts = header.split()
68 if len(parts) == 0: 68 ↛ 70line 68 didn't jump to line 70, because the condition on line 68 was never true
69 # Empty AUTHORIZATION header sent
70 return None
72 if parts[0] not in AUTH_HEADER_TYPE_BYTES: 72 ↛ 74line 72 didn't jump to line 74, because the condition on line 72 was never true
73 # Assume the header does not contain a JSON web token
74 return None
76 if len(parts) != 2: 76 ↛ 77line 76 didn't jump to line 77, because the condition on line 76 was never true
77 raise AuthenticationFailed(
78 _("Authorization header must contain two space-delimited values"),
79 code="bad_authorization_header",
80 )
82 return parts[1]
84 def get_validated_token(self, raw_token):
85 """
86 Validates an encoded JSON web token and returns a validated token
87 wrapper object.
88 """
89 messages = []
90 for AuthToken in api_settings.AUTH_TOKEN_CLASSES: 90 ↛ 102line 90 didn't jump to line 102, because the loop on line 90 didn't complete
91 try:
92 return AuthToken(raw_token)
93 except TokenError as e:
94 messages.append(
95 {
96 "token_class": AuthToken.__name__,
97 "token_type": AuthToken.token_type,
98 "message": e.args[0],
99 }
100 )
102 raise InvalidToken(
103 {
104 "detail": _("Given token not valid for any token type"),
105 "messages": messages,
106 }
107 )
109 def get_user(self, validated_token):
110 """
111 Attempts to find and return a user using the given validated token.
112 """
113 try:
114 user_id = validated_token[api_settings.USER_ID_CLAIM]
115 except KeyError:
116 raise InvalidToken(_("Token contained no recognizable user identification"))
118 try:
119 user = self.user_model.objects.get(**{api_settings.USER_ID_FIELD: user_id})
120 except self.user_model.DoesNotExist:
121 raise AuthenticationFailed(_("User not found"), code="user_not_found")
123 if not user.is_active: 123 ↛ 124line 123 didn't jump to line 124, because the condition on line 123 was never true
124 raise AuthenticationFailed(_("User is inactive"), code="user_inactive")
126 return user
129class JWTStatelessUserAuthentication(JWTAuthentication):
130 """
131 An authentication plugin that authenticates requests through a JSON web
132 token provided in a request header without performing a database lookup to obtain a user instance.
133 """
135 def get_user(self, validated_token):
136 """
137 Returns a stateless user object which is backed by the given validated
138 token.
139 """
140 if api_settings.USER_ID_CLAIM not in validated_token:
141 # The TokenUser class assumes tokens will have a recognizable user
142 # identifier claim.
143 raise InvalidToken(_("Token contained no recognizable user identification"))
145 return api_settings.TOKEN_USER_CLASS(validated_token)
148JWTTokenUserAuthentication = JWTStatelessUserAuthentication
151def default_user_authentication_rule(user):
152 # Prior to Django 1.10, inactive users could be authenticated with the
153 # default `ModelBackend`. As of Django 1.10, the `ModelBackend`
154 # prevents inactive users from authenticating. App designers can still
155 # allow inactive users to authenticate by opting for the new
156 # `AllowAllUsersModelBackend`. However, we explicitly prevent inactive
157 # users from authenticating to enforce a reasonable policy and provide
158 # sensible backwards compatibility with older Django versions.
159 return user is not None and user.is_active