Fixed #18182 -- Made is_usable_password check if hashing algorithm is 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.
This commit is contained in:
parent
859aa2a6c4
commit
703c266682
|
@ -11,7 +11,7 @@ from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -24,22 +24,22 @@ mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -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'):
|
||||||
|
|
|
@ -236,23 +236,30 @@ class UserChangeFormTest(TestCase):
|
||||||
# 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',))
|
||||||
|
|
|
@ -100,6 +100,10 @@ class TestUtilsHashPass(unittest.TestCase):
|
||||||
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')
|
||||||
|
|
Loading…
Reference in New Issue