60 lines
2.4 KiB
Python
60 lines
2.4 KiB
Python
|
|
"""Authentication for the People core app."""
|
||
|
|
from django.conf import settings
|
||
|
|
from django.utils.functional import SimpleLazyObject
|
||
|
|
from django.utils.module_loading import import_string
|
||
|
|
from django.utils.translation import gettext_lazy as _
|
||
|
|
|
||
|
|
from drf_spectacular.authentication import SessionScheme, TokenScheme
|
||
|
|
from drf_spectacular.plumbing import build_bearer_security_scheme_object
|
||
|
|
from rest_framework import authentication
|
||
|
|
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||
|
|
|
||
|
|
|
||
|
|
class DelegatedJWTAuthentication(JWTAuthentication):
|
||
|
|
"""Override JWTAuthentication to create missing users on the fly."""
|
||
|
|
|
||
|
|
def get_user(self, validated_token):
|
||
|
|
"""
|
||
|
|
Return the user related to the given validated token, creating or updating it if necessary.
|
||
|
|
"""
|
||
|
|
get_user = import_string(settings.JWT_USER_GETTER)
|
||
|
|
return SimpleLazyObject(lambda: get_user(validated_token))
|
||
|
|
|
||
|
|
|
||
|
|
class OpenApiJWTAuthenticationExtension(TokenScheme):
|
||
|
|
"""Extension for specifying JWT authentication schemes."""
|
||
|
|
|
||
|
|
target_class = "core.authentication.DelegatedJWTAuthentication"
|
||
|
|
name = "DelegatedJWTAuthentication"
|
||
|
|
|
||
|
|
def get_security_definition(self, auto_schema):
|
||
|
|
"""Return the security definition for JWT authentication."""
|
||
|
|
return build_bearer_security_scheme_object(
|
||
|
|
header_name="Authorization",
|
||
|
|
token_prefix="Bearer", # noqa S106
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class SessionAuthenticationWithAuthenticateHeader(authentication.SessionAuthentication):
|
||
|
|
"""
|
||
|
|
This class is needed, because REST Framework's default SessionAuthentication does
|
||
|
|
never return 401's, because they cannot fill the WWW-Authenticate header with a
|
||
|
|
valid value in the 401 response. As a result, we cannot distinguish calls that are
|
||
|
|
not unauthorized (401 unauthorized) and calls for which the user does not have
|
||
|
|
permission (403 forbidden).
|
||
|
|
See https://github.com/encode/django-rest-framework/issues/5968
|
||
|
|
|
||
|
|
We do set authenticate_header function in SessionAuthentication, so that a value
|
||
|
|
for the WWW-Authenticate header can be retrieved and the response code is
|
||
|
|
automatically set to 401 in case of unauthenticated requests.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def authenticate_header(self, request):
|
||
|
|
return "Session"
|
||
|
|
|
||
|
|
|
||
|
|
class OpenApiSessionAuthenticationExtension(SessionScheme):
|
||
|
|
"""Extension for specifying session authentication schemes."""
|
||
|
|
|
||
|
|
target_class = "core.api.authentication.SessionAuthenticationWithAuthenticateHeader"
|