mirror of https://github.com/django/django.git
Fixed #25029 -- Added PersistentRemoteUserMiddleware for login-page-only external authentication.
This commit is contained in:
parent
c6cce4de38
commit
a570701e02
1
AUTHORS
1
AUTHORS
|
@ -308,6 +308,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
James Wheare <django@sparemint.com>
|
James Wheare <django@sparemint.com>
|
||||||
Jannis Leidel <jannis@leidel.info>
|
Jannis Leidel <jannis@leidel.info>
|
||||||
Janos Guljas
|
Janos Guljas
|
||||||
|
Jan Pazdziora
|
||||||
Jan Rademaker
|
Jan Rademaker
|
||||||
Jarek Zgoda <jarek.zgoda@gmail.com>
|
Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||||
Jason Davies (Esaj) <http://www.jasondavies.com/>
|
Jason Davies (Esaj) <http://www.jasondavies.com/>
|
||||||
|
|
|
@ -53,6 +53,7 @@ class RemoteUserMiddleware(object):
|
||||||
# used in the request.META dictionary, i.e. the normalization of headers to
|
# used in the request.META dictionary, i.e. the normalization of headers to
|
||||||
# all uppercase and the addition of "HTTP_" prefix apply.
|
# all uppercase and the addition of "HTTP_" prefix apply.
|
||||||
header = "REMOTE_USER"
|
header = "REMOTE_USER"
|
||||||
|
force_logout_if_no_header = True
|
||||||
|
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
# AuthenticationMiddleware is required so that request.user exists.
|
# AuthenticationMiddleware is required so that request.user exists.
|
||||||
|
@ -69,7 +70,7 @@ class RemoteUserMiddleware(object):
|
||||||
# If specified header doesn't exist then remove any existing
|
# If specified header doesn't exist then remove any existing
|
||||||
# authenticated remote-user, or return (leaving request.user set to
|
# authenticated remote-user, or return (leaving request.user set to
|
||||||
# AnonymousUser by the AuthenticationMiddleware).
|
# AnonymousUser by the AuthenticationMiddleware).
|
||||||
if request.user.is_authenticated():
|
if self.force_logout_if_no_header and request.user.is_authenticated():
|
||||||
self._remove_invalid_user(request)
|
self._remove_invalid_user(request)
|
||||||
return
|
return
|
||||||
# If the user is already authenticated and that user is the user we are
|
# If the user is already authenticated and that user is the user we are
|
||||||
|
@ -118,3 +119,16 @@ class RemoteUserMiddleware(object):
|
||||||
else:
|
else:
|
||||||
if isinstance(stored_backend, RemoteUserBackend):
|
if isinstance(stored_backend, RemoteUserBackend):
|
||||||
auth.logout(request)
|
auth.logout(request)
|
||||||
|
|
||||||
|
|
||||||
|
class PersistentRemoteUserMiddleware(RemoteUserMiddleware):
|
||||||
|
"""
|
||||||
|
Middleware for Web-server provided authentication on logon pages.
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
force_logout_if_no_header = False
|
||||||
|
|
|
@ -19,7 +19,8 @@ When the Web server takes care of authentication it typically sets the
|
||||||
``REMOTE_USER`` environment variable for use in the underlying application. In
|
``REMOTE_USER`` environment variable for use in the underlying application. In
|
||||||
Django, ``REMOTE_USER`` is made available in the :attr:`request.META
|
Django, ``REMOTE_USER`` is made available in the :attr:`request.META
|
||||||
<django.http.HttpRequest.META>` attribute. Django can be configured to make
|
<django.http.HttpRequest.META>` attribute. Django can be configured to make
|
||||||
use of the ``REMOTE_USER`` value using the ``RemoteUserMiddleware`` and
|
use of the ``REMOTE_USER`` value using the ``RemoteUserMiddleware``
|
||||||
|
or ``PersistentRemoteUserMiddleware``, and
|
||||||
:class:`~django.contrib.auth.backends.RemoteUserBackend` classes found in
|
:class:`~django.contrib.auth.backends.RemoteUserBackend` classes found in
|
||||||
:mod:`django.contrib.auth`.
|
:mod:`django.contrib.auth`.
|
||||||
|
|
||||||
|
@ -95,3 +96,25 @@ If your authentication mechanism uses a custom HTTP header and not
|
||||||
If you need more control, you can create your own authentication backend
|
If you need more control, you can create your own authentication backend
|
||||||
that inherits from :class:`~django.contrib.auth.backends.RemoteUserBackend` and
|
that inherits from :class:`~django.contrib.auth.backends.RemoteUserBackend` and
|
||||||
override one or more of its attributes and methods.
|
override one or more of its attributes and methods.
|
||||||
|
|
||||||
|
.. _persistent-remote-user-middleware-howto:
|
||||||
|
|
||||||
|
Using ``REMOTE_USER`` on login pages only
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
.. versionadded:: 1.9
|
||||||
|
|
||||||
|
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 other
|
||||||
|
simple 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.
|
||||||
|
|
|
@ -374,6 +374,14 @@ every incoming ``HttpRequest`` object. See :ref:`Authentication in Web requests
|
||||||
Middleware for utilizing Web server provided authentication. See
|
Middleware for utilizing Web server provided authentication. See
|
||||||
:doc:`/howto/auth-remote-user` for usage details.
|
:doc:`/howto/auth-remote-user` for usage details.
|
||||||
|
|
||||||
|
.. class:: PersistentRemoteUserMiddleware
|
||||||
|
|
||||||
|
.. versionadded:: 1.9
|
||||||
|
|
||||||
|
Middleware for utilizing Web server provided authentication when enabled only
|
||||||
|
on the login page. See :ref:`persistent-remote-user-middleware-howto` for usage
|
||||||
|
details.
|
||||||
|
|
||||||
.. class:: SessionAuthenticationMiddleware
|
.. class:: SessionAuthenticationMiddleware
|
||||||
|
|
||||||
Allows a user's sessions to be invalidated when their password changes. See
|
Allows a user's sessions to be invalidated when their password changes. See
|
||||||
|
|
|
@ -172,6 +172,10 @@ Minor features
|
||||||
:func:`~django.contrib.auth.decorators.permission_required()` accepts all
|
:func:`~django.contrib.auth.decorators.permission_required()` accepts all
|
||||||
kinds of iterables, not only list and tuples.
|
kinds of iterables, not only list and tuples.
|
||||||
|
|
||||||
|
* The new :class:`~django.contrib.auth.middleware.PersistentRemoteUserMiddleware`
|
||||||
|
makes it possible to use ``REMOTE_USER`` for setups where the header is only
|
||||||
|
populated on login pages instead of every request in the session.
|
||||||
|
|
||||||
:mod:`django.contrib.gis`
|
:mod:`django.contrib.gis`
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -232,3 +232,26 @@ class CustomHeaderRemoteUserTest(RemoteUserTest):
|
||||||
'auth_tests.test_remote_user.CustomHeaderMiddleware'
|
'auth_tests.test_remote_user.CustomHeaderMiddleware'
|
||||||
)
|
)
|
||||||
header = 'HTTP_AUTHUSER'
|
header = 'HTTP_AUTHUSER'
|
||||||
|
|
||||||
|
|
||||||
|
class PersistentRemoteUserTest(RemoteUserTest):
|
||||||
|
"""
|
||||||
|
PersistentRemoteUserMiddleware keeps the user logged in even if the
|
||||||
|
subsequent calls do not contain the header value.
|
||||||
|
"""
|
||||||
|
middleware = 'django.contrib.auth.middleware.PersistentRemoteUserMiddleware'
|
||||||
|
require_header = False
|
||||||
|
|
||||||
|
def test_header_disappears(self):
|
||||||
|
"""
|
||||||
|
A logged in user is kept logged in even if the REMOTE_USER header
|
||||||
|
disappears during the same browser session.
|
||||||
|
"""
|
||||||
|
User.objects.create(username='knownuser')
|
||||||
|
# Known user authenticates
|
||||||
|
response = self.client.get('/remote_user/', **{self.header: self.known_user})
|
||||||
|
self.assertEqual(response.context['user'].username, 'knownuser')
|
||||||
|
# Should stay logged in if the REMOTE_USER header disappears.
|
||||||
|
response = self.client.get('/remote_user/')
|
||||||
|
self.assertEqual(response.context['user'].is_anonymous(), False)
|
||||||
|
self.assertEqual(response.context['user'].username, 'knownuser')
|
||||||
|
|
Loading…
Reference in New Issue