From 8aa71f4e8706b6b3e4e60aaffb29d004e1378ae3 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Thu, 26 Mar 2020 13:23:32 +0100 Subject: [PATCH] Fixed #31375 -- Made contrib.auth.hashers.make_password() accept only bytes or strings. --- django/contrib/auth/hashers.py | 5 +++++ docs/releases/3.1.txt | 4 ++++ docs/topics/auth/passwords.txt | 16 ++++++++++------ tests/auth_tests/test_hashers.py | 5 +++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index c8cf0d3bf8..66fb94e7af 100644 --- a/django/contrib/auth/hashers.py +++ b/django/contrib/auth/hashers.py @@ -72,6 +72,11 @@ def make_password(password, salt=None, hasher='default'): """ if password is None: return UNUSABLE_PASSWORD_PREFIX + get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH) + if not isinstance(password, (bytes, str)): + raise TypeError( + 'Password must be a string or bytes, got %s.' + % type(password).__qualname__ + ) hasher = get_hasher(hasher) salt = salt or hasher.salt() return hasher.encode(password, salt) diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index e4992b0a4a..492622d3bd 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -603,6 +603,10 @@ Miscellaneous * The admin CSS classes ``row1`` and ``row2`` are removed in favor of ``:nth-child(odd)`` and ``:nth-child(even)`` pseudo-classes. +* The :func:`~django.contrib.auth.hashers.make_password` now requires its + argument to be a string or bytes. Other types should be explicitly cast to + one of these. + .. _deprecated-features-3.1: Features deprecated in 3.1 diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt index 134ef14583..cc8ca55501 100644 --- a/docs/topics/auth/passwords.txt +++ b/docs/topics/auth/passwords.txt @@ -402,12 +402,16 @@ from the ``User`` model. .. function:: make_password(password, salt=None, hasher='default') Creates a hashed password in the format used by this application. It takes - one mandatory argument: the password in plain-text. Optionally, you can - provide a salt and a hashing algorithm to use, if you don't want to use the - defaults (first entry of ``PASSWORD_HASHERS`` setting). See - :ref:`auth-included-hashers` for the algorithm name of each hasher. If the - password argument is ``None``, an unusable password is returned (one that - will never be accepted by :func:`check_password`). + one mandatory argument: the password in plain-text (string or bytes). + Optionally, you can provide a salt and a hashing algorithm to use, if you + don't want to use the defaults (first entry of ``PASSWORD_HASHERS`` + setting). See :ref:`auth-included-hashers` for the algorithm name of each + hasher. If the password argument is ``None``, an unusable password is + returned (one that will never be accepted by :func:`check_password`). + + .. versionchanged:: 3.1 + + The ``password`` parameter must be a string or bytes if not ``None``. .. function:: is_password_usable(encoded_password) diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py index 7435569a7c..05be565fed 100644 --- a/tests/auth_tests/test_hashers.py +++ b/tests/auth_tests/test_hashers.py @@ -56,6 +56,11 @@ class TestUtilsHashPass(SimpleTestCase): self.assertIs(is_password_usable(encoded), True) self.assertIs(check_password(b'bytes_password', encoded), True) + def test_invalid_password(self): + msg = 'Password must be a string or bytes, got int.' + with self.assertRaisesMessage(TypeError, msg): + make_password(1) + def test_pbkdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') self.assertEqual(encoded, 'pbkdf2_sha256$216000$seasalt$youGZxOw6ZOcfrXv2i8/AhrnpZflJJ9EshS9XmUJTUg=')