Loading django/conf/global_settings.py +12 −0 Original line number Diff line number Diff line Loading @@ -498,6 +498,18 @@ LOGIN_REDIRECT_URL = '/accounts/profile/' # The number of days a password reset link is valid for PASSWORD_RESET_TIMEOUT_DAYS = 3 # the first hasher in this list is the preferred algorithm. any # password using different algorithms will be converted automatically # upon login PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.PBKDF2PasswordHasher', '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', ) ########### # SIGNING # ########### Loading django/contrib/auth/forms.py +20 −20 Original line number Diff line number Diff line from django import forms from django.forms.util import flatatt from django.template import loader from django.utils.encoding import smart_str from django.utils.http import int_to_base36 from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User from django.contrib.auth.utils import UNUSABLE_PASSWORD from django.contrib.auth import authenticate from django.contrib.auth.models import User from django.contrib.auth.hashers import UNUSABLE_PASSWORD, is_password_usable, get_hasher from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.models import get_current_site Loading @@ -18,27 +19,26 @@ mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p class ReadOnlyPasswordHashWidget(forms.Widget): def render(self, name, value, attrs): if not value: encoded = value if not is_password_usable(encoded): return "None" final_attrs = self.build_attrs(attrs) parts = value.split("$") if len(parts) != 3: # Legacy passwords didn't specify a hash type and were md5. hash_type = "md5" masked = mask_password(value) encoded = smart_str(encoded) if len(encoded) == 32 and '$' not in encoded: hasher = get_hasher('md5') else: hash_type = parts[0] masked = mask_password(parts[2]) return mark_safe("""<div%(attrs)s> <strong>%(hash_type_label)s</strong>: %(hash_type)s <strong>%(masked_label)s</strong>: %(masked)s </div>""" % { "attrs": flatatt(final_attrs), "hash_type_label": _("Hash type"), "hash_type": hash_type, "masked_label": _("Masked hash"), "masked": masked, }) algorithm = encoded.split('$', 1)[0] hasher = get_hasher(algorithm) summary = "" for key, value in hasher.safe_summary(encoded).iteritems(): summary += "<strong>%(key)s</strong>: %(value)s " % {"key": key, "value": value} return mark_safe("<div%(attrs)s>%(summary)s</div>" % {"attrs": flatatt(final_attrs), "summary": summary}) class ReadOnlyPasswordHashField(forms.Field): Loading django/contrib/auth/models.py +9 −16 Original line number Diff line number Diff line Loading @@ -9,11 +9,10 @@ from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from django.contrib import auth from django.contrib.auth.signals import user_logged_in # UNUSABLE_PASSWORD is still imported here for backwards compatibility from django.contrib.auth.utils import (get_hexdigest, make_password, check_password, is_password_usable, get_random_string, UNUSABLE_PASSWORD) from django.contrib.auth.hashers import ( check_password, make_password, is_password_usable, UNUSABLE_PASSWORD) from django.contrib.auth.signals import user_logged_in from django.contrib.contenttypes.models import ContentType def update_last_login(sender, user, **kwargs): Loading Loading @@ -220,27 +219,21 @@ class User(models.Model): return full_name.strip() def set_password(self, raw_password): self.password = make_password('sha1', raw_password) self.password = make_password(raw_password) def check_password(self, raw_password): """ Returns a boolean of whether the raw_password was correct. Handles hashing formats behind the scenes. """ # Backwards-compatibility check. Older passwords won't include the # algorithm or salt. if '$' not in self.password: is_correct = (self.password == get_hexdigest('md5', '', raw_password)) if is_correct: # Convert the password to the new, more secure format. def setter(raw_password): self.set_password(raw_password) self.save() return is_correct return check_password(raw_password, self.password) return check_password(raw_password, self.password, setter) def set_unusable_password(self): # Sets a value that will never be a valid hash self.password = make_password('sha1', None) self.password = make_password(None) def has_usable_password(self): return is_password_usable(self.password) Loading django/contrib/auth/tests/__init__.py +5 −3 Original line number Diff line number Diff line from django.contrib.auth.tests.auth_backends import (BackendTest, RowlevelBackendTest, AnonymousUserBackendTest, NoBackendsTest, InActiveUserBackendTest, NoInActiveUserBackendTest) from django.contrib.auth.tests.basic import BasicTestCase, PasswordUtilsTestCase from django.contrib.auth.tests.basic import BasicTestCase from django.contrib.auth.tests.context_processors import AuthContextProcessorTests from django.contrib.auth.tests.decorators import LoginRequiredTestCase from django.contrib.auth.tests.forms import (UserCreationFormTest, Loading @@ -11,9 +11,11 @@ from django.contrib.auth.tests.remote_user import (RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest) from django.contrib.auth.tests.management import GetDefaultUsernameTestCase from django.contrib.auth.tests.models import ProfileTestCase from django.contrib.auth.tests.hashers import TestUtilsHashPass from django.contrib.auth.tests.signals import SignalTestCase from django.contrib.auth.tests.tokens import TokenGeneratorTest from django.contrib.auth.tests.views import (AuthViewNamedURLTests, PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest, LoginURLSettings) from django.contrib.auth.tests.views import (AuthViewNamedURLTests, PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest, LoginURLSettings) # The password for the fixture data users is 'password' django/contrib/auth/tests/basic.py +0 −28 Original line number Diff line number Diff line from django.test import TestCase from django.utils.unittest import skipUnless from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth import utils from django.core.management import call_command from StringIO import StringIO Loading Loading @@ -111,30 +110,3 @@ class BasicTestCase(TestCase): u = User.objects.get(username="joe+admin@somewhere.org") self.assertEqual(u.email, 'joe@somewhere.org') self.assertFalse(u.has_usable_password()) class PasswordUtilsTestCase(TestCase): def _test_make_password(self, algo): password = utils.make_password(algo, "foobar") self.assertTrue(utils.is_password_usable(password)) self.assertTrue(utils.check_password("foobar", password)) def test_make_unusable(self): "Check that you can create an unusable password." password = utils.make_password("any", None) self.assertFalse(utils.is_password_usable(password)) self.assertFalse(utils.check_password("foobar", password)) def test_make_password_sha1(self): "Check creating passwords with SHA1 algorithm." self._test_make_password("sha1") def test_make_password_md5(self): "Check creating passwords with MD5 algorithm." self._test_make_password("md5") @skipUnless(crypt_module, "no crypt module to generate password.") def test_make_password_crypt(self): "Check creating passwords with CRYPT algorithm." self._test_make_password("crypt") Loading
django/conf/global_settings.py +12 −0 Original line number Diff line number Diff line Loading @@ -498,6 +498,18 @@ LOGIN_REDIRECT_URL = '/accounts/profile/' # The number of days a password reset link is valid for PASSWORD_RESET_TIMEOUT_DAYS = 3 # the first hasher in this list is the preferred algorithm. any # password using different algorithms will be converted automatically # upon login PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.PBKDF2PasswordHasher', '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', ) ########### # SIGNING # ########### Loading
django/contrib/auth/forms.py +20 −20 Original line number Diff line number Diff line from django import forms from django.forms.util import flatatt from django.template import loader from django.utils.encoding import smart_str from django.utils.http import int_to_base36 from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User from django.contrib.auth.utils import UNUSABLE_PASSWORD from django.contrib.auth import authenticate from django.contrib.auth.models import User from django.contrib.auth.hashers import UNUSABLE_PASSWORD, is_password_usable, get_hasher from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.models import get_current_site Loading @@ -18,27 +19,26 @@ mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p class ReadOnlyPasswordHashWidget(forms.Widget): def render(self, name, value, attrs): if not value: encoded = value if not is_password_usable(encoded): return "None" final_attrs = self.build_attrs(attrs) parts = value.split("$") if len(parts) != 3: # Legacy passwords didn't specify a hash type and were md5. hash_type = "md5" masked = mask_password(value) encoded = smart_str(encoded) if len(encoded) == 32 and '$' not in encoded: hasher = get_hasher('md5') else: hash_type = parts[0] masked = mask_password(parts[2]) return mark_safe("""<div%(attrs)s> <strong>%(hash_type_label)s</strong>: %(hash_type)s <strong>%(masked_label)s</strong>: %(masked)s </div>""" % { "attrs": flatatt(final_attrs), "hash_type_label": _("Hash type"), "hash_type": hash_type, "masked_label": _("Masked hash"), "masked": masked, }) algorithm = encoded.split('$', 1)[0] hasher = get_hasher(algorithm) summary = "" for key, value in hasher.safe_summary(encoded).iteritems(): summary += "<strong>%(key)s</strong>: %(value)s " % {"key": key, "value": value} return mark_safe("<div%(attrs)s>%(summary)s</div>" % {"attrs": flatatt(final_attrs), "summary": summary}) class ReadOnlyPasswordHashField(forms.Field): Loading
django/contrib/auth/models.py +9 −16 Original line number Diff line number Diff line Loading @@ -9,11 +9,10 @@ from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from django.contrib import auth from django.contrib.auth.signals import user_logged_in # UNUSABLE_PASSWORD is still imported here for backwards compatibility from django.contrib.auth.utils import (get_hexdigest, make_password, check_password, is_password_usable, get_random_string, UNUSABLE_PASSWORD) from django.contrib.auth.hashers import ( check_password, make_password, is_password_usable, UNUSABLE_PASSWORD) from django.contrib.auth.signals import user_logged_in from django.contrib.contenttypes.models import ContentType def update_last_login(sender, user, **kwargs): Loading Loading @@ -220,27 +219,21 @@ class User(models.Model): return full_name.strip() def set_password(self, raw_password): self.password = make_password('sha1', raw_password) self.password = make_password(raw_password) def check_password(self, raw_password): """ Returns a boolean of whether the raw_password was correct. Handles hashing formats behind the scenes. """ # Backwards-compatibility check. Older passwords won't include the # algorithm or salt. if '$' not in self.password: is_correct = (self.password == get_hexdigest('md5', '', raw_password)) if is_correct: # Convert the password to the new, more secure format. def setter(raw_password): self.set_password(raw_password) self.save() return is_correct return check_password(raw_password, self.password) return check_password(raw_password, self.password, setter) def set_unusable_password(self): # Sets a value that will never be a valid hash self.password = make_password('sha1', None) self.password = make_password(None) def has_usable_password(self): return is_password_usable(self.password) Loading
django/contrib/auth/tests/__init__.py +5 −3 Original line number Diff line number Diff line from django.contrib.auth.tests.auth_backends import (BackendTest, RowlevelBackendTest, AnonymousUserBackendTest, NoBackendsTest, InActiveUserBackendTest, NoInActiveUserBackendTest) from django.contrib.auth.tests.basic import BasicTestCase, PasswordUtilsTestCase from django.contrib.auth.tests.basic import BasicTestCase from django.contrib.auth.tests.context_processors import AuthContextProcessorTests from django.contrib.auth.tests.decorators import LoginRequiredTestCase from django.contrib.auth.tests.forms import (UserCreationFormTest, Loading @@ -11,9 +11,11 @@ from django.contrib.auth.tests.remote_user import (RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest) from django.contrib.auth.tests.management import GetDefaultUsernameTestCase from django.contrib.auth.tests.models import ProfileTestCase from django.contrib.auth.tests.hashers import TestUtilsHashPass from django.contrib.auth.tests.signals import SignalTestCase from django.contrib.auth.tests.tokens import TokenGeneratorTest from django.contrib.auth.tests.views import (AuthViewNamedURLTests, PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest, LoginURLSettings) from django.contrib.auth.tests.views import (AuthViewNamedURLTests, PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest, LoginURLSettings) # The password for the fixture data users is 'password'
django/contrib/auth/tests/basic.py +0 −28 Original line number Diff line number Diff line from django.test import TestCase from django.utils.unittest import skipUnless from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth import utils from django.core.management import call_command from StringIO import StringIO Loading Loading @@ -111,30 +110,3 @@ class BasicTestCase(TestCase): u = User.objects.get(username="joe+admin@somewhere.org") self.assertEqual(u.email, 'joe@somewhere.org') self.assertFalse(u.has_usable_password()) class PasswordUtilsTestCase(TestCase): def _test_make_password(self, algo): password = utils.make_password(algo, "foobar") self.assertTrue(utils.is_password_usable(password)) self.assertTrue(utils.check_password("foobar", password)) def test_make_unusable(self): "Check that you can create an unusable password." password = utils.make_password("any", None) self.assertFalse(utils.is_password_usable(password)) self.assertFalse(utils.check_password("foobar", password)) def test_make_password_sha1(self): "Check creating passwords with SHA1 algorithm." self._test_make_password("sha1") def test_make_password_md5(self): "Check creating passwords with MD5 algorithm." self._test_make_password("md5") @skipUnless(crypt_module, "no crypt module to generate password.") def test_make_password_crypt(self): "Check creating passwords with CRYPT algorithm." self._test_make_password("crypt")