Commit eb286aa2 authored by Claude Paroz's avatar Claude Paroz
Browse files

Delayed encoding of password and salt in password checking.

Applied the rule that string encoding should happen as late as
possible. This is also a preparation for Python 3 compatibility.
parent 9c096ab9
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
from django import forms
from django.forms.util import flatatt
from django.template import loader
from django.utils.encoding import smart_str
from django.utils.http import int_to_base36
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext, ugettext_lazy as _
@@ -26,8 +25,6 @@ class ReadOnlyPasswordHashWidget(forms.Widget):

        final_attrs = self.build_attrs(attrs)

        encoded = smart_str(encoded)

        if len(encoded) == 32 and '$' not in encoded:
            algorithm = 'unsalted_md5'
        else:
+4 −9
Original line number Diff line number Diff line
@@ -40,9 +40,6 @@ def check_password(password, encoded, setter=None, preferred='default'):
        return False

    preferred = get_hasher(preferred)
    raw_password = password
    password = smart_str(password)
    encoded = smart_str(encoded)

    if len(encoded) == 32 and '$' not in encoded:
        hasher = get_hasher('unsalted_md5')
@@ -53,7 +50,7 @@ def check_password(password, encoded, setter=None, preferred='default'):
    must_update = hasher.algorithm != preferred.algorithm
    is_correct = hasher.verify(password, encoded)
    if setter and is_correct and must_update:
        setter(raw_password)
        setter(password)
    return is_correct


@@ -69,11 +66,9 @@ def make_password(password, salt=None, hasher='default'):
        return UNUSABLE_PASSWORD

    hasher = get_hasher(hasher)
    password = smart_str(password)

    if not salt:
        salt = hasher.salt()
    salt = smart_str(salt)

    return hasher.encode(password, salt)

@@ -291,7 +286,7 @@ class SHA1PasswordHasher(BasePasswordHasher):
    def encode(self, password, salt):
        assert password
        assert salt and '$' not in salt
        hash = hashlib.sha1(salt + password).hexdigest()
        hash = hashlib.sha1(smart_str(salt + password)).hexdigest()
        return "%s$%s$%s" % (self.algorithm, salt, hash)

    def verify(self, password, encoded):
@@ -319,7 +314,7 @@ class MD5PasswordHasher(BasePasswordHasher):
    def encode(self, password, salt):
        assert password
        assert salt and '$' not in salt
        hash = hashlib.md5(salt + password).hexdigest()
        hash = hashlib.md5(smart_str(salt + password)).hexdigest()
        return "%s$%s$%s" % (self.algorithm, salt, hash)

    def verify(self, password, encoded):
@@ -353,7 +348,7 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
        return ''

    def encode(self, password, salt):
        return hashlib.md5(password).hexdigest()
        return hashlib.md5(smart_str(password)).hexdigest()

    def verify(self, password, encoded):
        encoded_2 = self.encode(password, '')
+3 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ except NotImplementedError:
    using_sysrandom = False

from django.conf import settings
from django.utils.encoding import smart_str


_trans_5c = b"".join([chr(x ^ 0x5C) for x in xrange(256)])
@@ -137,6 +138,8 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
    assert iterations > 0
    if not digest:
        digest = hashlib.sha256
    password = smart_str(password)
    salt = smart_str(salt)
    hlen = digest().digest_size
    if not dklen:
        dklen = hlen
+9 −0
Original line number Diff line number Diff line
@@ -128,6 +128,15 @@ If you were using the ``data`` parameter in a PUT request without a
``content_type``, you must encode your data before passing it to the test
client and set the ``content_type`` argument.

String types of hasher method parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you have written a :ref:`custom password hasher <auth_password_storage>`,
your ``encode()``, ``verify()`` or ``safe_summary()`` methods should accept
Unicode parameters (``password``, ``salt`` or ``encoded``). If any of the
hashing methods need byte strings, you can use the
:func:`~django.utils.encoding.smart_str` utility to encode the strings.

Features deprecated in 1.5
==========================