mirror of https://github.com/django/django.git
Fixed #29324 -- Made SECRET_KEY validation lazy (on first access).
This commit is contained in:
parent
9c9a3fe118
commit
948a874425
|
@ -81,6 +81,8 @@ class LazySettings(LazyObject):
|
||||||
# This is done here for performance reasons so the modified value is cached.
|
# This is done here for performance reasons so the modified value is cached.
|
||||||
if name in {'MEDIA_URL', 'STATIC_URL'} and val is not None:
|
if name in {'MEDIA_URL', 'STATIC_URL'} and val is not None:
|
||||||
val = self._add_script_prefix(val)
|
val = self._add_script_prefix(val)
|
||||||
|
elif name == 'SECRET_KEY' and not val:
|
||||||
|
raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
|
||||||
|
|
||||||
self.__dict__[name] = val
|
self.__dict__[name] = val
|
||||||
return val
|
return val
|
||||||
|
@ -184,9 +186,6 @@ class Settings:
|
||||||
setattr(self, setting, setting_value)
|
setattr(self, setting, setting_value)
|
||||||
self._explicit_settings.add(setting)
|
self._explicit_settings.add(setting)
|
||||||
|
|
||||||
if not self.SECRET_KEY:
|
|
||||||
raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
|
|
||||||
|
|
||||||
if self.is_overridden('PASSWORD_RESET_TIMEOUT_DAYS'):
|
if self.is_overridden('PASSWORD_RESET_TIMEOUT_DAYS'):
|
||||||
if self.is_overridden('PASSWORD_RESET_TIMEOUT'):
|
if self.is_overridden('PASSWORD_RESET_TIMEOUT'):
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
|
|
|
@ -12,7 +12,10 @@ class PasswordResetTokenGenerator:
|
||||||
"""
|
"""
|
||||||
key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
|
key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
|
||||||
algorithm = 'sha256'
|
algorithm = 'sha256'
|
||||||
secret = settings.SECRET_KEY
|
secret = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.secret = self.secret or settings.SECRET_KEY
|
||||||
|
|
||||||
def make_token(self, user):
|
def make_token(self, user):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
from .. import Error, Tags, Warning, register
|
from .. import Error, Tags, Warning, register
|
||||||
|
|
||||||
|
@ -182,11 +183,15 @@ def check_ssl_redirect(app_configs, **kwargs):
|
||||||
|
|
||||||
@register(Tags.security, deploy=True)
|
@register(Tags.security, deploy=True)
|
||||||
def check_secret_key(app_configs, **kwargs):
|
def check_secret_key(app_configs, **kwargs):
|
||||||
passed_check = (
|
try:
|
||||||
getattr(settings, 'SECRET_KEY', None) and
|
secret_key = settings.SECRET_KEY
|
||||||
len(set(settings.SECRET_KEY)) >= SECRET_KEY_MIN_UNIQUE_CHARACTERS and
|
except (ImproperlyConfigured, AttributeError):
|
||||||
len(settings.SECRET_KEY) >= SECRET_KEY_MIN_LENGTH
|
passed_check = False
|
||||||
)
|
else:
|
||||||
|
passed_check = (
|
||||||
|
len(set(secret_key)) >= SECRET_KEY_MIN_UNIQUE_CHARACTERS and
|
||||||
|
len(secret_key) >= SECRET_KEY_MIN_LENGTH
|
||||||
|
)
|
||||||
return [] if passed_check else [W009]
|
return [] if passed_check else [W009]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,13 @@ Requests and Responses
|
||||||
Security
|
Security
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* The :setting:`SECRET_KEY` setting is now checked for a valid value upon first
|
||||||
|
access, rather than when settings are first loaded. This enables running
|
||||||
|
management commands that do not rely on the ``SECRET_KEY`` without needing to
|
||||||
|
provide a value. As a consequence of this, calling
|
||||||
|
:func:`~django.conf.settings.configure` without providing a valid
|
||||||
|
``SECRET_KEY``, and then going on to access ``settings.SECRET_KEY`` will now
|
||||||
|
raise an :exc:`~django.core.exceptions.ImproperlyConfigured` exception.
|
||||||
|
|
||||||
Serialization
|
Serialization
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
|
@ -289,15 +289,11 @@ class SettingsTests(SimpleTestCase):
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
getattr(settings, 'TEST2')
|
getattr(settings, 'TEST2')
|
||||||
|
|
||||||
|
@override_settings(SECRET_KEY='')
|
||||||
def test_no_secret_key(self):
|
def test_no_secret_key(self):
|
||||||
settings_module = ModuleType('fake_settings_module')
|
|
||||||
sys.modules['fake_settings_module'] = settings_module
|
|
||||||
msg = 'The SECRET_KEY setting must not be empty.'
|
msg = 'The SECRET_KEY setting must not be empty.'
|
||||||
try:
|
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
||||||
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
settings.SECRET_KEY
|
||||||
Settings('fake_settings_module')
|
|
||||||
finally:
|
|
||||||
del sys.modules['fake_settings_module']
|
|
||||||
|
|
||||||
def test_no_settings_module(self):
|
def test_no_settings_module(self):
|
||||||
msg = (
|
msg = (
|
||||||
|
|
Loading…
Reference in New Issue