diff --git a/django/contrib/auth/tokens.py b/django/contrib/auth/tokens.py index c83bcd7ca5..eefa00c330 100644 --- a/django/contrib/auth/tokens.py +++ b/django/contrib/auth/tokens.py @@ -11,6 +11,7 @@ class PasswordResetTokenGenerator: reset mechanism. """ key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator" + secret = settings.SECRET_KEY def make_token(self, user): """ @@ -61,6 +62,7 @@ class PasswordResetTokenGenerator: hash = salted_hmac( self.key_salt, self._make_hash_value(user, timestamp), + secret=self.secret, ).hexdigest()[::2] return "%s-%s" % (ts_b36, hash) diff --git a/tests/auth_tests/test_tokens.py b/tests/auth_tests/test_tokens.py index 0662ec513e..eb06e00425 100644 --- a/tests/auth_tests/test_tokens.py +++ b/tests/auth_tests/test_tokens.py @@ -55,3 +55,24 @@ class TokenGeneratorTest(TestCase): tk1 = p0.make_token(user) self.assertIs(p0.check_token(None, tk1), False) self.assertIs(p0.check_token(user, None), False) + + def test_token_with_different_secret(self): + """ + A valid token can be created with a secret other than SECRET_KEY by + using the PasswordResetTokenGenerator.secret attribute. + """ + user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') + new_secret = 'abcdefghijkl' + # Create and check a token with a different secret. + p0 = PasswordResetTokenGenerator() + p0.secret = new_secret + tk0 = p0.make_token(user) + self.assertTrue(p0.check_token(user, tk0)) + # Create and check a token with the default secret. + p1 = PasswordResetTokenGenerator() + self.assertEqual(p1.secret, settings.SECRET_KEY) + self.assertNotEqual(p1.secret, new_secret) + tk1 = p1.make_token(user) + # Tokens created with a different secret don't validate. + self.assertFalse(p0.check_token(user, tk1)) + self.assertFalse(p1.check_token(user, tk0))