Fixed #14674 -- Prevent user accounts with an unusable password from resetting passwords. Thanks, summerisgone, thejaswi_puthraya and lrekucki.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16455 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
821d8aaaaa
commit
2619dc8285
|
@ -1,11 +1,14 @@
|
||||||
from django.contrib.auth.models import User
|
from django import forms
|
||||||
|
from django.template import Context, loader
|
||||||
|
from django.utils.http import int_to_base36
|
||||||
|
from django.utils.itercompat import any
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User, UNUSABLE_PASSWORD
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
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
|
||||||
from django.template import Context, loader
|
|
||||||
from django import forms
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.utils.http import int_to_base36
|
|
||||||
|
|
||||||
class UserCreationForm(forms.ModelForm):
|
class UserCreationForm(forms.ModelForm):
|
||||||
"""
|
"""
|
||||||
|
@ -114,10 +117,11 @@ class PasswordResetForm(forms.Form):
|
||||||
email = self.cleaned_data["email"]
|
email = self.cleaned_data["email"]
|
||||||
self.users_cache = User.objects.filter(
|
self.users_cache = User.objects.filter(
|
||||||
email__iexact=email,
|
email__iexact=email,
|
||||||
is_active=True
|
is_active=True)
|
||||||
)
|
if not len(self.users_cache):
|
||||||
if len(self.users_cache) == 0:
|
|
||||||
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
||||||
|
if any((user.password == UNUSABLE_PASSWORD) for user in self.users_cache):
|
||||||
|
raise forms.ValidationError(_("The user account associated with this e-mail address cannot reset the password."))
|
||||||
return email
|
return email
|
||||||
|
|
||||||
def save(self, domain_override=None,
|
def save(self, domain_override=None,
|
||||||
|
|
|
@ -4,7 +4,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2011-06-19 13:08+0200\n"
|
"POT-Creation-Date: 2011-06-25 20:39+0200\n"
|
||||||
"PO-Revision-Date: 2010-05-13 15:35+0200\n"
|
"PO-Revision-Date: 2010-05-13 15:35+0200\n"
|
||||||
"Last-Translator: Django team\n"
|
"Last-Translator: Django team\n"
|
||||||
"Language-Team: English <en@li.org>\n"
|
"Language-Team: English <en@li.org>\n"
|
||||||
|
@ -37,190 +37,196 @@ msgstr ""
|
||||||
msgid "Change password: %s"
|
msgid "Change password: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:14 forms.py:48 forms.py:66
|
#: forms.py:17 forms.py:51 forms.py:69
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:15 forms.py:49
|
#: forms.py:18 forms.py:52
|
||||||
msgid "Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."
|
msgid "Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:16 forms.py:50
|
#: forms.py:19 forms.py:53
|
||||||
msgid "This value may contain only letters, numbers and @/./+/-/_ characters."
|
msgid "This value may contain only letters, numbers and @/./+/-/_ characters."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:17 forms.py:67 forms.py:201
|
#: forms.py:20 forms.py:70 forms.py:205
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:18
|
#: forms.py:21
|
||||||
msgid "Password confirmation"
|
msgid "Password confirmation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:19
|
#: forms.py:22
|
||||||
msgid "Enter the same password as above, for verification."
|
msgid "Enter the same password as above, for verification."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:31
|
#: forms.py:34
|
||||||
msgid "A user with that username already exists."
|
msgid "A user with that username already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:37 forms.py:171 forms.py:213
|
#: forms.py:40 forms.py:175 forms.py:217
|
||||||
msgid "The two password fields didn't match."
|
msgid "The two password fields didn't match."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:87
|
#: forms.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please enter a correct username and password. Note that both fields are case-"
|
"Please enter a correct username and password. Note that both fields are case-"
|
||||||
"sensitive."
|
"sensitive."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:89
|
#: forms.py:92
|
||||||
msgid "This account is inactive."
|
msgid "This account is inactive."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:96
|
#: forms.py:99
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
|
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
|
||||||
"required for logging in."
|
"required for logging in."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:108
|
#: forms.py:111
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:120
|
#: forms.py:122
|
||||||
msgid ""
|
msgid ""
|
||||||
"That e-mail address doesn't have an associated user account. Are you sure "
|
"That e-mail address doesn't have an associated user account. Are you sure "
|
||||||
"you've registered?"
|
"you've registered?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:159
|
#: forms.py:124
|
||||||
|
msgid ""
|
||||||
|
"The user account associated with this e-mail address cannot reset the "
|
||||||
|
"password."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: forms.py:163
|
||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:160
|
#: forms.py:164
|
||||||
msgid "New password confirmation"
|
msgid "New password confirmation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:185
|
#: forms.py:189
|
||||||
msgid "Old password"
|
msgid "Old password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:193
|
#: forms.py:197
|
||||||
msgid "Your old password was entered incorrectly. Please enter it again."
|
msgid "Your old password was entered incorrectly. Please enter it again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:202
|
#: forms.py:206
|
||||||
msgid "Password (again)"
|
msgid "Password (again)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:77 models.py:105
|
#: models.py:94 models.py:122
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:79
|
#: models.py:96
|
||||||
msgid "codename"
|
msgid "codename"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:83
|
#: models.py:100
|
||||||
msgid "permission"
|
msgid "permission"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:84 models.py:106
|
#: models.py:101 models.py:123
|
||||||
msgid "permissions"
|
msgid "permissions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:109
|
#: models.py:126
|
||||||
msgid "group"
|
msgid "group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:110 models.py:217
|
#: models.py:127 models.py:236
|
||||||
msgid "groups"
|
msgid "groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:207
|
#: models.py:226
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:207
|
#: models.py:226
|
||||||
msgid ""
|
msgid ""
|
||||||
"Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"
|
"Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:208
|
#: models.py:227
|
||||||
msgid "first name"
|
msgid "first name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:209
|
#: models.py:228
|
||||||
msgid "last name"
|
msgid "last name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:210
|
#: models.py:229
|
||||||
msgid "e-mail address"
|
msgid "e-mail address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:211
|
#: models.py:230
|
||||||
msgid "password"
|
msgid "password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:211
|
#: models.py:230
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
|
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
|
||||||
"password form</a>."
|
"password form</a>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:212
|
#: models.py:231
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:212
|
#: models.py:231
|
||||||
msgid "Designates whether the user can log into this admin site."
|
msgid "Designates whether the user can log into this admin site."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:213
|
#: models.py:232
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:213
|
#: models.py:232
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates whether this user should be treated as active. Unselect this "
|
"Designates whether this user should be treated as active. Unselect this "
|
||||||
"instead of deleting accounts."
|
"instead of deleting accounts."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:214
|
#: models.py:233
|
||||||
msgid "superuser status"
|
msgid "superuser status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:214
|
#: models.py:233
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates that this user has all permissions without explicitly assigning "
|
"Designates that this user has all permissions without explicitly assigning "
|
||||||
"them."
|
"them."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:215
|
#: models.py:234
|
||||||
msgid "last login"
|
msgid "last login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:216
|
#: models.py:235
|
||||||
msgid "date joined"
|
msgid "date joined"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:218
|
#: models.py:237
|
||||||
msgid ""
|
msgid ""
|
||||||
"In addition to the permissions manually assigned, this user will also get "
|
"In addition to the permissions manually assigned, this user will also get "
|
||||||
"all permissions granted to each group he/she is in."
|
"all permissions granted to each group he/she is in."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:219
|
#: models.py:238
|
||||||
msgid "user permissions"
|
msgid "user permissions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:223
|
#: models.py:242
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:224
|
#: models.py:243
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -281,3 +281,16 @@ class PasswordResetFormTest(TestCase):
|
||||||
user.save()
|
user.save()
|
||||||
form = PasswordResetForm({'email': email})
|
form = PasswordResetForm({'email': email})
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
|
|
||||||
|
|
||||||
|
def test_unusable_password(self):
|
||||||
|
user = User.objects.create_user('testuser', 'test@example.com', 'test')
|
||||||
|
data = {"email": "test@example.com"}
|
||||||
|
form = PasswordResetForm(data)
|
||||||
|
self.assertTrue(form.is_valid())
|
||||||
|
user.set_unusable_password()
|
||||||
|
user.save()
|
||||||
|
form = PasswordResetForm(data)
|
||||||
|
self.assertFalse(form.is_valid())
|
||||||
|
self.assertEqual(form["email"].errors,
|
||||||
|
[u"The user account associated with this e-mail address cannot reset the password."])
|
||||||
|
|
|
@ -1011,6 +1011,12 @@ includes a few other useful built-in views located in
|
||||||
|
|
||||||
* ``form``: The form for resetting the user's password.
|
* ``form``: The form for resetting the user's password.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.4
|
||||||
|
Users flagged with an unusable password (see
|
||||||
|
:meth:`~django.contrib.auth.models.User.set_unusable_password()`
|
||||||
|
will not be able to request a password reset to prevent misuse
|
||||||
|
when using an external authentication source like LDAP.
|
||||||
|
|
||||||
.. function:: password_reset_done(request[, template_name])
|
.. function:: password_reset_done(request[, template_name])
|
||||||
|
|
||||||
The page shown after a user has been emailed a link to reset their
|
The page shown after a user has been emailed a link to reset their
|
||||||
|
|
Loading…
Reference in New Issue