Code

Ticket #20593: empty-password-fix.patch

File empty-password-fix.patch, 6.4 KB (added by jonaskoelker, 10 months ago)

Proper fix, plus test cases

  • django/contrib/auth/hashers.py

    diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
    index 6abdb5f..a3e1511 100644
    a b def check_password(password, encoded, setter=None, preferred='default'): 
    4747    If setter is specified, it'll be called when you need to 
    4848    regenerate the password. 
    4949    """ 
    50     if not password or not is_password_usable(encoded): 
     50    if not is_password_usable(encoded): 
    5151        return False 
    5252 
    5353    preferred = get_hasher(preferred) 
    def make_password(password, salt=None, hasher='default'): 
    6868    password is None or blank then UNUSABLE_PASSWORD will be 
    6969    returned which disallows logins. 
    7070    """ 
    71     if not password: 
     71    if password is None: 
    7272        return UNUSABLE_PASSWORD 
    7373 
    7474    hasher = get_hasher(hasher) 
    class PBKDF2PasswordHasher(BasePasswordHasher): 
    222222    digest = hashlib.sha256 
    223223 
    224224    def encode(self, password, salt, iterations=None): 
    225         assert password 
    226225        assert salt and '$' not in salt 
    227226        if not iterations: 
    228227            iterations = self.iterations 
    class SHA1PasswordHasher(BasePasswordHasher): 
    350349    algorithm = "sha1" 
    351350 
    352351    def encode(self, password, salt): 
    353         assert password 
    354352        assert salt and '$' not in salt 
    355353        hash = hashlib.sha1(force_bytes(salt + password)).hexdigest() 
    356354        return "%s$%s$%s" % (self.algorithm, salt, hash) 
    class MD5PasswordHasher(BasePasswordHasher): 
    378376    algorithm = "md5" 
    379377 
    380378    def encode(self, password, salt): 
    381         assert password 
    382379        assert salt and '$' not in salt 
    383380        hash = hashlib.md5(force_bytes(salt + password)).hexdigest() 
    384381        return "%s$%s$%s" % (self.algorithm, salt, hash) 
  • django/contrib/auth/tests/test_hashers.py

    diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py
    index d49fdc4..88c8f40 100644
    a b class TestUtilsHashPass(unittest.TestCase): 
    4141        self.assertFalse(check_password('lètmeinz', encoded)) 
    4242        self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256") 
    4343 
     44        encoded = make_password('', 'sodium chloride', 'pbkdf2_sha256') 
     45        self.assertTrue(is_password_usable(encoded)) 
     46        self.assertTrue(check_password('', encoded)) 
     47 
    4448    def test_sha1(self): 
    4549        encoded = make_password('lètmein', 'seasalt', 'sha1') 
    4650        self.assertEqual(encoded, 
    class TestUtilsHashPass(unittest.TestCase): 
    5054        self.assertFalse(check_password('lètmeinz', encoded)) 
    5155        self.assertEqual(identify_hasher(encoded).algorithm, "sha1") 
    5256 
     57        encoded = make_password('', 'sodium chloride', 'sha1') 
     58        self.assertTrue(is_password_usable(encoded)) 
     59        self.assertTrue(check_password('', encoded)) 
     60 
    5361    def test_md5(self): 
    5462        encoded = make_password('lètmein', 'seasalt', 'md5') 
    5563        self.assertEqual(encoded, 
    class TestUtilsHashPass(unittest.TestCase): 
    5967        self.assertFalse(check_password('lètmeinz', encoded)) 
    6068        self.assertEqual(identify_hasher(encoded).algorithm, "md5") 
    6169 
     70        encoded = make_password('', 'sodium chloride', 'md5') 
     71        self.assertTrue(is_password_usable(encoded)) 
     72        self.assertTrue(check_password('', encoded)) 
     73 
    6274    def test_unsalted_md5(self): 
    6375        encoded = make_password('lètmein', '', 'unsalted_md5') 
    6476        self.assertEqual(encoded, '88a434c88cca4e900f7874cd98123f43') 
    class TestUtilsHashPass(unittest.TestCase): 
    7284        self.assertTrue(check_password('lètmein', alt_encoded)) 
    7385        self.assertFalse(check_password('lètmeinz', alt_encoded)) 
    7486 
     87        encoded = make_password('', '', 'unsalted_md5') 
     88        self.assertTrue(is_password_usable(encoded)) 
     89        self.assertTrue(check_password('', encoded)) 
     90 
    7591    def test_unsalted_sha1(self): 
    7692        encoded = make_password('lètmein', '', 'unsalted_sha1') 
    7793        self.assertEqual(encoded, 'sha1$$6d138ca3ae545631b3abd71a4f076ce759c5700b') 
    class TestUtilsHashPass(unittest.TestCase): 
    8399        alt_encoded = encoded[6:] 
    84100        self.assertFalse(check_password('lètmein', alt_encoded)) 
    85101 
     102        encoded = make_password('', '', 'unsalted_sha1') 
     103        self.assertTrue(is_password_usable(encoded)) 
     104        self.assertTrue(check_password('', encoded)) 
     105 
    86106    @skipUnless(crypt, "no crypt module to generate password.") 
    87107    def test_crypt(self): 
    88108        encoded = make_password('lètmei', 'ab', 'crypt') 
    class TestUtilsHashPass(unittest.TestCase): 
    92112        self.assertFalse(check_password('lètmeiz', encoded)) 
    93113        self.assertEqual(identify_hasher(encoded).algorithm, "crypt") 
    94114 
     115        encoded = make_password('', 'ab', 'crypt') 
     116        self.assertTrue(is_password_usable(encoded)) 
     117        self.assertTrue(check_password('', encoded)) 
     118 
    95119    @skipUnless(bcrypt, "bcrypt not installed") 
    96120    def test_bcrypt_sha256(self): 
    97121        encoded = make_password('lètmein', hasher='bcrypt_sha256') 
    class TestUtilsHashPass(unittest.TestCase): 
    108132        self.assertTrue(check_password(password, encoded)) 
    109133        self.assertFalse(check_password(password[:72], encoded)) 
    110134 
     135        encoded = make_password('', 'bcrypt_sha256') 
     136        self.assertTrue(is_password_usable(encoded)) 
     137        self.assertTrue(check_password('', encoded)) 
     138 
    111139    @skipUnless(bcrypt, "bcrypt not installed") 
    112140    def test_bcrypt(self): 
    113141        encoded = make_password('lètmein', hasher='bcrypt') 
    class TestUtilsHashPass(unittest.TestCase): 
    117145        self.assertFalse(check_password('lètmeinz', encoded)) 
    118146        self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt") 
    119147 
     148        encoded = make_password('', 'bcrypt') 
     149        self.assertTrue(is_password_usable(encoded)) 
     150        self.assertTrue(check_password('', encoded)) 
     151 
    120152    def test_unusable(self): 
    121153        encoded = make_password(None) 
    122154        self.assertFalse(is_password_usable(encoded)) 
    class TestUtilsHashPass(unittest.TestCase): 
    151183            'pbkdf2_sha1$10000$seasalt$oAfF6vgs95ncksAhGXOWf4Okq7o=') 
    152184        self.assertTrue(hasher.verify('lètmein', encoded)) 
    153185 
     186        encoded = hasher.encode('', 'sodium chloride') 
     187        self.assertTrue(hasher.verify('', encoded)) 
     188 
    154189    def test_upgrade(self): 
    155190        self.assertEqual('pbkdf2_sha256', get_hasher('default').algorithm) 
    156191        for algo in ('sha1', 'md5'):