1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
=========================================
How to authenticate using ``REMOTE_USER``
=========================================
This document describes how to make use of external authentication sources in
your Django applications. This type of authentication solution is typically
seen on intranet sites, with single sign-on solutions such as IIS and
Integrated Windows Authentication or Apache and `mod_authnz_ldap`_, `CAS`_,
`WebAuth`_, `mod_auth_sspi`_, etc.
.. _mod_authnz_ldap: https://httpd.apache.org/docs/current/mod/mod_authnz_ldap.html
.. _CAS: https://www.apereo.org/projects/cas
.. _WebAuth: https://uit.stanford.edu/service/authentication
.. _mod_auth_sspi: https://sourceforge.net/projects/mod-auth-sspi
When the web server takes care of authentication it typically provides the
authenticated user as ``REMOTE_USER``. In Django, this value is made available
in :attr:`request.META <django.http.HttpRequest.META>` (as ``REMOTE_USER`` when
supplied as an environment variable, as in WSGI, or ``HTTP_REMOTE_USER`` when
supplied via an HTTP header, as in ASGI). Django can be configured to make use
of the ``REMOTE_USER`` value using the ``RemoteUserMiddleware`` or
``PersistentRemoteUserMiddleware``, and
:class:`~django.contrib.auth.backends.RemoteUserBackend` classes found in
:mod:`django.contrib.auth`.
Configuration
=============
First, you must add the
:class:`django.contrib.auth.middleware.RemoteUserMiddleware` to the
:setting:`MIDDLEWARE` setting **after** the
:class:`django.contrib.auth.middleware.AuthenticationMiddleware`::
MIDDLEWARE = [
"...",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.auth.middleware.RemoteUserMiddleware",
"...",
]
Next, you must replace the :class:`~django.contrib.auth.backends.ModelBackend`
with :class:`~django.contrib.auth.backends.RemoteUserBackend` in the
:setting:`AUTHENTICATION_BACKENDS` setting::
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.RemoteUserBackend",
]
With this setup, ``RemoteUserMiddleware`` will detect the username in
``request.META['REMOTE_USER']`` (or ``request.META['HTTP_REMOTE_USER']`` under
ASGI) and will authenticate and auto-login that user
using the :class:`~django.contrib.auth.backends.RemoteUserBackend`.
Be aware that this particular setup disables authentication with the default
``ModelBackend``. This means that if the ``REMOTE_USER`` value is not set
then the user is unable to log in, even using Django's admin interface.
Adding ``'django.contrib.auth.backends.ModelBackend'`` to the
``AUTHENTICATION_BACKENDS`` list will use ``ModelBackend`` as a fallback
if ``REMOTE_USER`` is absent, which will solve these issues.
Django's user management, such as the views in ``contrib.admin`` and
the :djadmin:`createsuperuser` management command, doesn't integrate with
remote users. These interfaces work with users stored in the database
regardless of ``AUTHENTICATION_BACKENDS``.
.. note::
Since the ``RemoteUserBackend`` inherits from ``ModelBackend``, you will
still have all of the same permissions checking that is implemented in
``ModelBackend``.
Users with :attr:`is_active=False
<django.contrib.auth.models.User.is_active>` won't be allowed to
authenticate. Use
:class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if
you want to allow them to.
If your authentication mechanism uses a custom HTTP header and not
``REMOTE_USER``, you can subclass ``RemoteUserMiddleware`` and set the
``header`` attribute to the desired ``request.META`` key. For example:
.. code-block:: python
:caption: ``mysite/middleware.py``
from django.contrib.auth.middleware import RemoteUserMiddleware
class CustomHeaderRemoteUserMiddleware(RemoteUserMiddleware):
header = "HTTP_AUTHUSER"
This custom middleware is then used in the :setting:`MIDDLEWARE` setting
instead of :class:`django.contrib.auth.middleware.RemoteUserMiddleware`::
MIDDLEWARE = [
"...",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"mysite.middleware.CustomHeaderRemoteUserMiddleware",
"...",
]
.. warning::
``RemoteUserMiddleware`` must not be deployed in configurations where a
client can supply the header. You must be sure that your web server or
reverse proxy always sets or strips that header based on the appropriate
authentication checks, never permitting an end user to submit a fake (or
"spoofed") header value.
Since the HTTP headers ``X-Auth-User`` and ``X-Auth_User`` (for example)
both normalize to the ``HTTP_X_AUTH_USER`` key in ``request.META``, you
must also check that your web server doesn't allow a spoofed header using
underscores in place of dashes.
Under WSGI, this warning doesn't apply to ``RemoteUserMiddleware`` in its
default configuration with ``header = "REMOTE_USER"``, since a key that
doesn't start with ``HTTP_`` in ``request.META`` can only be set by your
WSGI server, not directly from an HTTP request header.
This warning applies under ASGI in all configurations, because there is
no equivalent for a WSGI server's ability to place a trusted value in the
environ. ASGI deployments *must* use a reverse proxy as described above
when using this middleware.
If you need more control, you can create your own authentication backend
that inherits from :class:`~django.contrib.auth.backends.RemoteUserBackend` and
override one or more of its attributes and methods.
.. _persistent-remote-user-middleware-howto:
Using ``REMOTE_USER`` on login pages only
=========================================
The ``RemoteUserMiddleware`` authentication middleware assumes that the HTTP
request header ``REMOTE_USER`` is present with all authenticated requests. That
might be expected and practical when Basic HTTP Auth with ``htpasswd`` or
similar mechanisms are used, but with Negotiate (GSSAPI/Kerberos) or other
resource intensive authentication methods, the authentication in the front-end
HTTP server is usually only set up for one or a few login URLs, and after
successful authentication, the application is supposed to maintain the
authenticated session itself.
:class:`~django.contrib.auth.middleware.PersistentRemoteUserMiddleware`
provides support for this use case. It will maintain the authenticated session
until explicit logout by the user. The class can be used as a drop-in
replacement of :class:`~django.contrib.auth.middleware.RemoteUserMiddleware`
in the documentation above.
|