Refs #28622 -- Removed settings.PASSWORD_RESET_TIMEOUT_DAYS per deprecation timeline.

This commit is contained in:
Mariusz Felisiak 2021-01-07 13:10:37 +01:00
parent 9e456f3166
commit 12ac4916af
8 changed files with 6 additions and 146 deletions

View File

@ -9,11 +9,9 @@ for a list of all possible variables.
import importlib import importlib
import os import os
import time import time
import traceback
import warnings import warnings
from pathlib import Path from pathlib import Path
import django
from django.conf import global_settings from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.deprecation import RemovedInDjango40Warning from django.utils.deprecation import RemovedInDjango40Warning
@ -21,11 +19,6 @@ from django.utils.functional import LazyObject, empty
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG = (
'The PASSWORD_RESET_TIMEOUT_DAYS setting is deprecated. Use '
'PASSWORD_RESET_TIMEOUT instead.'
)
DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG = ( DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG = (
'The DEFAULT_HASHING_ALGORITHM transitional setting is deprecated. ' 'The DEFAULT_HASHING_ALGORITHM transitional setting is deprecated. '
'Support for it and tokens, cookies, sessions, and signatures that use ' 'Support for it and tokens, cookies, sessions, and signatures that use '
@ -142,20 +135,6 @@ class LazySettings(LazyObject):
"""Return True if the settings have already been configured.""" """Return True if the settings have already been configured."""
return self._wrapped is not empty return self._wrapped is not empty
@property
def PASSWORD_RESET_TIMEOUT_DAYS(self):
stack = traceback.extract_stack()
# Show a warning if the setting is used outside of Django.
# Stack index: -1 this line, -2 the caller.
filename, _, _, _ = stack[-2]
if not filename.startswith(os.path.dirname(django.__file__)):
warnings.warn(
PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG,
RemovedInDjango40Warning,
stacklevel=2,
)
return self.__getattr__('PASSWORD_RESET_TIMEOUT_DAYS')
class Settings: class Settings:
def __init__(self, settings_module): def __init__(self, settings_module):
@ -185,15 +164,6 @@ class Settings:
setattr(self, setting, setting_value) setattr(self, setting, setting_value)
self._explicit_settings.add(setting) self._explicit_settings.add(setting)
if self.is_overridden('PASSWORD_RESET_TIMEOUT_DAYS'):
if self.is_overridden('PASSWORD_RESET_TIMEOUT'):
raise ImproperlyConfigured(
'PASSWORD_RESET_TIMEOUT_DAYS/PASSWORD_RESET_TIMEOUT are '
'mutually exclusive.'
)
setattr(self, 'PASSWORD_RESET_TIMEOUT', self.PASSWORD_RESET_TIMEOUT_DAYS * 60 * 60 * 24)
warnings.warn(PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG, RemovedInDjango40Warning)
if self.is_overridden('DEFAULT_HASHING_ALGORITHM'): if self.is_overridden('DEFAULT_HASHING_ALGORITHM'):
warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning) warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning)
@ -240,9 +210,6 @@ class UserSettingsHolder:
def __setattr__(self, name, value): def __setattr__(self, name, value):
self._deleted.discard(name) self._deleted.discard(name)
if name == 'PASSWORD_RESET_TIMEOUT_DAYS':
setattr(self, 'PASSWORD_RESET_TIMEOUT', value * 60 * 60 * 24)
warnings.warn(PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG, RemovedInDjango40Warning)
if name == 'DEFAULT_HASHING_ALGORITHM': if name == 'DEFAULT_HASHING_ALGORITHM':
warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning) warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning)
super().__setattr__(name, value) super().__setattr__(name, value)

View File

@ -515,9 +515,6 @@ LOGIN_REDIRECT_URL = '/accounts/profile/'
LOGOUT_REDIRECT_URL = None LOGOUT_REDIRECT_URL = None
# The number of days a password reset link is valid for
PASSWORD_RESET_TIMEOUT_DAYS = 3
# The number of seconds a password reset link is valid for (default: 3 days). # The number of seconds a password reset link is valid for (default: 3 days).
PASSWORD_RESET_TIMEOUT = 60 * 60 * 24 * 3 PASSWORD_RESET_TIMEOUT = 60 * 60 * 24 * 3

View File

@ -876,8 +876,8 @@ details on these changes.
supports base36 encoded user IDs supports base36 encoded user IDs
(``django.contrib.auth.views.password_reset_confirm_uidb36``) will be (``django.contrib.auth.views.password_reset_confirm_uidb36``) will be
removed. If your site has been running Django 1.6 for more than removed. If your site has been running Django 1.6 for more than
:setting:`PASSWORD_RESET_TIMEOUT_DAYS`, this change will have no effect. If ``PASSWORD_RESET_TIMEOUT_DAYS``, this change will have no effect. If not,
not, then any password reset links generated before you upgrade to Django 1.7 then any password reset links generated before you upgrade to Django 1.7
won't work after the upgrade. won't work after the upgrade.
* The ``django.utils.encoding.StrAndUnicode`` mix-in will be removed. * The ``django.utils.encoding.StrAndUnicode`` mix-in will be removed.

View File

@ -2967,21 +2967,6 @@ Used by the :class:`~django.contrib.auth.views.PasswordResetConfirmView`.
as someone gaining access to email archives that may contain old, unused as someone gaining access to email archives that may contain old, unused
password reset tokens. password reset tokens.
.. setting:: PASSWORD_RESET_TIMEOUT_DAYS
``PASSWORD_RESET_TIMEOUT_DAYS``
-------------------------------
Default: ``3``
The number of days a password reset link is valid for.
Used by the :class:`~django.contrib.auth.views.PasswordResetConfirmView`.
.. deprecated:: 3.1
This setting is deprecated. Use :setting:`PASSWORD_RESET_TIMEOUT` instead.
.. setting:: PASSWORD_HASHERS .. setting:: PASSWORD_HASHERS
``PASSWORD_HASHERS`` ``PASSWORD_HASHERS``

View File

@ -781,7 +781,7 @@ time you need to run Django 1.3 for the data to expire or become irrelevant.
* Consequences: Password reset links from before the upgrade will not work. * Consequences: Password reset links from before the upgrade will not work.
* Time period: Defined by :setting:`PASSWORD_RESET_TIMEOUT_DAYS`. * Time period: Defined by ``PASSWORD_RESET_TIMEOUT_DAYS``.
Form-related hashes: these have a much shorter lifetime and are relevant Form-related hashes: these have a much shorter lifetime and are relevant
only for the short window where a user might fill in a form generated by the only for the short window where a user might fill in a form generated by the

View File

@ -756,7 +756,7 @@ A temporary shim for ``django.contrib.auth.views.password_reset_confirm()``
that will allow password reset links generated prior to Django 1.6 to continue that will allow password reset links generated prior to Django 1.6 to continue
to work has been added to provide backwards compatibility; this will be removed to work has been added to provide backwards compatibility; this will be removed
in Django 1.7. Thus, as long as your site has been running Django 1.6 for more in Django 1.7. Thus, as long as your site has been running Django 1.6 for more
than :setting:`PASSWORD_RESET_TIMEOUT_DAYS`, this change will have no effect. than ``PASSWORD_RESET_TIMEOUT_DAYS``, this change will have no effect.
If not (for example, if you upgrade directly from Django 1.5 to Django 1.7), If not (for example, if you upgrade directly from Django 1.5 to Django 1.7),
then any password reset links generated before you upgrade to Django 1.7 or then any password reset links generated before you upgrade to Django 1.7 or
later won't work after the upgrade. later won't work after the upgrade.
@ -788,7 +788,7 @@ the ``name`` argument so it doesn't conflict with the new url::
'django.contrib.auth.views.password_reset_confirm_uidb36'), 'django.contrib.auth.views.password_reset_confirm_uidb36'),
You can remove this URL pattern after your app has been deployed with Django You can remove this URL pattern after your app has been deployed with Django
1.6 for :setting:`PASSWORD_RESET_TIMEOUT_DAYS`. 1.6 for ``PASSWORD_RESET_TIMEOUT_DAYS``.
Default session serialization switched to JSON Default session serialization switched to JSON
---------------------------------------------- ----------------------------------------------

View File

@ -267,4 +267,4 @@ to remove usage of these features.
See :ref:`deprecated-features-3.1` for details on these changes, including how See :ref:`deprecated-features-3.1` for details on these changes, including how
to remove usage of these features. to remove usage of these features.
* ... * The ``PASSWORD_RESET_TIMEOUT_DAYS`` setting is removed.

View File

@ -1,89 +0,0 @@
import sys
from datetime import datetime, timedelta
from types import ModuleType
from django.conf import (
PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG, Settings, settings,
)
from django.contrib.auth.models import User
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase, ignore_warnings
from django.utils.deprecation import RemovedInDjango40Warning
class DeprecationTests(TestCase):
msg = PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG
@ignore_warnings(category=RemovedInDjango40Warning)
def test_timeout(self):
"""The token is valid after n days, but no greater."""
# Uses a mocked version of PasswordResetTokenGenerator so we can change
# the value of 'now'.
class Mocked(PasswordResetTokenGenerator):
def __init__(self, now):
self._now_val = now
super().__init__()
def _now(self):
return self._now_val
user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw')
p0 = PasswordResetTokenGenerator()
tk1 = p0.make_token(user)
p1 = Mocked(datetime.now() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS))
self.assertIs(p1.check_token(user, tk1), True)
p2 = Mocked(datetime.now() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1))
self.assertIs(p2.check_token(user, tk1), False)
with self.settings(PASSWORD_RESET_TIMEOUT_DAYS=1):
self.assertEqual(settings.PASSWORD_RESET_TIMEOUT, 60 * 60 * 24)
p3 = Mocked(datetime.now() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS))
self.assertIs(p3.check_token(user, tk1), True)
p4 = Mocked(datetime.now() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1))
self.assertIs(p4.check_token(user, tk1), False)
def test_override_settings_warning(self):
with self.assertRaisesMessage(RemovedInDjango40Warning, self.msg):
with self.settings(PASSWORD_RESET_TIMEOUT_DAYS=2):
pass
def test_settings_init_warning(self):
settings_module = ModuleType('fake_settings_module')
settings_module.SECRET_KEY = 'foo'
settings_module.PASSWORD_RESET_TIMEOUT_DAYS = 2
sys.modules['fake_settings_module'] = settings_module
try:
with self.assertRaisesMessage(RemovedInDjango40Warning, self.msg):
Settings('fake_settings_module')
finally:
del sys.modules['fake_settings_module']
def test_access_warning(self):
with self.assertRaisesMessage(RemovedInDjango40Warning, self.msg):
settings.PASSWORD_RESET_TIMEOUT_DAYS
# Works a second time.
with self.assertRaisesMessage(RemovedInDjango40Warning, self.msg):
settings.PASSWORD_RESET_TIMEOUT_DAYS
@ignore_warnings(category=RemovedInDjango40Warning)
def test_access(self):
with self.settings(PASSWORD_RESET_TIMEOUT_DAYS=2):
self.assertEqual(settings.PASSWORD_RESET_TIMEOUT_DAYS, 2)
# Works a second time.
self.assertEqual(settings.PASSWORD_RESET_TIMEOUT_DAYS, 2)
def test_use_both_settings_init_error(self):
msg = (
'PASSWORD_RESET_TIMEOUT_DAYS/PASSWORD_RESET_TIMEOUT are '
'mutually exclusive.'
)
settings_module = ModuleType('fake_settings_module')
settings_module.SECRET_KEY = 'foo'
settings_module.PASSWORD_RESET_TIMEOUT_DAYS = 2
settings_module.PASSWORD_RESET_TIMEOUT = 2000
sys.modules['fake_settings_module'] = settings_module
try:
with self.assertRaisesMessage(ImproperlyConfigured, msg):
Settings('fake_settings_module')
finally:
del sys.modules['fake_settings_module']