0
votes

ive got an user table from an old php application where users have unsalted md5 hashes as password and because im migrating the app to django, im trying to put all users in auth_user table.

referring to this post, it is possible to store passwords as md5 hashes without salt. but that doesnt work for me? (python/2.7.6,django/1.6.1)

like e.g. for an user having password "changeme" i assume it should be in the format md5$$4cb9c8a8048fd02294477fcb1a41191a or am i missing something?

EDIT: in settings.py ive got:

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
)

im using login_required decorator in views.py if somehow related:

@login_required
def index(request):
    logger.debug('index accessed from %s by %s' % (request.META.get('REMOTE_ADDR'), request.user.username) )
    member = members.objects.get(nickname=request.user.username)
    context = {'request': request, 'member': member}
    return render(request, 'voip/index.html', context)

and following urls.py:

url(r'^login/$', 'django.contrib.auth.views.login', {
  'template_name': 'voip/login.html'
}),
url(r'^logout/$', 'django.contrib.auth.views.logout_then_login', {
  #'template_name': 'voip/logout.html'
}),

this works as long as in settings.py AUTHENTICATION_BACKENDS looks like this:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'django_auth_ldap.backend.LDAPBackend',
)

as soon as i comment out django_auth_ldap its not working. but if i then copy the pbkdf2 hash from initially installed superuser (ive set pw changeme for debugging) to my own user in auth_user table, i may log in with password "changeme"...

3

3 Answers

2
votes

From what I can see in Django 1.6.1 source code you cannot use MD5PasswordHasher with an empty salt: https://github.com/django/django/blob/1.6.1/django/contrib/auth/hashers.py#L397.

But there is UnsaltedMD5PasswordHasher which might work for you.

EDIT: The answer you mentioned was written 4 years ago when Django 1.2 ruled the market. I've checked its password hashing code and it didn't have any assertions there, that's why MD5 hasher worked with empty salts back then.

1
votes

I have two suggestions for your problem.

First, please check PASSWORD_HASHERS in settings.py. Django is able to upgrade passwords from older algorithms, but only if they are available in your configuration. Read more at the django docs.

At least you need the MD5PasswordHasher activated:

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
)

Second, if you've done that already you may try to simply store the old MD5 passwords without leading md5$$. That's also supported as a fallback. Django will recognize a 32 digit hexadecimal number as MD5 hash. This is the relevant code block from the django source code:

# Ancient versions of Django created plain MD5 passwords and accepted
# MD5 passwords with an empty salt.
if ((len(encoded) == 32 and '$' not in encoded) or
        (len(encoded) == 37 and encoded.startswith('md5$$'))):
    algorithm = 'unsalted_md5'

Hope this helps!

-1
votes

You can customize the authentication process, or even write your custom authentication backend. This topic is covered in official documentation:

https://docs.djangoproject.com/en/1.6/topics/auth/customizing/