On Jan 21, 2015, at 3:07 PM, Supermario <human...@gmail.com> wrote:

I am trying to move Druap 7 site to django 1.7 without invalidating user passwords, and this proved to be daunting.

Fortunately, I have found this SO question and this hashing snippet but there is no documentation and as a newbie to django, I have no clue how to integrate the snippet into my project.


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.

Reply via email to