#37042: alogin() does not invalidate _acached_user, causing stale AnonymousUser
after async login
-------------------------------------+-------------------------------------
     Reporter:  Dong Huynh           |                     Type:  Bug
       Status:  new                  |                Component:
                                     |  contrib.auth
      Version:  5.2                  |                 Severity:  Normal
     Keywords:  alogin, async,       |             Triage Stage:
  auser                              |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  1                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
 When alogin() is called after request.auser() in the same request,
 subsequent calls to request.auser() return a stale AnonymousUser because
 alogin() does not update request._acached_user.

 The sync path does not have this problem. login() sets request.user =
 user, which replaces the SimpleLazyObject entirely, so all subsequent
 request.user access returns the correct user. But in the async path,
 request.auser() is a separate callable (partial(auser, request)) that
 caches its result in request._acached_user. alogin() updates request.user
 but never touches _acached_user.

 Reproduction:

 {{{
 class MyAuthMiddleware:
     async def __acall__(self, request):
         # Step 1: check if already authenticated
         user = await request.auser()  # caches AnonymousUser in
 _acached_user

         if not user.is_authenticated:
             db_user = await
 User.objects.aget(email="[email protected]")
             await alogin(request, db_user)  # updates request.user, NOT
 _acached_user

         response = await self.get_response(request)  # view runs
         return response

 # In the view:
 async def my_view(request):
     user = await request.auser()  # returns stale AnonymousUser
     assert user.is_authenticated  # FAILS
 }}}

 Fixed in: Django 6.x, which replaces request.auser with a closure after
 login:

 {{{
 if hasattr(request, "auser"):
     async def auser():
         return user
     request.auser = auser
 }}}

 Workaround for 5.x, after await alogin(request, user):

 {{{
 request._acached_user = user  # Fixed in Django 6.x (alogin replaces
 request.auser)
 }}}
-- 
Ticket URL: <https://code.djangoproject.com/ticket/37042>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019d9b0831ee-3742de33-4d38-4442-8827-c68f357f61ba-000000%40eu-central-1.amazonses.com.

Reply via email to