1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #30037 -- Added request arg to RemoteUserBackend.configure_user().

This commit is contained in:
Joshua Cannon 2018-12-13 10:14:03 -06:00 committed by Tim Graham
parent 4ca2820ff5
commit db1b10ef0d
7 changed files with 100 additions and 9 deletions

View File

@ -439,6 +439,7 @@ answer newbie questions, and generally made Django that much better:
Josef Rousek <josef.rousek@gmail.com> Josef Rousek <josef.rousek@gmail.com>
Joseph Kocherhans <joseph@jkocherhans.com> Joseph Kocherhans <joseph@jkocherhans.com>
Josh Smeaton <josh.smeaton@gmail.com> Josh Smeaton <josh.smeaton@gmail.com>
Joshua Cannon <joshdcannon@gmail.com>
Joshua Ginsberg <jag@flowtheory.net> Joshua Ginsberg <jag@flowtheory.net>
Jozko Skrablin <jozko.skrablin@gmail.com> Jozko Skrablin <jozko.skrablin@gmail.com>
J. Pablo Fernandez <pupeno@pupeno.com> J. Pablo Fernandez <pupeno@pupeno.com>

View File

@ -1,5 +1,9 @@
import inspect
import warnings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.utils.deprecation import RemovedInDjango31Warning
UserModel = get_user_model() UserModel = get_user_model()
@ -143,7 +147,17 @@ class RemoteUserBackend(ModelBackend):
UserModel.USERNAME_FIELD: username UserModel.USERNAME_FIELD: username
}) })
if created: if created:
user = self.configure_user(user) args = (request, user)
try:
inspect.getcallargs(self.configure_user, request, user)
except TypeError:
args = (user,)
warnings.warn(
'Update %s.configure_user() to accept `request` as '
'the first argument.'
% self.__class__.__name__, RemovedInDjango31Warning
)
user = self.configure_user(*args)
else: else:
try: try:
user = UserModel._default_manager.get_by_natural_key(username) user = UserModel._default_manager.get_by_natural_key(username)
@ -160,7 +174,7 @@ class RemoteUserBackend(ModelBackend):
""" """
return username return username
def configure_user(self, user): def configure_user(self, request, user):
""" """
Configure a user after creation and return the updated user. Configure a user after creation and return the updated user.

View File

@ -29,6 +29,9 @@ details on these changes.
* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` will be * ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` will be
removed. removed.
* ``RemoteUserBackend.configure_user()`` will require ``request`` as the first
positional argument.
.. _deprecation-removed-in-3.0: .. _deprecation-removed-in-3.0:
3.0 3.0

View File

@ -611,13 +611,22 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
information) prior to using it to get or create a user object. Returns information) prior to using it to get or create a user object. Returns
the cleaned username. the cleaned username.
.. method:: configure_user(user) .. method:: configure_user(request, user)
Configures a newly created user. This method is called immediately Configures a newly created user. This method is called immediately
after a new user is created, and can be used to perform custom setup after a new user is created, and can be used to perform custom setup
actions, such as setting the user's groups based on attributes in an actions, such as setting the user's groups based on attributes in an
LDAP directory. Returns the user object. LDAP directory. Returns the user object.
``request`` is an :class:`~django.http.HttpRequest` and may be ``None``
if it wasn't provided to :func:`~django.contrib.auth.authenticate`
(which passes it on to the backend).
.. versionchanged:: 2.2
The ``request`` argument was added. Support for method overrides
that don't accept it will be removed in Django 3.1.
.. method:: user_can_authenticate() .. method:: user_can_authenticate()
Returns whether the user is allowed to authenticate. This method Returns whether the user is allowed to authenticate. This method

View File

@ -55,7 +55,8 @@ Minor features
:mod:`django.contrib.auth` :mod:`django.contrib.auth`
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
* ... * The ``HttpRequest`` is now passed as the first positional argument to
:meth:`.RemoteUserBackend.configure_user`, if it accepts it.
:mod:`django.contrib.contenttypes` :mod:`django.contrib.contenttypes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -505,3 +506,7 @@ Miscellaneous
* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` is * ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` is
deprecated due to the intractable problems that is has. Use deprecated due to the intractable problems that is has. Use
:class:`.ManifestStaticFilesStorage` or a third-party cloud storage instead. :class:`.ManifestStaticFilesStorage` or a third-party cloud storage instead.
* :meth:`.RemoteUserBackend.configure_user` is now passed ``request`` as the
first positional argument, if it accepts it. Support for overrides that don't
accept it will be removed in Django 3.1.

View File

@ -15,6 +15,7 @@ class RemoteUserTest(TestCase):
middleware = 'django.contrib.auth.middleware.RemoteUserMiddleware' middleware = 'django.contrib.auth.middleware.RemoteUserMiddleware'
backend = 'django.contrib.auth.backends.RemoteUserBackend' backend = 'django.contrib.auth.backends.RemoteUserBackend'
header = 'REMOTE_USER' header = 'REMOTE_USER'
email_header = 'REMOTE_EMAIL'
# Usernames to be passed in REMOTE_USER for the test_known_user test case. # Usernames to be passed in REMOTE_USER for the test_known_user test case.
known_user = 'knownuser' known_user = 'knownuser'
@ -192,11 +193,11 @@ class CustomRemoteUserBackend(RemoteUserBackend):
""" """
return username.split('@')[0] return username.split('@')[0]
def configure_user(self, user): def configure_user(self, request, user):
""" """
Sets user's email address. Sets user's email address using the email specified in an HTTP header.
""" """
user.email = 'user@example.com' user.email = request.META.get(RemoteUserTest.email_header, '')
user.save() user.save()
return user return user
@ -224,9 +225,17 @@ class RemoteUserCustomTest(RemoteUserTest):
def test_unknown_user(self): def test_unknown_user(self):
""" """
The unknown user created should be configured with an email address. The unknown user created should be configured with an email address
provided in the request header.
""" """
super().test_unknown_user() num_users = User.objects.count()
response = self.client.get('/remote_user/', **{
self.header: 'newuser',
self.email_header: 'user@example.com',
})
self.assertEqual(response.context['user'].username, 'newuser')
self.assertEqual(response.context['user'].email, 'user@example.com')
self.assertEqual(User.objects.count(), num_users + 1)
newuser = User.objects.get(username='newuser') newuser = User.objects.get(username='newuser')
self.assertEqual(newuser.email, 'user@example.com') self.assertEqual(newuser.email, 'user@example.com')

View File

@ -0,0 +1,50 @@
import warnings
from django.contrib.auth.backends import RemoteUserBackend
from django.contrib.auth.models import User
from django.test import TestCase, modify_settings, override_settings
class CustomRemoteUserBackend(RemoteUserBackend):
"""Override configure_user() without a request argument."""
def configure_user(self, user):
user.email = 'user@example.com'
user.save()
return user
@override_settings(ROOT_URLCONF='auth_tests.urls')
class RemoteUserCustomTest(TestCase):
middleware = 'django.contrib.auth.middleware.RemoteUserMiddleware'
backend = 'auth_tests.test_remote_user_deprecation.CustomRemoteUserBackend'
header = 'REMOTE_USER'
def setUp(self):
self.patched_settings = modify_settings(
AUTHENTICATION_BACKENDS={'append': self.backend},
MIDDLEWARE={'append': self.middleware},
)
self.patched_settings.enable()
def tearDown(self):
self.patched_settings.disable()
def test_configure_user_deprecation_warning(self):
"""
A deprecation warning is shown for RemoteUserBackend that have a
configure_user() method without a request parameter.
"""
num_users = User.objects.count()
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
response = self.client.get('/remote_user/', **{self.header: 'newuser'})
self.assertEqual(response.context['user'].username, 'newuser')
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
'Update CustomRemoteUserBackend.configure_user() to accept '
'`request` as the first argument.'
)
self.assertEqual(User.objects.count(), num_users + 1)
user = User.objects.get(username='newuser')
self.assertEqual(user.email, 'user@example.com')