Hello Django community,
I have a mystery error or bug somewhere in my code and I cannot seem to resolve it, hence, I am here seeking some external help. Thanks for your time in advance.
Context
I have a custom mixin class that I use with DRF’s APIView that adds permission classes and authentication classes to my api views.
from importlib import import_module
from typing import TYPE_CHECKING, Sequence, Type
from django.conf import settings
from django.contrib import auth
from rest_framework.authentication import BaseAuthentication, SessionAuthentication
from rest_framework.permissions import BasePermission, IsAuthenticated, IsAdminUser, DjangoModelPermissions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
def get_auth_header(headers):
value = headers.get("Authorization")
if not value:
return None
auth_type, auth_value = value.split()[:2]
return auth_type, auth_value
class SessionAsHeaderAuthentication(BaseAuthentication):
"""
In case we are dealing with issues like Safari not supporting SameSite=None,
And the client passes the session as Authorization header:
Authorization: Session 7wvz4sxcp3chm9quyw015n6ryre29b3u
Run the standard Django auth & try obtaining user.
"""
def authenticate(self, request):
auth_header = get_auth_header(request.headers)
if auth_header is None:
return None
auth_type, auth_value = auth_header
if auth_type != "Session":
return None
engine = import_module(settings.SESSION_ENGINE)
SessionStore = engine.SessionStore
session_key = auth_value
request.session = SessionStore(session_key)
user = auth.get_user(request)
return user, None
class CsrfExemptedSessionAuthentication(SessionAuthentication):
"""
DRF SessionAuthentication is enforcing CSRF, which may be problematic.
That's why we want to make sure we are exempting any kind of CSRF checks for APIs.
"""
def enforce_csrf(self, request):
return
if TYPE_CHECKING:
# This is going to be resolved in the stub library
# https://github.com/typeddjango/djangorestframework-stubs/
from rest_framework.permissions import _PermissionClass
PermissionClassesType = Sequence[_PermissionClass]
else:
PermissionClassesType = Sequence[Type[BasePermission]]
class AdminApiAuthMixin:
authentication_classes: Sequence[Type[BaseAuthentication]] = [
CsrfExemptedSessionAuthentication,
SessionAsHeaderAuthentication,
JSONWebTokenAuthentication,
]
permission_classes: PermissionClassesType = [IsAdminUser, DjangoModelPermissions,]
My api view looks something like this:
class PackageListCreateApi(AdminApiAuthMixin, APIView):
... # code removed for brevity
Problem
For some strange reason when a non-admin (i.e., a user who has is_staff=False
) calls the api endpoint, they are still being served a valid response instead of getting HTTP 403 error.