Ticket #5600: django_rev_15346.patch

File django_rev_15346.patch, 5.4 KB (added by coh, 13 years ago)
  • docs/topics/auth.txt

     
    386386
    387387That's hashtype, salt and hash, separated by the dollar-sign character.
    388388
    389 Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm
    390 used to perform a one-way hash of the password. Salt is a random string used
    391 to salt the raw password to create the hash. Note that the ``crypt`` method is
    392 only supported on platforms that have the standard Python ``crypt`` module
    393 available.
     389Hashtype is either ``sha1`` (default), ``sha256``, ``sha512``, ``md5`` or
     390``crypt`` -- the algorithm used to perform a one-way hash of the password.
     391Salt is a random string used to salt the raw password to create the hash.
     392Note that the ``crypt`` method is only supported on platforms that have the
     393standard Python ``crypt`` module available. Also note that the ``sha256`` and
     394``sha512`` methods are only available under Python 2.5 or newer.
    394395
    395396For example::
    396397
  • docs/ref/settings.txt

     
    117117authenticate a user. See the :doc:`authentication backends documentation
    118118</ref/authbackends>` for details.
    119119
     120.. setting:: AUTH_HASH_ALGORITHM
     121
     122AUTH_HASH_ALGORITHM
     123-------------------
     124
     125Default: ``'sha1'``
     126
     127The hash algorithm that should be used by the authentication backend.
     128Available options are ``sha1``, ``sha256``, ``sha512``, ``md5`` and ``crypt``.
     129Please note that the two strongest ones, ``sha512`` and ``sha256``, are only
     130available when running Python >= 2.5, since it uses the then-introduced
     131``hashlib``.
     132
    120133.. setting:: AUTH_PROFILE_MODULE
    121134
    122135AUTH_PROFILE_MODULE
  • django/conf/global_settings.py

     
    477477
    478478AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
    479479
     480AUTH_HASH_ALGORITHM = 'sha1'
     481
    480482LOGIN_URL = '/accounts/login/'
    481483
    482484LOGOUT_URL = '/accounts/logout/'
  • django/contrib/auth/models.py

     
    11import datetime
    22import urllib
    33
     4from django.conf import settings
    45from django.contrib import auth
    56from django.contrib.auth.signals import user_logged_in
    67from django.core.exceptions import ImproperlyConfigured
     
    1415
    1516UNUSABLE_PASSWORD = '!' # This will never be a valid hash
    1617
     18# we're using 160 bits for the salt length, and then 'only' use a 128 bit
     19# chunk of that as the actual salt
     20SALT_LENGTH = 28 # ceil(160/7) + 5 as safety margin
     21SALT_HEX_LENGTH = 128 // 4
     22
     23
    1724def get_hexdigest(algorithm, salt, raw_password):
    1825    """
    1926    Returns a string of the hexdigest of the given plaintext password and salt
     
    3138        return md5_constructor(salt + raw_password).hexdigest()
    3239    elif algorithm == 'sha1':
    3340        return sha_constructor(salt + raw_password).hexdigest()
     41    elif algorithm in ('sha256', 'sha512'):
     42        try:
     43            import hashlib
     44        except ImportError:
     45            raise ValueError('"%s" password algorithm not supported in this environment' % algorithm)
     46        thehash = None
     47        if algorithm == 'sha256':
     48            thehash = hashlib.sha256
     49        else:
     50            thehash = hashlib.sha512
     51        return thehash(salt + raw_password).hexdigest()
     52
    3453    raise ValueError("Got unknown password algorithm type in password.")
    3554
    3655def check_password(raw_password, enc_password):
     
    147166        "Generates a random password with the given length and given allowed_chars"
    148167        # Note that default value of allowed_chars does not have "I" or letters
    149168        # that look like it -- just to avoid confusion.
    150         from random import choice
    151         return ''.join([choice(allowed_chars) for i in range(length)])
     169        from random import sample
     170        return ''.join(sample(allowed_chars, length))
    152171
    153172
    154173# A few helper functions for common logic between User and AnonymousUser.
     
    251270        if raw_password is None:
    252271            self.set_unusable_password()
    253272        else:
    254             import random
    255             algo = 'sha1'
    256             salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
     273            import os
     274            algo = settings.AUTH_HASH_ALGORITHM
     275            salt = None
     276            try:
     277                # try to get some really strong salt first
     278                salt = sha1_constructor(
     279                    os.urandom(SALT_LENGTH))[:SALT_HEX_LENGTH]
     280            except NotImplementedError:
     281                # if that fails, use some weaker stuff
     282                import random
     283                salt = ''
     284                salt_salt = ''
     285                for i in xrange(SALT_LENGTH):
     286                    salt += chr(random.randint(0, 255))
     287                    salt_salt += chr(random.randint(0, 255))
     288                # but let it work the extra mile
     289                salt = get_hexdigest(algo, salt_salt,
     290                    salt)[:SALT_HEX_LENGTH]
    257291            hsh = get_hexdigest(algo, salt, raw_password)
    258292            self.password = '%s$%s$%s' % (algo, salt, hsh)
    259293
Back to Top