Opened 5 weeks ago

Closed 4 weeks ago

#36002 closed Cleanup/optimization (fixed)

RemoteUserMiddleware/PersistentRemoteUserMiddleware docstrings and code comments refer to "headers" rather than request.META keys

Reported by: Anders Einar Hilden Owned by: Anders Einar Hilden
Component: contrib.auth Version: dev
Severity: Normal Keywords: RemoteUserMiddleware, PersistentRemoteUserMiddleware
Cc: Anders Einar Hilden Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

File
django/django/contrib/auth/middleware.py (https://github.com/django/django/blob/main/django/contrib/auth/middleware.py)

Middleware
RemoteUserMiddleware and PersistentRemoteUserMiddleware

Error
The docstring and comments state that the middlewares by default uses a request header named REMOTE_USER for authentication. This is wrong, as it by default uses the REMOTE_USER environment variable.

Using git blame, all of these texts appear to be from when the respective middlewares were added to Django, 16 and 9 years ago. While it might have been correct 16/9 years ago, it is not correct for the current code base.

While the howto for RemoteUserMiddleware imho could use some work, it appears to use the correct terms. https://docs.djangoproject.com/en/5.1/howto/auth-remote-user/#configuration

From RemoteUserMiddleware docstring (line 94)

    If request.user is not authenticated, then this middleware attempts to
    authenticate the username passed in the ``REMOTE_USER`` request header.
    If authentication is successful, the user is automatically logged in to
    persist the user in the session.

    The header used is configurable and defaults to ``REMOTE_USER``.  Subclass
    this class and change the ``header`` attribute if you need to use a
    different header.

In the comment starting at line 119, it is referenced to as a header again.

    # Name of request header to grab username from.  This will be the key as
    # used in the request.META dictionary, i.e. the normalization of headers to
    # all uppercase and the addition of "HTTP_" prefix apply.
    header = "REMOTE_USER"

From PersistentRemoteUserMiddleware (line 258)

    Like RemoteUserMiddleware but keeps the user authenticated even if
    the header (``REMOTE_USER``) is not found in the request. Useful
    for setups when the external authentication via ``REMOTE_USER``
    is only expected to happen on some "logon" URL and the rest of
    the application wants to use Django's authentication mechanism.

For testing

A view that dumps meta and the user:

from django.http import HttpResponse
import pprint

def dump_request(request):
    rs = pprint.pformat(request.META, indent=2) + f"\nrequest.user: {request.user}"
    return HttpResponse(rs)

Start runserver with a REMOTE_USER environment variable

REMOTE_USER=set-in@env.com ./manage.py runserver

Send a request the the request header REMOTE_USER set. Note that the header is with a dash (-), not underline (_), as runserver and other WSGI servers do not allow headers with underscores, as not to be confused with environment variables)

curl -s -H 'REMOTE-USER: set-in@header.com' http://localhost:8000/dump_request | grep -E 'REMOTE_USER|request.user'

observe that the authenticated user is the email from the environment variable.

'HTTP_REMOTE_USER': 'set-in@header.com',
'REMOTE_USER': 'set-in@env.com',
request.user: set-in@env.com

Stop runserver and restart w/o environment variable

./manage.py runserver

observe that the user is not authenticated.

curl -s -H 'REMOTE-USER: set-in@header.com' http://localhost:8006/dump_request | grep -E 'REMOTE_USER|request.user'
'HTTP_REMOTE_USER': 'set-in@header.com',
request.user: AnonymousUser

For the adventrus bugreader, subclass RemoteUserMiddleware and make it actually respect a HTTP request header named Remote-User.

from django.contrib.auth.middleware import RemoteUserMiddleware

class CustomRemoteUserMiddleware(RemoteUserMiddleware):
        header = "HTTP_REMOTE_USER"
curl -s -H 'REMOTE-USER: set-in@header.com' http://localhost:8000/dump_request | grep -E 'REMOTE_USER|request.user'
'HTTP_REMOTE_USER': 'set-in@header.com',
'REMOTE_USER': 'set-in@env.com',
request.user: set-in@header.com

Change History (13)

comment:1 by Anders Einar Hilden, 5 weeks ago

Has patch: set

I have suggested changes in https://github.com/Kagee/django/commit/ba199155ae9b82693b7d2b0f7dfd7e2fb3f036e2. The contributor howtos feel unclear if i should have just pushed this as a PR or waiting until i get some response here.

comment:2 by Anders Einar Hilden, 5 weeks ago

Was informed a PR was the way to go, so made a PR: https://github.com/django/django/pull/18920

comment:3 by JaeHyuckSa, 5 weeks ago

Owner: set to Anders Einar Hilden
Status: newassigned

comment:4 by Sarah Boyce, 5 weeks ago

Resolution: invalid
Status: assignedclosed

HttpRequest.META is a dictionary of headers. On WSGI, these are initiated from environment variables.
I think both the docs and the doc strings are correct. The docs refer to how the header is likely to be set (from the environment variable) and the docstring is on what it actually is looking at (the header).

comment:5 by Anders Einar Hilden, 5 weeks ago

I do not concurre with that evaluation. The docstring & comments spesifically say "the REMOTE_USER request header" - But a request header can never be named "REMOTE_USER", if you send a header named "REMOTE-USER", it will be named HTTP_REMOTE_USER in the dict, not REMOTE_USER. Thus the default can only be passed as a direct envirionment variable, it can never come from a header.

comment:6 by Anders Einar Hilden, 5 weeks ago

For more context, this issue was raised after a lengthy support session after a user assumed passing a header named REMOTE-USER would work, because that was spesifically what the docstring for the middleware said would work.

comment:7 by Sarah Boyce, 5 weeks ago

There is a configurable header attribute and in the docs there is an example configuring it

from django.contrib.auth.middleware import RemoteUserMiddleware


class CustomHeaderMiddleware(RemoteUserMiddleware):
    header = "HTTP_AUTHUSER"

By default, the value is "REMOTE_USER". This header can only be set via an environment variable.

I think the comment above the header also hints at this

    # Name of request header to grab username from.  This will be the key as
    # used in the request.META dictionary, i.e. the normalization of headers to
    # all uppercase and the addition of "HTTP_" prefix apply.
    header = "REMOTE_USER"

As there are different ways to set headers, I don't think it's wrong to refer to this as a header 🤔


We might be able to make the docstring clearer, but I'm not convinced that it's clearly wrong

comment:8 by Sarah Boyce, 5 weeks ago

Patch needs improvement: set
Resolution: invalid
Status: closednew
Summary: Errors in RemoteUserMiddleware/PersistentRemoteUserMiddleware docstrings and code commentsRemoteUserMiddleware/PersistentRemoteUserMiddleware docstrings and code comments refer to "headers" rather than request.META keys
Triage Stage: UnreviewedAccepted

Accepting after further investigation
Also looks like some clarification in the HttpRequest.META docs would be beneficial to clarify that these are not exclusively headers and contain things like request Meta variables but that discussion should perhaps happen on the forum to iron things out

comment:9 by devian-321, 5 weeks ago

Owner: changed from Anders Einar Hilden to devian-321
Status: newassigned

Hi, This is my first time trying to contribute and I would like to work on this ticket to get familiar with. I currently am not familiar with the methods and the ticketing system, So i might be prone to making beginners mistakes in the protocol. Appreciate the understanding

comment:10 by Anders Einar Hilden, 5 weeks ago

Welcome devian-321- while i created this ticket, I have also created a PR for resolving it (linked) - i have just not been able to incorporate the comments from the PR discussion yet.

I would reccommend looking at another ticket :)

comment:11 by Sarah Boyce, 5 weeks ago

Owner: changed from devian-321 to Anders Einar Hilden

comment:12 by Sarah Boyce, 4 weeks ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:13 by Sarah Boyce <42296566+sarahboyce@…>, 4 weeks ago

Resolution: fixed
Status: assignedclosed

In a8b70aef:

Fixed #36002 -- Referred to request.Meta key in Persistent/RemoteUserMiddleware comments.

Changed the docstrings and code comments to better reflect where the default value
comes from (an environment variable, not request header).

Note: See TracTickets for help on using tickets.
Back to Top