1
0
mirror of https://github.com/django/django.git synced 2025-10-27 07:36:08 +00:00

Fixed #30360 -- Added support for secret key rotation.

Thanks Florian Apolloner for the implementation idea.

Co-authored-by: Andreas Pelme <andreas@pelme.se>
Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
Co-authored-by: Vuyisile Ndlovu <terrameijar@gmail.com>
This commit is contained in:
tschilling
2021-12-13 21:47:03 -06:00
committed by Mariusz Felisiak
parent ba4a6880d1
commit 0dcd549bbe
18 changed files with 364 additions and 56 deletions

View File

@@ -13,6 +13,7 @@ class PasswordResetTokenGenerator:
key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
algorithm = None
_secret = None
_secret_fallbacks = None
def __init__(self):
self.algorithm = self.algorithm or 'sha256'
@@ -25,12 +26,26 @@ class PasswordResetTokenGenerator:
secret = property(_get_secret, _set_secret)
def _get_fallbacks(self):
if self._secret_fallbacks is None:
return settings.SECRET_KEY_FALLBACKS
return self._secret_fallbacks
def _set_fallbacks(self, fallbacks):
self._secret_fallbacks = fallbacks
secret_fallbacks = property(_get_fallbacks, _set_fallbacks)
def make_token(self, user):
"""
Return a token that can be used once to do a password reset
for the given user.
"""
return self._make_token_with_timestamp(user, self._num_seconds(self._now()))
return self._make_token_with_timestamp(
user,
self._num_seconds(self._now()),
self.secret,
)
def check_token(self, user, token):
"""
@@ -50,7 +65,13 @@ class PasswordResetTokenGenerator:
return False
# Check that the timestamp/uid has not been tampered with
if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
for secret in [self.secret, *self.secret_fallbacks]:
if constant_time_compare(
self._make_token_with_timestamp(user, ts, secret),
token,
):
break
else:
return False
# Check the timestamp is within limit.
@@ -59,14 +80,14 @@ class PasswordResetTokenGenerator:
return True
def _make_token_with_timestamp(self, user, timestamp):
def _make_token_with_timestamp(self, user, timestamp, secret):
# timestamp is number of seconds since 2001-1-1. Converted to base 36,
# this gives us a 6 digit string until about 2069.
ts_b36 = int_to_base36(timestamp)
hash_string = salted_hmac(
self.key_salt,
self._make_hash_value(user, timestamp),
secret=self.secret,
secret=secret,
algorithm=self.algorithm,
).hexdigest()[::2] # Limit to shorten the URL.
return "%s-%s" % (ts_b36, hash_string)