mirror of
https://github.com/django/django.git
synced 2025-06-05 03:29:12 +00:00
Fixed #34391 -- Added async-compatible interface to auth functions and related methods test clients.
This commit is contained in:
parent
2360ba2274
commit
5e98959d92
@ -1,6 +1,8 @@
|
|||||||
import inspect
|
import inspect
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from asgiref.sync import sync_to_async
|
||||||
|
|
||||||
from django.apps import apps as django_apps
|
from django.apps import apps as django_apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||||
@ -91,6 +93,12 @@ def authenticate(request=None, **credentials):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@sensitive_variables("credentials")
|
||||||
|
async def aauthenticate(request=None, **credentials):
|
||||||
|
"""See authenticate()."""
|
||||||
|
return await sync_to_async(authenticate)(request, **credentials)
|
||||||
|
|
||||||
|
|
||||||
def login(request, user, backend=None):
|
def login(request, user, backend=None):
|
||||||
"""
|
"""
|
||||||
Persist a user id and a backend in the request. This way a user doesn't
|
Persist a user id and a backend in the request. This way a user doesn't
|
||||||
@ -144,6 +152,11 @@ def login(request, user, backend=None):
|
|||||||
user_logged_in.send(sender=user.__class__, request=request, user=user)
|
user_logged_in.send(sender=user.__class__, request=request, user=user)
|
||||||
|
|
||||||
|
|
||||||
|
async def alogin(request, user, backend=None):
|
||||||
|
"""See login()."""
|
||||||
|
return await sync_to_async(login)(request, user, backend)
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
def logout(request):
|
||||||
"""
|
"""
|
||||||
Remove the authenticated user's ID from the request and flush their session
|
Remove the authenticated user's ID from the request and flush their session
|
||||||
@ -162,6 +175,11 @@ def logout(request):
|
|||||||
request.user = AnonymousUser()
|
request.user = AnonymousUser()
|
||||||
|
|
||||||
|
|
||||||
|
async def alogout(request):
|
||||||
|
"""See logout()."""
|
||||||
|
return await sync_to_async(logout)(request)
|
||||||
|
|
||||||
|
|
||||||
def get_user_model():
|
def get_user_model():
|
||||||
"""
|
"""
|
||||||
Return the User model that is active in this project.
|
Return the User model that is active in this project.
|
||||||
@ -223,6 +241,11 @@ def get_user(request):
|
|||||||
return user or AnonymousUser()
|
return user or AnonymousUser()
|
||||||
|
|
||||||
|
|
||||||
|
async def aget_user(request):
|
||||||
|
"""See get_user()."""
|
||||||
|
return await sync_to_async(get_user)(request)
|
||||||
|
|
||||||
|
|
||||||
def get_permission_codename(action, opts):
|
def get_permission_codename(action, opts):
|
||||||
"""
|
"""
|
||||||
Return the codename of the permission for the specified action.
|
Return the codename of the permission for the specified action.
|
||||||
@ -242,3 +265,8 @@ def update_session_auth_hash(request, user):
|
|||||||
request.session.cycle_key()
|
request.session.cycle_key()
|
||||||
if hasattr(user, "get_session_auth_hash") and request.user == user:
|
if hasattr(user, "get_session_auth_hash") and request.user == user:
|
||||||
request.session[HASH_SESSION_KEY] = user.get_session_auth_hash()
|
request.session[HASH_SESSION_KEY] = user.get_session_auth_hash()
|
||||||
|
|
||||||
|
|
||||||
|
async def aupdate_session_auth_hash(request, user):
|
||||||
|
"""See update_session_auth_hash()."""
|
||||||
|
return await sync_to_async(update_session_auth_hash)(request, user)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
|
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.auth import load_backend
|
from django.contrib.auth import load_backend
|
||||||
from django.contrib.auth.backends import RemoteUserBackend
|
from django.contrib.auth.backends import RemoteUserBackend
|
||||||
@ -18,7 +16,7 @@ def get_user(request):
|
|||||||
|
|
||||||
async def auser(request):
|
async def auser(request):
|
||||||
if not hasattr(request, "_acached_user"):
|
if not hasattr(request, "_acached_user"):
|
||||||
request._acached_user = await sync_to_async(auth.get_user)(request)
|
request._acached_user = await auth.aget_user(request)
|
||||||
return request._acached_user
|
return request._acached_user
|
||||||
|
|
||||||
|
|
||||||
|
@ -747,6 +747,9 @@ class ClientMixin:
|
|||||||
self.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
|
self.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
|
||||||
return session
|
return session
|
||||||
|
|
||||||
|
async def asession(self):
|
||||||
|
return await sync_to_async(lambda: self.session)()
|
||||||
|
|
||||||
def login(self, **credentials):
|
def login(self, **credentials):
|
||||||
"""
|
"""
|
||||||
Set the Factory to appear as if it has successfully logged into a site.
|
Set the Factory to appear as if it has successfully logged into a site.
|
||||||
@ -762,20 +765,36 @@ class ClientMixin:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def alogin(self, **credentials):
|
||||||
|
"""See login()."""
|
||||||
|
from django.contrib.auth import aauthenticate
|
||||||
|
|
||||||
|
user = await aauthenticate(**credentials)
|
||||||
|
if user:
|
||||||
|
await self._alogin(user)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def force_login(self, user, backend=None):
|
def force_login(self, user, backend=None):
|
||||||
def get_backend():
|
|
||||||
from django.contrib.auth import load_backend
|
|
||||||
|
|
||||||
for backend_path in settings.AUTHENTICATION_BACKENDS:
|
|
||||||
backend = load_backend(backend_path)
|
|
||||||
if hasattr(backend, "get_user"):
|
|
||||||
return backend_path
|
|
||||||
|
|
||||||
if backend is None:
|
if backend is None:
|
||||||
backend = get_backend()
|
backend = self._get_backend()
|
||||||
user.backend = backend
|
user.backend = backend
|
||||||
self._login(user, backend)
|
self._login(user, backend)
|
||||||
|
|
||||||
|
async def aforce_login(self, user, backend=None):
|
||||||
|
if backend is None:
|
||||||
|
backend = self._get_backend()
|
||||||
|
user.backend = backend
|
||||||
|
await self._alogin(user, backend)
|
||||||
|
|
||||||
|
def _get_backend(self):
|
||||||
|
from django.contrib.auth import load_backend
|
||||||
|
|
||||||
|
for backend_path in settings.AUTHENTICATION_BACKENDS:
|
||||||
|
backend = load_backend(backend_path)
|
||||||
|
if hasattr(backend, "get_user"):
|
||||||
|
return backend_path
|
||||||
|
|
||||||
def _login(self, user, backend=None):
|
def _login(self, user, backend=None):
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
|
|
||||||
@ -789,6 +808,26 @@ class ClientMixin:
|
|||||||
login(request, user, backend)
|
login(request, user, backend)
|
||||||
# Save the session values.
|
# Save the session values.
|
||||||
request.session.save()
|
request.session.save()
|
||||||
|
self._set_login_cookies(request)
|
||||||
|
|
||||||
|
async def _alogin(self, user, backend=None):
|
||||||
|
from django.contrib.auth import alogin
|
||||||
|
|
||||||
|
# Create a fake request to store login details.
|
||||||
|
request = HttpRequest()
|
||||||
|
session = await self.asession()
|
||||||
|
if session:
|
||||||
|
request.session = session
|
||||||
|
else:
|
||||||
|
engine = import_module(settings.SESSION_ENGINE)
|
||||||
|
request.session = engine.SessionStore()
|
||||||
|
|
||||||
|
await alogin(request, user, backend)
|
||||||
|
# Save the session values.
|
||||||
|
await sync_to_async(request.session.save)()
|
||||||
|
self._set_login_cookies(request)
|
||||||
|
|
||||||
|
def _set_login_cookies(self, request):
|
||||||
# Set the cookie to represent the session.
|
# Set the cookie to represent the session.
|
||||||
session_cookie = settings.SESSION_COOKIE_NAME
|
session_cookie = settings.SESSION_COOKIE_NAME
|
||||||
self.cookies[session_cookie] = request.session.session_key
|
self.cookies[session_cookie] = request.session.session_key
|
||||||
@ -815,6 +854,21 @@ class ClientMixin:
|
|||||||
logout(request)
|
logout(request)
|
||||||
self.cookies = SimpleCookie()
|
self.cookies = SimpleCookie()
|
||||||
|
|
||||||
|
async def alogout(self):
|
||||||
|
"""See logout()."""
|
||||||
|
from django.contrib.auth import aget_user, alogout
|
||||||
|
|
||||||
|
request = HttpRequest()
|
||||||
|
session = await self.asession()
|
||||||
|
if session:
|
||||||
|
request.session = session
|
||||||
|
request.user = await aget_user(request)
|
||||||
|
else:
|
||||||
|
engine = import_module(settings.SESSION_ENGINE)
|
||||||
|
request.session = engine.SessionStore()
|
||||||
|
await alogout(request)
|
||||||
|
self.cookies = SimpleCookie()
|
||||||
|
|
||||||
def _parse_json(self, response, **extra):
|
def _parse_json(self, response, **extra):
|
||||||
if not hasattr(response, "_json"):
|
if not hasattr(response, "_json"):
|
||||||
if not JSON_CONTENT_TYPE_RE.match(response.get("Content-Type")):
|
if not JSON_CONTENT_TYPE_RE.match(response.get("Content-Type")):
|
||||||
|
@ -693,6 +693,9 @@ Utility functions
|
|||||||
.. currentmodule:: django.contrib.auth
|
.. currentmodule:: django.contrib.auth
|
||||||
|
|
||||||
.. function:: get_user(request)
|
.. function:: get_user(request)
|
||||||
|
.. function:: aget_user(request)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``aget_user()``
|
||||||
|
|
||||||
Returns the user model instance associated with the given ``request``’s
|
Returns the user model instance associated with the given ``request``’s
|
||||||
session.
|
session.
|
||||||
@ -716,3 +719,7 @@ Utility functions
|
|||||||
.. versionchanged:: 4.1.8
|
.. versionchanged:: 4.1.8
|
||||||
|
|
||||||
Fallback verification with :setting:`SECRET_KEY_FALLBACKS` was added.
|
Fallback verification with :setting:`SECRET_KEY_FALLBACKS` was added.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``aget_user()`` function was added.
|
||||||
|
@ -150,6 +150,12 @@ Minor features
|
|||||||
* The default iteration count for the PBKDF2 password hasher is increased from
|
* The default iteration count for the PBKDF2 password hasher is increased from
|
||||||
600,000 to 720,000.
|
600,000 to 720,000.
|
||||||
|
|
||||||
|
* The new asynchronous functions are now provided, using an
|
||||||
|
``a`` prefix: :func:`django.contrib.auth.aauthenticate`,
|
||||||
|
:func:`~.django.contrib.auth.aget_user`,
|
||||||
|
:func:`~.django.contrib.auth.alogin`, :func:`~.django.contrib.auth.alogout`,
|
||||||
|
and :func:`~.django.contrib.auth.aupdate_session_auth_hash`.
|
||||||
|
|
||||||
* ``AuthenticationMiddleware`` now adds an :meth:`.HttpRequest.auser`
|
* ``AuthenticationMiddleware`` now adds an :meth:`.HttpRequest.auser`
|
||||||
asynchronous method that returns the currently logged-in user.
|
asynchronous method that returns the currently logged-in user.
|
||||||
|
|
||||||
@ -366,7 +372,11 @@ Templates
|
|||||||
Tests
|
Tests
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
* ...
|
* :class:`~django.test.Client` and :class:`~django.test.AsyncClient` now
|
||||||
|
provide asynchronous methods, using an ``a`` prefix:
|
||||||
|
:meth:`~django.test.Client.asession`, :meth:`~django.test.Client.alogin`,
|
||||||
|
:meth:`~django.test.Client.aforce_login`, and
|
||||||
|
:meth:`~django.test.Client.alogout`.
|
||||||
|
|
||||||
URLs
|
URLs
|
||||||
~~~~
|
~~~~
|
||||||
|
@ -120,6 +120,9 @@ Authenticating users
|
|||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
.. function:: authenticate(request=None, **credentials)
|
.. function:: authenticate(request=None, **credentials)
|
||||||
|
.. function:: aauthenticate(request=None, **credentials)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``aauthenticate()``
|
||||||
|
|
||||||
Use :func:`~django.contrib.auth.authenticate()` to verify a set of
|
Use :func:`~django.contrib.auth.authenticate()` to verify a set of
|
||||||
credentials. It takes credentials as keyword arguments, ``username`` and
|
credentials. It takes credentials as keyword arguments, ``username`` and
|
||||||
@ -152,6 +155,10 @@ Authenticating users
|
|||||||
this. Rather if you're looking for a way to login a user, use the
|
this. Rather if you're looking for a way to login a user, use the
|
||||||
:class:`~django.contrib.auth.views.LoginView`.
|
:class:`~django.contrib.auth.views.LoginView`.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``aauthenticate()`` function was added.
|
||||||
|
|
||||||
.. _topic-authorization:
|
.. _topic-authorization:
|
||||||
|
|
||||||
Permissions and Authorization
|
Permissions and Authorization
|
||||||
@ -407,6 +414,9 @@ 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.
|
- this is done with a :func:`~django.contrib.auth.login` function.
|
||||||
|
|
||||||
.. function:: login(request, user, backend=None)
|
.. function:: login(request, user, backend=None)
|
||||||
|
.. function:: alogin(request, user, backend=None)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``alogin()``
|
||||||
|
|
||||||
To log a user in, from a view, use :func:`~django.contrib.auth.login()`. It
|
To log a user in, from a view, use :func:`~django.contrib.auth.login()`. It
|
||||||
takes an :class:`~django.http.HttpRequest` object and a
|
takes an :class:`~django.http.HttpRequest` object and a
|
||||||
@ -436,6 +446,10 @@ If you have an authenticated user you want to attach to the current session
|
|||||||
# Return an 'invalid login' error message.
|
# Return an 'invalid login' error message.
|
||||||
...
|
...
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``alogin()`` function was added.
|
||||||
|
|
||||||
Selecting the authentication backend
|
Selecting the authentication backend
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -463,6 +477,9 @@ How to log a user out
|
|||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
.. function:: logout(request)
|
.. function:: logout(request)
|
||||||
|
.. function:: alogout(request)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``alogout()``
|
||||||
|
|
||||||
To log out a user who has been logged in via
|
To log out a user who has been logged in via
|
||||||
:func:`django.contrib.auth.login()`, use
|
:func:`django.contrib.auth.login()`, use
|
||||||
@ -488,6 +505,10 @@ How to log a user out
|
|||||||
immediately after logging out, do that *after* calling
|
immediately after logging out, do that *after* calling
|
||||||
:func:`django.contrib.auth.logout()`.
|
:func:`django.contrib.auth.logout()`.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``alogout()`` function was added.
|
||||||
|
|
||||||
Limiting access to logged-in users
|
Limiting access to logged-in users
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
@ -935,6 +956,9 @@ and wish to have similar behavior, use the :func:`update_session_auth_hash`
|
|||||||
function.
|
function.
|
||||||
|
|
||||||
.. function:: update_session_auth_hash(request, user)
|
.. function:: update_session_auth_hash(request, user)
|
||||||
|
.. function:: aupdate_session_auth_hash(request, user)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``aupdate_session_auth_hash()``
|
||||||
|
|
||||||
This function takes the current request and the updated user object from
|
This function takes the current request and the updated user object from
|
||||||
which the new session hash will be derived and updates the session hash
|
which the new session hash will be derived and updates the session hash
|
||||||
@ -955,6 +979,10 @@ function.
|
|||||||
else:
|
else:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``aupdate_session_auth_hash()`` function was added.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Since
|
Since
|
||||||
|
@ -440,6 +440,9 @@ Use the ``django.test.Client`` class to make requests.
|
|||||||
The ``headers`` parameter was added.
|
The ``headers`` parameter was added.
|
||||||
|
|
||||||
.. method:: Client.login(**credentials)
|
.. method:: Client.login(**credentials)
|
||||||
|
.. method:: Client.alogin(**credentials)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``alogin()``
|
||||||
|
|
||||||
If your site uses Django's :doc:`authentication system</topics/auth/index>`
|
If your site uses Django's :doc:`authentication system</topics/auth/index>`
|
||||||
and you deal with logging in users, you can use the test client's
|
and you deal with logging in users, you can use the test client's
|
||||||
@ -485,7 +488,14 @@ Use the ``django.test.Client`` class to make requests.
|
|||||||
:meth:`~django.contrib.auth.models.UserManager.create_user` helper
|
:meth:`~django.contrib.auth.models.UserManager.create_user` helper
|
||||||
method to create a new user with a correctly hashed password.
|
method to create a new user with a correctly hashed password.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``alogin()`` method was added.
|
||||||
|
|
||||||
.. method:: Client.force_login(user, backend=None)
|
.. method:: Client.force_login(user, backend=None)
|
||||||
|
.. method:: Client.aforce_login(user, backend=None)
|
||||||
|
|
||||||
|
*Asynchronous version*: ``aforce_login()``
|
||||||
|
|
||||||
If your site uses Django's :doc:`authentication
|
If your site uses Django's :doc:`authentication
|
||||||
system</topics/auth/index>`, you can use the ``force_login()`` method
|
system</topics/auth/index>`, you can use the ``force_login()`` method
|
||||||
@ -509,7 +519,14 @@ Use the ``django.test.Client`` class to make requests.
|
|||||||
``login()`` by :ref:`using a weaker hasher while testing
|
``login()`` by :ref:`using a weaker hasher while testing
|
||||||
<speeding-up-tests-auth-hashers>`.
|
<speeding-up-tests-auth-hashers>`.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``aforce_login()`` method was added.
|
||||||
|
|
||||||
.. method:: Client.logout()
|
.. method:: Client.logout()
|
||||||
|
.. method:: Client.alogout()
|
||||||
|
|
||||||
|
*Asynchronous version*: ``alogout()``
|
||||||
|
|
||||||
If your site uses Django's :doc:`authentication system</topics/auth/index>`,
|
If your site uses Django's :doc:`authentication system</topics/auth/index>`,
|
||||||
the ``logout()`` method can be used to simulate the effect of a user
|
the ``logout()`` method can be used to simulate the effect of a user
|
||||||
@ -519,6 +536,10 @@ Use the ``django.test.Client`` class to make requests.
|
|||||||
and session data cleared to defaults. Subsequent requests will appear
|
and session data cleared to defaults. Subsequent requests will appear
|
||||||
to come from an :class:`~django.contrib.auth.models.AnonymousUser`.
|
to come from an :class:`~django.contrib.auth.models.AnonymousUser`.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
``alogout()`` method was added.
|
||||||
|
|
||||||
Testing responses
|
Testing responses
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@ -703,6 +724,13 @@ access these properties as part of a test condition.
|
|||||||
session["somekey"] = "test"
|
session["somekey"] = "test"
|
||||||
session.save()
|
session.save()
|
||||||
|
|
||||||
|
.. method:: Client.asession()
|
||||||
|
|
||||||
|
.. versionadded:: 5.0
|
||||||
|
|
||||||
|
This is similar to the :attr:`session` attribute but it works in async
|
||||||
|
contexts.
|
||||||
|
|
||||||
Setting the language
|
Setting the language
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
98
tests/async/test_async_auth.py
Normal file
98
tests/async/test_async_auth.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
from django.contrib.auth import (
|
||||||
|
aauthenticate,
|
||||||
|
aget_user,
|
||||||
|
alogin,
|
||||||
|
alogout,
|
||||||
|
aupdate_session_auth_hash,
|
||||||
|
)
|
||||||
|
from django.contrib.auth.models import AnonymousUser, User
|
||||||
|
from django.http import HttpRequest
|
||||||
|
from django.test import TestCase, override_settings
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncAuthTest(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.test_user = User.objects.create_user(
|
||||||
|
"testuser", "test@example.com", "testpw"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def test_aauthenticate(self):
|
||||||
|
user = await aauthenticate(username="testuser", password="testpw")
|
||||||
|
self.assertIsInstance(user, User)
|
||||||
|
self.assertEqual(user.username, self.test_user.username)
|
||||||
|
user.is_active = False
|
||||||
|
await user.asave()
|
||||||
|
self.assertIsNone(await aauthenticate(username="testuser", password="testpw"))
|
||||||
|
|
||||||
|
async def test_alogin(self):
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
await alogin(request, self.test_user)
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, User)
|
||||||
|
self.assertEqual(user.username, self.test_user.username)
|
||||||
|
|
||||||
|
async def test_alogin_without_user(self):
|
||||||
|
request = HttpRequest()
|
||||||
|
request.user = self.test_user
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
await alogin(request, None)
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, User)
|
||||||
|
self.assertEqual(user.username, self.test_user.username)
|
||||||
|
|
||||||
|
async def test_alogout(self):
|
||||||
|
await self.client.alogin(username="testuser", password="testpw")
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
await alogout(request)
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, AnonymousUser)
|
||||||
|
|
||||||
|
async def test_client_alogout(self):
|
||||||
|
await self.client.alogin(username="testuser", password="testpw")
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
await self.client.alogout()
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, AnonymousUser)
|
||||||
|
|
||||||
|
async def test_change_password(self):
|
||||||
|
await self.client.alogin(username="testuser", password="testpw")
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
request.user = self.test_user
|
||||||
|
await aupdate_session_auth_hash(request, self.test_user)
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, User)
|
||||||
|
|
||||||
|
async def test_invalid_login(self):
|
||||||
|
self.assertEqual(
|
||||||
|
await self.client.alogin(username="testuser", password=""), False
|
||||||
|
)
|
||||||
|
|
||||||
|
async def test_client_aforce_login(self):
|
||||||
|
await self.client.aforce_login(self.test_user)
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertEqual(user.username, self.test_user.username)
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
AUTHENTICATION_BACKENDS=[
|
||||||
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
|
"django.contrib.auth.backends.AllowAllUsersModelBackend",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def test_client_aforce_login_backend(self):
|
||||||
|
self.test_user.is_active = False
|
||||||
|
await self.test_user.asave()
|
||||||
|
await self.client.aforce_login(
|
||||||
|
self.test_user,
|
||||||
|
backend="django.contrib.auth.backends.AllowAllUsersModelBackend",
|
||||||
|
)
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertEqual(user.username, self.test_user.username)
|
@ -6,6 +6,7 @@ from django.contrib.auth import (
|
|||||||
BACKEND_SESSION_KEY,
|
BACKEND_SESSION_KEY,
|
||||||
SESSION_KEY,
|
SESSION_KEY,
|
||||||
_clean_credentials,
|
_clean_credentials,
|
||||||
|
aauthenticate,
|
||||||
authenticate,
|
authenticate,
|
||||||
get_user,
|
get_user,
|
||||||
signals,
|
signals,
|
||||||
@ -764,6 +765,28 @@ class AuthenticateTests(TestCase):
|
|||||||
status_code=500,
|
status_code=500,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
AUTHENTICATION_BACKENDS=["auth_tests.test_auth_backends.TypeErrorBackend"]
|
||||||
|
)
|
||||||
|
async def test_aauthenticate_sensitive_variables(self):
|
||||||
|
try:
|
||||||
|
await aauthenticate(
|
||||||
|
username="testusername", password=self.sensitive_password
|
||||||
|
)
|
||||||
|
except TypeError:
|
||||||
|
exc_info = sys.exc_info()
|
||||||
|
rf = RequestFactory()
|
||||||
|
response = technical_500_response(rf.get("/"), *exc_info)
|
||||||
|
self.assertNotContains(response, self.sensitive_password, status_code=500)
|
||||||
|
self.assertContains(response, "TypeErrorBackend", status_code=500)
|
||||||
|
self.assertContains(
|
||||||
|
response,
|
||||||
|
'<tr><td>credentials</td><td class="code">'
|
||||||
|
"<pre>'********************'</pre></td></tr>",
|
||||||
|
html=True,
|
||||||
|
status_code=500,
|
||||||
|
)
|
||||||
|
|
||||||
def test_clean_credentials_sensitive_variables(self):
|
def test_clean_credentials_sensitive_variables(self):
|
||||||
try:
|
try:
|
||||||
# Passing in a list to cause an exception
|
# Passing in a list to cause an exception
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
from asgiref.sync import sync_to_async
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user, get_user_model
|
from django.contrib.auth import aget_user, get_user, get_user_model
|
||||||
from django.contrib.auth.models import AnonymousUser, User
|
from django.contrib.auth.models import AnonymousUser, User
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
@ -129,6 +131,12 @@ class TestGetUser(TestCase):
|
|||||||
user = get_user(request)
|
user = get_user(request)
|
||||||
self.assertIsInstance(user, AnonymousUser)
|
self.assertIsInstance(user, AnonymousUser)
|
||||||
|
|
||||||
|
async def test_aget_user_anonymous(self):
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, AnonymousUser)
|
||||||
|
|
||||||
def test_get_user(self):
|
def test_get_user(self):
|
||||||
created_user = User.objects.create_user(
|
created_user = User.objects.create_user(
|
||||||
"testuser", "test@example.com", "testpw"
|
"testuser", "test@example.com", "testpw"
|
||||||
@ -162,3 +170,14 @@ class TestGetUser(TestCase):
|
|||||||
user = get_user(request)
|
user = get_user(request)
|
||||||
self.assertIsInstance(user, User)
|
self.assertIsInstance(user, User)
|
||||||
self.assertEqual(user.username, created_user.username)
|
self.assertEqual(user.username, created_user.username)
|
||||||
|
|
||||||
|
async def test_aget_user(self):
|
||||||
|
created_user = await sync_to_async(User.objects.create_user)(
|
||||||
|
"testuser", "test@example.com", "testpw"
|
||||||
|
)
|
||||||
|
await self.client.alogin(username="testuser", password="testpw")
|
||||||
|
request = HttpRequest()
|
||||||
|
request.session = await self.client.asession()
|
||||||
|
user = await aget_user(request)
|
||||||
|
self.assertIsInstance(user, User)
|
||||||
|
self.assertEqual(user.username, created_user.username)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user