Refs #31842 -- Removed DEFAULT_HASHING_ALGORITHM transitional setting.
Per deprecation timeline.
This commit is contained in:
parent
e7208f13c0
commit
0aa6a602b2
|
@ -9,22 +9,14 @@ for a list of all possible variables.
|
|||
import importlib
|
||||
import os
|
||||
import time
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import global_settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
from django.utils.functional import LazyObject, empty
|
||||
|
||||
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
|
||||
|
||||
DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG = (
|
||||
'The DEFAULT_HASHING_ALGORITHM transitional setting is deprecated. '
|
||||
'Support for it and tokens, cookies, sessions, and signatures that use '
|
||||
'SHA-1 hashing algorithm will be removed in Django 4.0.'
|
||||
)
|
||||
|
||||
|
||||
class SettingsReference(str):
|
||||
"""
|
||||
|
@ -164,9 +156,6 @@ class Settings:
|
|||
setattr(self, setting, setting_value)
|
||||
self._explicit_settings.add(setting)
|
||||
|
||||
if self.is_overridden('DEFAULT_HASHING_ALGORITHM'):
|
||||
warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning)
|
||||
|
||||
if hasattr(time, 'tzset') and self.TIME_ZONE:
|
||||
# When we can, attempt to validate the timezone. If we can't find
|
||||
# this file, no check happens and it's harmless.
|
||||
|
@ -210,8 +199,6 @@ class UserSettingsHolder:
|
|||
|
||||
def __setattr__(self, name, value):
|
||||
self._deleted.discard(name)
|
||||
if name == 'DEFAULT_HASHING_ALGORITHM':
|
||||
warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning)
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def __delattr__(self, name):
|
||||
|
|
|
@ -439,12 +439,6 @@ WSGI_APPLICATION = None
|
|||
# you may be opening yourself up to a security risk.
|
||||
SECURE_PROXY_SSL_HEADER = None
|
||||
|
||||
# Default hashing algorithm to use for encoding cookies, password reset tokens
|
||||
# in the admin site, user sessions, and signatures. It's a transitional setting
|
||||
# helpful in migrating multiple instance of the same project to Django 3.1+.
|
||||
# Algorithm must be 'sha1' or 'sha256'.
|
||||
DEFAULT_HASHING_ALGORITHM = 'sha256'
|
||||
|
||||
##############
|
||||
# MIDDLEWARE #
|
||||
##############
|
||||
|
|
|
@ -4,7 +4,6 @@ not in INSTALLED_APPS.
|
|||
"""
|
||||
import unicodedata
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import password_validation
|
||||
from django.contrib.auth.hashers import (
|
||||
check_password, is_password_usable, make_password,
|
||||
|
@ -129,10 +128,7 @@ class AbstractBaseUser(models.Model):
|
|||
return salted_hmac(
|
||||
key_salt,
|
||||
self.password,
|
||||
# RemovedInDjango40Warning: when the deprecation ends, replace
|
||||
# with:
|
||||
# algorithm='sha256',
|
||||
algorithm=settings.DEFAULT_HASHING_ALGORITHM,
|
||||
algorithm='sha256',
|
||||
).hexdigest()
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -16,9 +16,7 @@ class PasswordResetTokenGenerator:
|
|||
|
||||
def __init__(self):
|
||||
self.secret = self.secret or settings.SECRET_KEY
|
||||
# RemovedInDjango40Warning: when the deprecation ends, replace with:
|
||||
# self.algorithm = self.algorithm or 'sha256'
|
||||
self.algorithm = self.algorithm or settings.DEFAULT_HASHING_ALGORITHM
|
||||
self.algorithm = self.algorithm or 'sha256'
|
||||
|
||||
def make_token(self, user):
|
||||
"""
|
||||
|
|
|
@ -119,11 +119,6 @@ E023 = Error(
|
|||
id='security.E023',
|
||||
)
|
||||
|
||||
E100 = Error(
|
||||
"DEFAULT_HASHING_ALGORITHM must be 'sha1' or 'sha256'.",
|
||||
id='security.E100',
|
||||
)
|
||||
|
||||
|
||||
def _security_middleware():
|
||||
return 'django.middleware.security.SecurityMiddleware' in settings.MIDDLEWARE
|
||||
|
@ -237,11 +232,3 @@ def check_referrer_policy(app_configs, **kwargs):
|
|||
if not values <= REFERRER_POLICY_VALUES:
|
||||
return [E023]
|
||||
return []
|
||||
|
||||
|
||||
# RemovedInDjango40Warning
|
||||
@register(Tags.security)
|
||||
def check_default_hashing_algorithm(app_configs, **kwargs):
|
||||
if settings.DEFAULT_HASHING_ALGORITHM not in {'sha1', 'sha256'}:
|
||||
return [E100]
|
||||
return []
|
||||
|
|
|
@ -129,9 +129,7 @@ class Signer:
|
|||
'only A-z0-9-_=)' % sep,
|
||||
)
|
||||
self.salt = salt or '%s.%s' % (self.__class__.__module__, self.__class__.__name__)
|
||||
# RemovedInDjango40Warning: when the deprecation ends, replace with:
|
||||
# self.algorithm = algorithm or 'sha256'
|
||||
self.algorithm = algorithm or settings.DEFAULT_HASHING_ALGORITHM
|
||||
self.algorithm = algorithm or 'sha256'
|
||||
|
||||
def signature(self, value):
|
||||
return base64_hmac(self.salt + 'signer', value, self.key, algorithm=self.algorithm)
|
||||
|
|
|
@ -494,8 +494,8 @@ The following checks are run if you use the :option:`check --deploy` option:
|
|||
The following checks verify that your security-related settings are correctly
|
||||
configured:
|
||||
|
||||
* **security.E100**: :setting:`DEFAULT_HASHING_ALGORITHM` must be ``'sha1'`` or
|
||||
``'sha256'``.
|
||||
* **security.E100**: ``DEFAULT_HASHING_ALGORITHM`` must be ``'sha1'`` or
|
||||
``'sha256'``. *This check appeared in Django 3.1 and 3.2*.
|
||||
* **security.E101**: The CSRF failure view ``'path.to.view'`` does not take the
|
||||
correct number of arguments.
|
||||
* **security.E102**: The CSRF failure view ``'path.to.view'`` could not be
|
||||
|
|
|
@ -1291,25 +1291,6 @@ Default email address to use for various automated correspondence from the
|
|||
site manager(s). This doesn't include error messages sent to :setting:`ADMINS`
|
||||
and :setting:`MANAGERS`; for that, see :setting:`SERVER_EMAIL`.
|
||||
|
||||
.. setting:: DEFAULT_HASHING_ALGORITHM
|
||||
|
||||
``DEFAULT_HASHING_ALGORITHM``
|
||||
-----------------------------
|
||||
|
||||
Default: ``'sha256'``
|
||||
|
||||
Default hashing algorithm to use for encoding cookies, password reset tokens in
|
||||
the admin site, user sessions, and signatures created by
|
||||
:class:`django.core.signing.Signer` and :meth:`django.core.signing.dumps`.
|
||||
Algorithm must be ``'sha1'`` or ``'sha256'``. See
|
||||
:ref:`release notes <default-hashing-algorithm-usage>` for usage details.
|
||||
|
||||
.. deprecated:: 3.1
|
||||
|
||||
This transitional setting is deprecated. Support for it and tokens,
|
||||
cookies, sessions, and signatures that use SHA-1 hashing algorithm will be
|
||||
removed in Django 4.0.
|
||||
|
||||
.. setting:: DEFAULT_INDEX_TABLESPACE
|
||||
|
||||
``DEFAULT_INDEX_TABLESPACE``
|
||||
|
|
|
@ -101,17 +101,17 @@ of this release <deprecated-jsonfield>`.
|
|||
``DEFAULT_HASHING_ALGORITHM`` settings
|
||||
--------------------------------------
|
||||
|
||||
The new :setting:`DEFAULT_HASHING_ALGORITHM` transitional setting allows
|
||||
specifying the default hashing algorithm to use for encoding cookies, password
|
||||
reset tokens in the admin site, user sessions, and signatures created by
|
||||
The new ``DEFAULT_HASHING_ALGORITHM`` transitional setting allows specifying
|
||||
the default hashing algorithm to use for encoding cookies, password reset
|
||||
tokens in the admin site, user sessions, and signatures created by
|
||||
:class:`django.core.signing.Signer` and :meth:`django.core.signing.dumps`.
|
||||
|
||||
Support for SHA-256 was added in Django 3.1. If you are upgrading multiple
|
||||
instances of the same project to Django 3.1, you should set
|
||||
:setting:`DEFAULT_HASHING_ALGORITHM` to ``'sha1'`` during the transition, in
|
||||
order to allow compatibility with the older versions of Django. Note that this
|
||||
requires Django 3.1.1+. Once the transition to 3.1 is complete you can stop
|
||||
overriding :setting:`DEFAULT_HASHING_ALGORITHM`.
|
||||
``DEFAULT_HASHING_ALGORITHM`` to ``'sha1'`` during the transition, in order to
|
||||
allow compatibility with the older versions of Django. Note that this requires
|
||||
Django 3.1.1+. Once the transition to 3.1 is complete you can stop overriding
|
||||
``DEFAULT_HASHING_ALGORITHM``.
|
||||
|
||||
This setting is deprecated as of this release, because support for tokens,
|
||||
cookies, sessions, and signatures that use SHA-1 algorithm will be removed in
|
||||
|
|
|
@ -323,3 +323,5 @@ to remove usage of these features.
|
|||
* ``django.contrib.postgres.forms.JSONField`` is removed.
|
||||
|
||||
* The ``{% ifequal %}`` and ``{% ifnotequal %}`` template tags are removed.
|
||||
|
||||
* The ``DEFAULT_HASHING_ALGORITHM`` transitional setting is removed.
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
from django.contrib.auth import HASH_SESSION_KEY
|
||||
from django.contrib.auth.middleware import AuthenticationMiddleware
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test.utils import ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class TestAuthenticationMiddleware(TestCase):
|
||||
|
@ -24,12 +21,6 @@ class TestAuthenticationMiddleware(TestCase):
|
|||
self.assertIsNotNone(self.request.user)
|
||||
self.assertFalse(self.request.user.is_anonymous)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_session_default_hashing_algorithm(self):
|
||||
hash_session = self.client.session[HASH_SESSION_KEY]
|
||||
with override_settings(DEFAULT_HASHING_ALGORITHM='sha1'):
|
||||
self.assertNotEqual(hash_session, self.user.get_session_auth_hash())
|
||||
|
||||
def test_changed_password_invalidates_session(self):
|
||||
# After password change, user should be anonymous
|
||||
self.user.set_password('new_password')
|
||||
|
|
|
@ -4,8 +4,6 @@ from django.conf import settings
|
|||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||
from django.test import TestCase
|
||||
from django.test.utils import ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
|
||||
from .models import CustomEmailField
|
||||
|
||||
|
@ -113,12 +111,3 @@ class TokenGeneratorTest(TestCase):
|
|||
# Tokens created with a different secret don't validate.
|
||||
self.assertIs(p0.check_token(user, tk1), False)
|
||||
self.assertIs(p1.check_token(user, tk0), False)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_token_default_hashing_algorithm(self):
|
||||
user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw')
|
||||
with self.settings(DEFAULT_HASHING_ALGORITHM='sha1'):
|
||||
generator = PasswordResetTokenGenerator()
|
||||
self.assertEqual(generator.algorithm, 'sha1')
|
||||
token = generator.make_token(user)
|
||||
self.assertIs(generator.check_token(user, token), True)
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
import sys
|
||||
from types import ModuleType
|
||||
|
||||
from django.conf import (
|
||||
DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, Settings, settings,
|
||||
)
|
||||
from django.core.checks.security import base as security_base
|
||||
from django.test import TestCase, ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
|
||||
|
||||
class DefaultHashingAlgorithmDeprecationTests(TestCase):
|
||||
msg = DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG
|
||||
|
||||
def test_override_settings_warning(self):
|
||||
with self.assertRaisesMessage(RemovedInDjango40Warning, self.msg):
|
||||
with self.settings(DEFAULT_HASHING_ALGORITHM='sha1'):
|
||||
pass
|
||||
|
||||
def test_settings_init_warning(self):
|
||||
settings_module = ModuleType('fake_settings_module')
|
||||
settings_module.SECRET_KEY = 'foo'
|
||||
settings_module.DEFAULT_HASHING_ALGORITHM = 'sha1'
|
||||
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(self):
|
||||
# Warning is not raised on access.
|
||||
self.assertEqual(settings.DEFAULT_HASHING_ALGORITHM, 'sha256')
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_system_check_invalid_value(self):
|
||||
tests = [
|
||||
None,
|
||||
256,
|
||||
'invalid',
|
||||
'md5',
|
||||
'sha512',
|
||||
]
|
||||
for value in tests:
|
||||
with self.subTest(value=value), self.settings(DEFAULT_HASHING_ALGORITHM=value):
|
||||
self.assertEqual(
|
||||
security_base.check_default_hashing_algorithm(None),
|
||||
[security_base.E100],
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_system_check_valid_value(self):
|
||||
for value in ['sha1', 'sha256']:
|
||||
with self.subTest(value=value), self.settings(DEFAULT_HASHING_ALGORITHM=value):
|
||||
self.assertEqual(security_base.check_default_hashing_algorithm(None), [])
|
|
@ -9,9 +9,7 @@ from django.contrib.messages.storage.cookie import (
|
|||
)
|
||||
from django.core.signing import get_cookie_signer
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from django.test.utils import ignore_warnings
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
from django.utils.safestring import SafeData, mark_safe
|
||||
|
||||
from .base import BaseTests
|
||||
|
@ -193,14 +191,3 @@ class CookieTests(BaseTests, SimpleTestCase):
|
|||
encoded_messages = signer.sign(value)
|
||||
decoded_messages = storage._decode(encoded_messages)
|
||||
self.assertEqual(messages, decoded_messages)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_default_hashing_algorithm(self):
|
||||
messages = Message(constants.DEBUG, ['this', 'that'])
|
||||
with self.settings(DEFAULT_HASHING_ALGORITHM='sha1'):
|
||||
storage = self.get_storage()
|
||||
encoded = storage._encode(messages)
|
||||
decoded = storage._decode(encoded)
|
||||
self.assertEqual(decoded, messages)
|
||||
storage_default = self.get_storage()
|
||||
self.assertNotEqual(encoded, storage_default._encode(messages))
|
||||
|
|
|
@ -2,9 +2,8 @@ import datetime
|
|||
|
||||
from django.core import signing
|
||||
from django.test import SimpleTestCase
|
||||
from django.test.utils import freeze_time, ignore_warnings
|
||||
from django.test.utils import freeze_time
|
||||
from django.utils.crypto import InvalidAlgorithm
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
|
||||
|
||||
class TestSigner(SimpleTestCase):
|
||||
|
@ -53,14 +52,6 @@ class TestSigner(SimpleTestCase):
|
|||
'VzO9_jVu7R-VkqknHYNvw',
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_default_hashing_algorithm(self):
|
||||
signer = signing.Signer('predictable-secret', algorithm='sha1')
|
||||
signature_sha1 = signer.signature('hello')
|
||||
with self.settings(DEFAULT_HASHING_ALGORITHM='sha1'):
|
||||
signer = signing.Signer('predictable-secret')
|
||||
self.assertEqual(signer.signature('hello'), signature_sha1)
|
||||
|
||||
def test_invalid_algorithm(self):
|
||||
signer = signing.Signer('predictable-secret', algorithm='whatever')
|
||||
msg = "'whatever' is not an algorithm accepted by the hashlib module."
|
||||
|
@ -143,13 +134,6 @@ class TestSigner(SimpleTestCase):
|
|||
self.assertNotEqual(o, signing.dumps(o, compress=True))
|
||||
self.assertEqual(o, signing.loads(signing.dumps(o, compress=True)))
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango40Warning)
|
||||
def test_dumps_loads_default_hashing_algorithm_sha1(self):
|
||||
value = 'a string \u2020'
|
||||
with self.settings(DEFAULT_HASHING_ALGORITHM='sha1'):
|
||||
signed = signing.dumps(value)
|
||||
self.assertEqual(signing.loads(signed), value)
|
||||
|
||||
def test_decode_detects_tampering(self):
|
||||
"loads should raise exception for tampered objects"
|
||||
transforms = (
|
||||
|
|
Loading…
Reference in New Issue