From 12ac4916af034221a4e08ce6b5669e53a0223a67 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 7 Jan 2021 13:10:37 +0100 Subject: [PATCH] Refs #28622 -- Removed settings.PASSWORD_RESET_TIMEOUT_DAYS per deprecation timeline. --- django/conf/__init__.py | 33 ------- django/conf/global_settings.py | 3 - docs/internals/deprecation.txt | 4 +- docs/ref/settings.txt | 15 ---- docs/releases/1.4.txt | 2 +- docs/releases/1.6.txt | 4 +- docs/releases/4.0.txt | 2 +- .../test_password_reset_timeout_days.py | 89 ------------------- 8 files changed, 6 insertions(+), 146 deletions(-) delete mode 100644 tests/auth_tests/test_password_reset_timeout_days.py diff --git a/django/conf/__init__.py b/django/conf/__init__.py index 28302440c7..8ebc3c70ce 100644 --- a/django/conf/__init__.py +++ b/django/conf/__init__.py @@ -9,11 +9,9 @@ for a list of all possible variables. import importlib import os import time -import traceback import warnings from pathlib import Path -import django from django.conf import global_settings from django.core.exceptions import ImproperlyConfigured from django.utils.deprecation import RemovedInDjango40Warning @@ -21,11 +19,6 @@ from django.utils.functional import LazyObject, empty 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 = ( 'The DEFAULT_HASHING_ALGORITHM transitional setting is deprecated. ' '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 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: def __init__(self, settings_module): @@ -185,15 +164,6 @@ class Settings: setattr(self, setting, setting_value) 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'): warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning) @@ -240,9 +210,6 @@ class UserSettingsHolder: def __setattr__(self, name, value): 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': warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning) super().__setattr__(name, value) diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index cf9fae496e..44f8275a24 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -515,9 +515,6 @@ LOGIN_REDIRECT_URL = '/accounts/profile/' 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). PASSWORD_RESET_TIMEOUT = 60 * 60 * 24 * 3 diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index d0d9c45f7e..181dc8e441 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -876,8 +876,8 @@ details on these changes. supports base36 encoded user IDs (``django.contrib.auth.views.password_reset_confirm_uidb36``) will be 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 - not, then any password reset links generated before you upgrade to Django 1.7 + ``PASSWORD_RESET_TIMEOUT_DAYS``, this change will have no effect. If not, + then any password reset links generated before you upgrade to Django 1.7 won't work after the upgrade. * The ``django.utils.encoding.StrAndUnicode`` mix-in will be removed. diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 55773d5c9b..796045aebd 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -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 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 ``PASSWORD_HASHERS`` diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index aa760cc4c9..4659b22f32 100644 --- a/docs/releases/1.4.txt +++ b/docs/releases/1.4.txt @@ -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. - * 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 only for the short window where a user might fill in a form generated by the diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index 60df27ad31..d6342a4cb2 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -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 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 -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), then any password reset links generated before you upgrade to Django 1.7 or 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'), 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 ---------------------------------------------- diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt index 636ddf5ec5..3f3d46617e 100644 --- a/docs/releases/4.0.txt +++ b/docs/releases/4.0.txt @@ -267,4 +267,4 @@ to remove usage of these features. See :ref:`deprecated-features-3.1` for details on these changes, including how to remove usage of these features. -* ... +* The ``PASSWORD_RESET_TIMEOUT_DAYS`` setting is removed. diff --git a/tests/auth_tests/test_password_reset_timeout_days.py b/tests/auth_tests/test_password_reset_timeout_days.py deleted file mode 100644 index 17aba80567..0000000000 --- a/tests/auth_tests/test_password_reset_timeout_days.py +++ /dev/null @@ -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']