On Jan 21, 2015, at 3:07 PM, Supermario <human...@gmail.com> wrote:
I’ve enclosed a password processor I used in the past for a Drupal conversion; the gist came from a web search and is attributed in the code but has some minor fixes. I’ve actually included two processors, with one disabled with “XXX� in the function name. I think I had trouble getting that one to work. You can create a “drupal� app, which just has an __init__.py and this file as hashers.py You will want to add “drupal� as one of your apps, then also define the following in your settings.py: PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'drupal.hashers.DrupalPasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ) Since you are starting fresh, you can include only the recommended best password hasher from Django plus the drupal hasher. And if you prefer you could fold the hashers.py file into another existing app in your project. Also, the structure of your project may be a bit different from mine since the recommended Django layout has changed a bit over the last few versions. hth, and enjoy getting the heck away from Drupal hell… - Tom You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com. To post to this group, send email to django-users@googlegroups.com. Visit this group at http://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/B276D536-93E4-4A28-AB5B-9E184685B675%40gmail.com. For more options, visit https://groups.google.com/d/optout. |
import hashlib from django.contrib.auth.hashers import BasePasswordHasher from collections import OrderedDict
class DrupalPasswordHasherXXX(BasePasswordHasher): """ From dgrtwo at http://djangosnippets.org/snippets/2729 As it stands, this looks for a password which starts with "S" so needs the leading "$" present in the drupal hashed value removed. This also fails in the user admin panel; perhaps due to a missing safe_summary method. """ algorithm = "S" iter_code = 'C' salt_length = 8 _ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' def encode(self, password, salt, iter_code=None): """The Drupal 7 method of encoding passwords""" if iter_code is None: iterations = 2 ** self._ITOA64.index(self.iter_code) else: iterations = 2 ** self._ITOA64.index(iter_code) hash = hashlib.sha512(salt + password).digest() for i in range(iterations): hash = hashlib.sha512(hash + password).digest() pass l = len(hash) output = '' i = 0 while i < l: value = ord(hash[i]) i = i + 1 output += self._ITOA64[value & 0x3f] if i < l: value |= ord(hash[i]) << 8 output += self._ITOA64[(value >> 6) & 0x3f] if i >= l: break i += 1 if i < l: value |= ord(hash[i]) << 16 pass output += self._ITOA64[(value >> 12) & 0x3f] if i >= l: break i += 1 output += self._ITOA64[(value >> 18) & 0x3f] pass longhashed = "%s$%s%s%s" % (self.algorithm, iter_code, salt, output) return longhashed[:54] def verify(self, password, encoded): hash = encoded.split("$")[1] iter_code = hash[0] salt = hash[1:1 + self.salt_length] return encoded == self.encode(password, salt, iter_code) class DrupalPasswordHasher(BasePasswordHasher): """ From grillermo at http://djangosnippets.org/snippets/2924/ Modified from DrupalPasswordHasher to fix "the issue" whatever that is. To verify functionality: >>> 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): # django-1.5 passes in password in unicode which causes trouble in hashlib.sha512() if (isinstance(password, unicode)): password = password.encode('ascii') pass # slight modification from the original snippet for cleanliness # hashed_password = hashed_password.replace("drupal", "") if (hashed_password.startswith("drupal")): hashed_password = hashed_password[6:] pass 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() pass 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 OrderedDict([ ('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
-- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com. To post to this group, send email to django-users@googlegroups.com. Visit this group at http://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/B276D536-93E4-4A28-AB5B-9E184685B675%40gmail.com. For more options, visit https://groups.google.com/d/optout. |