From 718a5ba1a1a77374c26b134ded46dab13776d1a1 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 9 Dec 2011 22:10:03 +0000 Subject: [PATCH] Fixed #16845 -- Admin 'Change user' page no longer shows the password hash. Thanks, dstufft git-svn-id: http://code.djangoproject.com/svn/django/trunk@17185 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/auth/forms.py | 40 +++++++++++++++++++++++++++++++++++ django/contrib/auth/models.py | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index b97c5d7054..6fcf323216 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -1,6 +1,8 @@ from django import forms +from django.forms.util import flatatt from django.template import loader 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 @@ -9,6 +11,40 @@ from django.contrib.auth import authenticate from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.models import get_current_site +UNMASKED_DIGITS_TO_SHOW = 6 + +mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0)) + +class ReadOnlyPasswordHashWidget(forms.Widget): + def render(self, name, value, attrs): + if not value: + 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) + else: + hash_type = parts[0] + masked = mask_password(parts[2]) + return mark_safe(""" + %(hash_type_label)s: %(hash_type)s + %(masked_label)s: %(masked)s + """ % { + "attrs": flatatt(final_attrs), + "hash_type_label": _("Hash type"), + "hash_type": hash_type, + "masked_label": _("Masked hash"), + "masked": masked, + }) + +class ReadOnlyPasswordHashField(forms.Field): + widget = ReadOnlyPasswordHashWidget + + def __init__(self, *args, **kwargs): + kwargs.setdefault("required", False) + super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs) class UserCreationForm(forms.ModelForm): """ @@ -51,6 +87,10 @@ class UserChangeForm(forms.ModelForm): username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$', help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."), error_messages = {'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")}) + password = ReadOnlyPasswordHashField(label=_("Password"), help_text=_("We don't store raw passwords, so there's no way to see this user's password, but you can change the password using this form.")) + + def clean_password(self): + return self.initial["password"] class Meta: model = User diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index c82ba12b8a..8ac94c1e8a 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -177,7 +177,7 @@ class User(models.Model): first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) email = models.EmailField(_('e-mail address'), blank=True) - password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the change password form.")) + password = models.CharField(_('password'), max_length=128) is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site.")) is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts.")) is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))