Refs #28622 -- Removed settings.PASSWORD_RESET_TIMEOUT_DAYS per deprecation timeline.
This commit is contained in:
parent
9e456f3166
commit
12ac4916af
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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``
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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']
|
|
Loading…
Reference in New Issue