This is another fork of http://djangosnippets.org/snippets/2729/ that fixes the issue.
Unlike those other versions i give you instructions so it works for you, this is modified a little.
Instructions:
If you want to import the passwords from drupal you need to prepend to each of them the word drupal so it looks like this:
drupal$S$DQjyXl0F7gupCqleCuraCkQJTzC3qAourXB7LvpOHKx0YAfihiPC
Then add this snippet to someapp/hashers/DrupalPasswordHasher.py
And then in your settings add this:
PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'someapp.hashers.DrupalPasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', 'django.contrib.auth.hashers.SHA1PasswordHasher', 'django.contrib.auth.hashers.MD5PasswordHasher', 'django.contrib.auth.hashers.CryptPasswordHasher', )
So, what did i modify
First i added the attribute algorithm to the class, django uses this word to identify wich hasher to use, so the passwords beggining with drupal should be verified with the hasher.algorithm == 'drupal'
Ok so know django knows to use our class, but now our passwords won't validate because we changed them by adding the word drupal, so what do we do? we modify the verify method to remove the word drupal before verification :P
Hope it helps
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import hashlib
from django.contrib.auth.hashers import BasePasswordHasher
class DrupalPasswordHasher(BasePasswordHasher):
"""
>>> h = DrupalPasswordHasher()
>>> h.verify("password1234", "$S$DeIZ1KTE.VzRvudZ5.xgOakipuMFrVyPmRdWTjAdYieWj27NMglI")
True
"""
DRUPAL_HASH_COUNT = 15
DRUPAL_MIN_HASH_COUNT = 7
DRUPAL_MAX_HASH_COUNT = 30
DRUPAL_HASH_LENGTH = 55
_ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
algorithm = 'drupal'
def verify(self, password, hashed_password):
hashed_password = hashed_password.replace('drupal','')
setting = hashed_password[0:12]
if setting[0] != '$' or setting[2] != '$':
return False
count_log2 = self._ITOA64.index(setting[3])
if count_log2 < self.DRUPAL_MIN_HASH_COUNT or count_log2 > self.DRUPAL_MAX_HASH_COUNT:
return False
salt = setting[4:4+8]
if len(salt) != 8:
return False
count = 2 ** count_log2
pass_hash = hashlib.sha512(salt + password).digest()
for _ in range(count):
pass_hash = hashlib.sha512(pass_hash + password).digest()
hash_length = len(pass_hash)
output = setting + self._password_base64_encode(pass_hash, hash_length)
if len(output) != 98:
return False
return output[:self.DRUPAL_HASH_LENGTH] == hashed_password
def safe_summary(self, encoded):
algorithm, iterations, salt = encoded.split('$', 3)
return SortedDict([
('algorithm', self.algorithm),
('iterations', iterations),
('salt', 'salt'),
('hash', 'hash'),
])
def _password_base64_encode(self, to_encode, count):
output = ''
i = 0
while True:
value = ord(to_encode[i])
i += 1
output = output + self._ITOA64[value & 0x3f]
if i < count:
value |= ord(to_encode[i]) << 8
output = output + self._ITOA64[(value >> 6) & 0x3f]
if i >= count:
break
i += 1
if i < count:
value |= ord(to_encode[i]) << 16
output = output + self._ITOA64[(value >> 12) & 0x3f]
if i >= count:
break
i += 1
output = output + self._ITOA64[(value >> 18) & 0x3f]
if i >= count:
break
return output
if __name__ == "__main__":
import doctest
doctest.testmod()
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Seems to have a (small) problem with (at least) Django-1.5 and python-2.7. The password is passed in to the verify() method as a unicode string and the call to hashlib.sha512 blows chunks at some point when iterating when it ends up with a non-ascii character in the hash. This can be fixed with the following extra bit of code at the top of the method:
#
Please login first before commenting.