Commit b6433866 authored by Paulo Poiati's avatar Paulo Poiati Committed by Tim Graham
Browse files

Fixed #24855 -- Allowed using contrib.auth.login() without credentials.

Added an optional `backend` argument to login().
parent bd3c2900
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -567,6 +567,7 @@ answer newbie questions, and generally made Django that much better:
    Paul Lanier <planier@google.com>
    Paul McLanahan <paul@mclanahan.net>
    Paul McMillan <Paul@McMillan.ws>
    Paulo Poiati <paulogpoiati@gmail.com>
    Paulo Scardine <paulo@scardine.com.br>
    Paul Smith <blinkylights23@gmail.com>
    pavithran s <pavithran.s@gmail.com>
+16 −2
Original line number Diff line number Diff line
@@ -86,7 +86,7 @@ def authenticate(**credentials):
            credentials=_clean_credentials(credentials))


def login(request, user):
def login(request, user, backend=None):
    """
    Persist a user id and a backend in the request. This way a user doesn't
    have to reauthenticate on every request. Note that data set during
@@ -108,8 +108,22 @@ def login(request, user):
            request.session.flush()
    else:
        request.session.cycle_key()

    try:
        backend = backend or user.backend
    except AttributeError:
        backends = _get_backends(return_tuples=True)
        if len(backends) == 1:
            _, backend = backends[0]
        else:
            raise ValueError(
                'You have multiple authentication backends configured and '
                'therefore must provide the `backend` argument or set the '
                '`backend` attribute on the user.'
            )

    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    request.session[BACKEND_SESSION_KEY] = user.backend
    request.session[BACKEND_SESSION_KEY] = backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
        request.user = user
+3 −6
Original line number Diff line number Diff line
@@ -603,12 +603,9 @@ class Client(RequestFactory):
            return False

    def force_login(self, user, backend=None):
        if backend is None:
            backend = settings.AUTHENTICATION_BACKENDS[0]
        user.backend = backend
        self._login(user)
        self._login(user, backend)

    def _login(self, user):
    def _login(self, user, backend=None):
        from django.contrib.auth import login
        engine = import_module(settings.SESSION_ENGINE)

@@ -619,7 +616,7 @@ class Client(RequestFactory):
            request.session = self.session
        else:
            request.session = engine.SessionStore()
        login(request, user)
        login(request, user, backend)

        # Save the session values.
        request.session.save()
+3 −0
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@ Minor features
  to prevent an issue where Safari caches redirects and prevents a user from
  being able to log out.

* Added the optional ``backend`` argument to :func:`~django.contrib.auth.login`
  to allowing using it without credentials.

:mod:`django.contrib.contenttypes`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

+30 −13
Original line number Diff line number Diff line
@@ -322,7 +322,7 @@ How to log a user in
If you have an authenticated user you want to attach to the current session
- this is done with a :func:`~django.contrib.auth.login` function.

.. function:: login(request, user)
.. function:: login(request, user, backend=None)

    To log a user in, from a view, use :func:`~django.contrib.auth.login()`. It
    takes an :class:`~django.http.HttpRequest` object and a
@@ -354,18 +354,35 @@ If you have an authenticated user you want to attach to the current session
                # Return an 'invalid login' error message.
                ...

.. admonition:: Calling ``authenticate()`` first
    .. versionchanged:: 1.10

        In older versions, when you're manually logging a user in, you *must*
        successfully authenticate the user with
        :func:`~django.contrib.auth.authenticate()` before you call
        :func:`~django.contrib.auth.login()`. Now you can set the backend using
        the new ``backend`` argument.

Selecting the :ref:`authentication backend <authentication-backends>`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    When you're manually logging a user in, you *must* successfully authenticate
    the user with :func:`~django.contrib.auth.authenticate()` before you call
    :func:`~django.contrib.auth.login()`.
When a user logs in, the user's ID and the backend that was used for
authentication are saved in the user's session. This allows the same
authentication backend to fetch the user's details on a future request. The
authentication backend to save in the session is selected as follows:

#. Use the value of the optional ``backend`` argument, if provided.
#. Use the value of the ``user.backend`` attribute, if present. This allows
   pairing :func:`~django.contrib.auth.authenticate()` and
   :func:`~django.contrib.auth.login()`:
   :func:`~django.contrib.auth.authenticate()`
    sets an attribute on the :class:`~django.contrib.auth.models.User` noting
    which authentication backend successfully authenticated that user (see the
    :ref:`backends documentation <authentication-backends>` for details), and
    this information is needed later during the login process. An error will be
    raised if you try to login a user object retrieved from the database
    directly.
   sets the ``user.backend`` attribute on the ``User`` object it returns.
#. Use the ``backend`` in :setting:`AUTHENTICATION_BACKENDS`, if there is only
   one.
#. Otherwise, raise an exception.

In cases 1 and 2, the value of the ``backend`` argument or the ``user.backend``
attribute should be a dotted import path string (like that found in
:setting:`AUTHENTICATION_BACKENDS`), not the actual backend class.

How to log a user out
---------------------
Loading