summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Cannon <joshua.cannon@ni.com>2018-12-13 10:14:03 -0600
committerTim Graham <timograham@gmail.com>2019-01-09 20:01:04 -0500
commitdb1b10ef0dcab2b8bacbea4adc681a57bd70b462 (patch)
tree98e5de16c2ba4a77d52bb0fc61c3b9b2da2f0473
parent4ca2820ff573ed87c70fedda69efa8de23955669 (diff)
Fixed #30037 -- Added request arg to RemoteUserBackend.configure_user().
-rw-r--r--AUTHORS1
-rw-r--r--django/contrib/auth/backends.py18
-rw-r--r--docs/internals/deprecation.txt3
-rw-r--r--docs/ref/contrib/auth.txt11
-rw-r--r--docs/releases/2.2.txt7
-rw-r--r--tests/auth_tests/test_remote_user.py19
-rw-r--r--tests/auth_tests/test_remote_user_deprecation.py50
7 files changed, 100 insertions, 9 deletions
diff --git a/AUTHORS b/AUTHORS
index 51bc2f592a..ddc2c9ee84 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -439,6 +439,7 @@ answer newbie questions, and generally made Django that much better:
Josef Rousek <josef.rousek@gmail.com>
Joseph Kocherhans <joseph@jkocherhans.com>
Josh Smeaton <josh.smeaton@gmail.com>
+ Joshua Cannon <joshdcannon@gmail.com>
Joshua Ginsberg <jag@flowtheory.net>
Jozko Skrablin <jozko.skrablin@gmail.com>
J. Pablo Fernandez <pupeno@pupeno.com>
diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
index 64937753ed..7549d71273 100644
--- a/django/contrib/auth/backends.py
+++ b/django/contrib/auth/backends.py
@@ -1,5 +1,9 @@
+import inspect
+import warnings
+
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
+from django.utils.deprecation import RemovedInDjango31Warning
UserModel = get_user_model()
@@ -143,7 +147,17 @@ class RemoteUserBackend(ModelBackend):
UserModel.USERNAME_FIELD: username
})
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:
try:
user = UserModel._default_manager.get_by_natural_key(username)
@@ -160,7 +174,7 @@ class RemoteUserBackend(ModelBackend):
"""
return username
- def configure_user(self, user):
+ def configure_user(self, request, user):
"""
Configure a user after creation and return the updated user.
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 8c81744e17..0e85e59e8c 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -29,6 +29,9 @@ details on these changes.
* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` will be
removed.
+* ``RemoteUserBackend.configure_user()`` will require ``request`` as the first
+ positional argument.
+
.. _deprecation-removed-in-3.0:
3.0
diff --git a/docs/ref/contrib/auth.txt b/docs/ref/contrib/auth.txt
index 0dfa3a9261..efbffa62c2 100644
--- a/docs/ref/contrib/auth.txt
+++ b/docs/ref/contrib/auth.txt
@@ -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
the cleaned username.
- .. method:: configure_user(user)
+ .. method:: configure_user(request, user)
Configures a newly created user. This method is called immediately
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
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()
Returns whether the user is allowed to authenticate. This method
diff --git a/docs/releases/2.2.txt b/docs/releases/2.2.txt
index 150fe413db..7cb5c84475 100644
--- a/docs/releases/2.2.txt
+++ b/docs/releases/2.2.txt
@@ -55,7 +55,8 @@ Minor features
: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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -505,3 +506,7 @@ Miscellaneous
* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` is
deprecated due to the intractable problems that is has. Use
: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.
diff --git a/tests/auth_tests/test_remote_user.py b/tests/auth_tests/test_remote_user.py
index 2a1ebbb569..6260c460af 100644
--- a/tests/auth_tests/test_remote_user.py
+++ b/tests/auth_tests/test_remote_user.py
@@ -15,6 +15,7 @@ class RemoteUserTest(TestCase):
middleware = 'django.contrib.auth.middleware.RemoteUserMiddleware'
backend = 'django.contrib.auth.backends.RemoteUserBackend'
header = 'REMOTE_USER'
+ email_header = 'REMOTE_EMAIL'
# Usernames to be passed in REMOTE_USER for the test_known_user test case.
known_user = 'knownuser'
@@ -192,11 +193,11 @@ class CustomRemoteUserBackend(RemoteUserBackend):
"""
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()
return user
@@ -224,9 +225,17 @@ class RemoteUserCustomTest(RemoteUserTest):
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')
self.assertEqual(newuser.email, 'user@example.com')
diff --git a/tests/auth_tests/test_remote_user_deprecation.py b/tests/auth_tests/test_remote_user_deprecation.py
new file mode 100644
index 0000000000..1b31d9f038
--- /dev/null
+++ b/tests/auth_tests/test_remote_user_deprecation.py
@@ -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')