Skip to content

Commit

Permalink
Fixed #18182 -- Made is_usable_password check if hashing algorithm is…
Browse files Browse the repository at this point in the history
… correct

The display of the ReadOnlyPasswordHashWidget has also been improved to
distinguish empty/unusable password from erroneous password.
Fixed #18453 also.
Thanks danielr and Leo for the reports and Moritz Sichert for the
initial patch.
  • Loading branch information
claudep committed Sep 12, 2012
1 parent 859aa2a commit 703c266
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 21 deletions.
28 changes: 14 additions & 14 deletions django/contrib/auth/forms.py
Expand Up @@ -11,7 +11,7 @@


from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.hashers import UNUSABLE_PASSWORD, is_password_usable, identify_hasher from django.contrib.auth.hashers import UNUSABLE_PASSWORD, identify_hasher
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.models import get_current_site from django.contrib.sites.models import get_current_site


Expand All @@ -24,22 +24,22 @@
class ReadOnlyPasswordHashWidget(forms.Widget): class ReadOnlyPasswordHashWidget(forms.Widget):
def render(self, name, value, attrs): def render(self, name, value, attrs):
encoded = value encoded = value

if not is_password_usable(encoded):
return "None"

final_attrs = self.build_attrs(attrs) final_attrs = self.build_attrs(attrs)


try: if encoded == '' or encoded == UNUSABLE_PASSWORD:
hasher = identify_hasher(encoded) summary = mark_safe("<strong>%s</strong>" % ugettext("No password set."))
except ValueError:
summary = mark_safe("<strong>Invalid password format or unknown hashing algorithm.</strong>")
else: else:
summary = format_html_join('', try:
"<strong>{0}</strong>: {1} ", hasher = identify_hasher(encoded)
((ugettext(key), value) except ValueError:
for key, value in hasher.safe_summary(encoded).items()) summary = mark_safe("<strong>%s</strong>" % ugettext(
) "Invalid password format or unknown hashing algorithm."))
else:
summary = format_html_join('',
"<strong>{0}</strong>: {1} ",
((ugettext(key), value)
for key, value in hasher.safe_summary(encoded).items())
)


return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary) return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)


Expand Down
8 changes: 7 additions & 1 deletion django/contrib/auth/hashers.py
Expand Up @@ -28,7 +28,13 @@ def reset_hashers(**kwargs):




def is_password_usable(encoded): def is_password_usable(encoded):
return (encoded is not None and encoded != UNUSABLE_PASSWORD) if encoded is None or encoded == UNUSABLE_PASSWORD:
return False
try:
hasher = identify_hasher(encoded)
except ValueError:
return False
return True




def check_password(password, encoded, setter=None, preferred='default'): def check_password(password, encoded, setter=None, preferred='default'):
Expand Down
19 changes: 13 additions & 6 deletions django/contrib/auth/tests/forms.py
Expand Up @@ -236,23 +236,30 @@ class Meta(UserChangeForm.Meta):
# Just check we can create it # Just check we can create it
form = MyUserForm({}) form = MyUserForm({})


def test_unsuable_password(self):
user = User.objects.get(username='empty_password')
user.set_unusable_password()
user.save()
form = UserChangeForm(instance=user)
self.assertIn(_("No password set."), form.as_table())

def test_bug_17944_empty_password(self): def test_bug_17944_empty_password(self):
user = User.objects.get(username='empty_password') user = User.objects.get(username='empty_password')
form = UserChangeForm(instance=user) form = UserChangeForm(instance=user)
# Just check that no error is raised. self.assertIn(_("Invalid password format or unknown hashing algorithm."),
form.as_table() form.as_table())


def test_bug_17944_unmanageable_password(self): def test_bug_17944_unmanageable_password(self):
user = User.objects.get(username='unmanageable_password') user = User.objects.get(username='unmanageable_password')
form = UserChangeForm(instance=user) form = UserChangeForm(instance=user)
# Just check that no error is raised. self.assertIn(_("Invalid password format or unknown hashing algorithm."),
form.as_table() form.as_table())


def test_bug_17944_unknown_password_algorithm(self): def test_bug_17944_unknown_password_algorithm(self):
user = User.objects.get(username='unknown_password') user = User.objects.get(username='unknown_password')
form = UserChangeForm(instance=user) form = UserChangeForm(instance=user)
# Just check that no error is raised. self.assertIn(_("Invalid password format or unknown hashing algorithm."),
form.as_table() form.as_table())




@override_settings(USE_TZ=False, PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) @override_settings(USE_TZ=False, PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
Expand Down
4 changes: 4 additions & 0 deletions django/contrib/auth/tests/hashers.py
Expand Up @@ -100,6 +100,10 @@ def doit():
self.assertRaises(ValueError, doit) self.assertRaises(ValueError, doit)
self.assertRaises(ValueError, identify_hasher, "lolcat$salt$hash") self.assertRaises(ValueError, identify_hasher, "lolcat$salt$hash")


def test_bad_encoded(self):
self.assertFalse(is_password_usable('letmein_badencoded'))
self.assertFalse(is_password_usable(''))

def test_low_level_pkbdf2(self): def test_low_level_pkbdf2(self):
hasher = PBKDF2PasswordHasher() hasher = PBKDF2PasswordHasher()
encoded = hasher.encode('letmein', 'seasalt') encoded = hasher.encode('letmein', 'seasalt')
Expand Down

0 comments on commit 703c266

Please sign in to comment.