Fixed #17194 -- Made sure the auth form tests work if a language other than English is activated by moving the error message translation strings into class level dictionaries. Many thanks to Claude Paroz, rabio and Bas Peschier for their initial work on this.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17204 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-12-15 16:12:46 +00:00
parent e7b5e22484
commit 5df31c0164
3 changed files with 122 additions and 82 deletions

View File

@ -15,6 +15,7 @@ UNMASKED_DIGITS_TO_SHOW = 6
mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0)) mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0))
class ReadOnlyPasswordHashWidget(forms.Widget): class ReadOnlyPasswordHashWidget(forms.Widget):
def render(self, name, value, attrs): def render(self, name, value, attrs):
if not value: if not value:
@ -39,6 +40,7 @@ class ReadOnlyPasswordHashWidget(forms.Widget):
"masked": masked, "masked": masked,
}) })
class ReadOnlyPasswordHashField(forms.Field): class ReadOnlyPasswordHashField(forms.Field):
widget = ReadOnlyPasswordHashWidget widget = ReadOnlyPasswordHashWidget
@ -46,10 +48,15 @@ class ReadOnlyPasswordHashField(forms.Field):
kwargs.setdefault("required", False) kwargs.setdefault("required", False)
super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs) super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs)
class UserCreationForm(forms.ModelForm): class UserCreationForm(forms.ModelForm):
""" """
A form that creates a user, with no privileges, from the given username and password. A form that creates a user, with no privileges, from the given username and password.
""" """
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$', username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$',
help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."), help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
error_messages = {'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")}) error_messages = {'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")})
@ -67,13 +74,13 @@ class UserCreationForm(forms.ModelForm):
User.objects.get(username=username) User.objects.get(username=username)
except User.DoesNotExist: except User.DoesNotExist:
return username return username
raise forms.ValidationError(_("A user with that username already exists.")) raise forms.ValidationError(self.error_messages['duplicate_username'])
def clean_password2(self): def clean_password2(self):
password1 = self.cleaned_data.get("password1", "") password1 = self.cleaned_data.get("password1", "")
password2 = self.cleaned_data["password2"] password2 = self.cleaned_data["password2"]
if password1 != password2: if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match.")) raise forms.ValidationError(self.error_messages['password_mismatch'])
return password2 return password2
def save(self, commit=True): def save(self, commit=True):
@ -83,6 +90,7 @@ class UserCreationForm(forms.ModelForm):
user.save() user.save()
return user return user
class UserChangeForm(forms.ModelForm): class UserChangeForm(forms.ModelForm):
username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$', username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$',
help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."), help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
@ -101,6 +109,7 @@ class UserChangeForm(forms.ModelForm):
if f is not None: if f is not None:
f.queryset = f.queryset.select_related('content_type') f.queryset = f.queryset.select_related('content_type')
class AuthenticationForm(forms.Form): class AuthenticationForm(forms.Form):
""" """
Base class for authenticating users. Extend this to get a form that accepts Base class for authenticating users. Extend this to get a form that accepts
@ -109,6 +118,14 @@ class AuthenticationForm(forms.Form):
username = forms.CharField(label=_("Username"), max_length=30) username = forms.CharField(label=_("Username"), max_length=30)
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
error_messages = {
'invalid_login': _("Please enter a correct username and password. "
"Note that both fields are case-sensitive."),
'no_cookies': _("Your Web browser doesn't appear to have cookies "
"enabled. Cookies are required for logging in."),
'inactive': _("This account is inactive."),
}
def __init__(self, request=None, *args, **kwargs): def __init__(self, request=None, *args, **kwargs):
""" """
If request is passed in, the form will validate that cookies are If request is passed in, the form will validate that cookies are
@ -127,17 +144,15 @@ class AuthenticationForm(forms.Form):
if username and password: if username and password:
self.user_cache = authenticate(username=username, password=password) self.user_cache = authenticate(username=username, password=password)
if self.user_cache is None: if self.user_cache is None:
raise forms.ValidationError(_("Please enter a correct username and password. Note that both fields are case-sensitive.")) raise forms.ValidationError(self.error_messages['invalid_login'])
elif not self.user_cache.is_active: elif not self.user_cache.is_active:
raise forms.ValidationError(_("This account is inactive.")) raise forms.ValidationError(self.error_messages['inactive'])
self.check_for_test_cookie() self.check_for_test_cookie()
return self.cleaned_data return self.cleaned_data
def check_for_test_cookie(self): def check_for_test_cookie(self):
if self.request and not self.request.session.test_cookie_worked(): if self.request and not self.request.session.test_cookie_worked():
raise forms.ValidationError( raise forms.ValidationError(self.error_messages['no_cookies'])
_("Your Web browser doesn't appear to have cookies enabled. "
"Cookies are required for logging in."))
def get_user_id(self): def get_user_id(self):
if self.user_cache: if self.user_cache:
@ -147,7 +162,14 @@ class AuthenticationForm(forms.Form):
def get_user(self): def get_user(self):
return self.user_cache return self.user_cache
class PasswordResetForm(forms.Form): class PasswordResetForm(forms.Form):
error_messages = {
'unknown': _("That e-mail address doesn't have an associated "
"user account. Are you sure you've registered?"),
'unusable': _("The user account associated with this e-mail "
"address cannot reset the password."),
}
email = forms.EmailField(label=_("E-mail"), max_length=75) email = forms.EmailField(label=_("E-mail"), max_length=75)
def clean_email(self): def clean_email(self):
@ -159,9 +181,9 @@ class PasswordResetForm(forms.Form):
email__iexact=email, email__iexact=email,
is_active=True) is_active=True)
if not len(self.users_cache): if not len(self.users_cache):
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?")) raise forms.ValidationError(self.error_messages['unknown'])
if any((user.password == UNUSABLE_PASSWORD) for user in self.users_cache): 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.")) raise forms.ValidationError(self.error_messages['unusable'])
return email return email
def save(self, domain_override=None, def save(self, domain_override=None,
@ -195,11 +217,15 @@ class PasswordResetForm(forms.Form):
email = loader.render_to_string(email_template_name, c) email = loader.render_to_string(email_template_name, c)
send_mail(subject, email, from_email, [user.email]) send_mail(subject, email, from_email, [user.email])
class SetPasswordForm(forms.Form): class SetPasswordForm(forms.Form):
""" """
A form that lets a user change set his/her password without A form that lets a user change set his/her password without
entering the old password entering the old password
""" """
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
new_password1 = forms.CharField(label=_("New password"), widget=forms.PasswordInput) new_password1 = forms.CharField(label=_("New password"), widget=forms.PasswordInput)
new_password2 = forms.CharField(label=_("New password confirmation"), widget=forms.PasswordInput) new_password2 = forms.CharField(label=_("New password confirmation"), widget=forms.PasswordInput)
@ -212,7 +238,7 @@ class SetPasswordForm(forms.Form):
password2 = self.cleaned_data.get('new_password2') password2 = self.cleaned_data.get('new_password2')
if password1 and password2: if password1 and password2:
if password1 != password2: if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match.")) raise forms.ValidationError(self.error_messages['password_mismatch'])
return password2 return password2
def save(self, commit=True): def save(self, commit=True):
@ -221,11 +247,15 @@ class SetPasswordForm(forms.Form):
self.user.save() self.user.save()
return self.user return self.user
class PasswordChangeForm(SetPasswordForm): class PasswordChangeForm(SetPasswordForm):
""" """
A form that lets a user change his/her password by entering A form that lets a user change his/her password by entering
their old password. their old password.
""" """
error_messages = dict(SetPasswordForm.error_messages, **{
'password_incorrect': _("Your old password was entered incorrectly. Please enter it again."),
})
old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput) old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput)
def clean_old_password(self): def clean_old_password(self):
@ -234,14 +264,18 @@ class PasswordChangeForm(SetPasswordForm):
""" """
old_password = self.cleaned_data["old_password"] old_password = self.cleaned_data["old_password"]
if not self.user.check_password(old_password): if not self.user.check_password(old_password):
raise forms.ValidationError(_("Your old password was entered incorrectly. Please enter it again.")) raise forms.ValidationError(self.error_messages['password_incorrect'])
return old_password return old_password
PasswordChangeForm.base_fields.keyOrder = ['old_password', 'new_password1', 'new_password2'] PasswordChangeForm.base_fields.keyOrder = ['old_password', 'new_password1', 'new_password2']
class AdminPasswordChangeForm(forms.Form): class AdminPasswordChangeForm(forms.Form):
""" """
A form used to change the password of a user in the admin interface. A form used to change the password of a user in the admin interface.
""" """
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput) password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)
@ -254,7 +288,7 @@ class AdminPasswordChangeForm(forms.Form):
password2 = self.cleaned_data.get('password2') password2 = self.cleaned_data.get('password2')
if password1 and password2: if password1 and password2:
if password1 != password2: if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match.")) raise forms.ValidationError(self.error_messages['password_mismatch'])
return password2 return password2
def save(self, commit=True): def save(self, commit=True):

View File

@ -1,9 +1,12 @@
from __future__ import with_statement from __future__ import with_statement
import os import os
from django.core import mail from django.core import mail
from django.forms.fields import Field, EmailField
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm
from django.test import TestCase from django.test import TestCase
from django.utils.encoding import force_unicode
from django.utils import translation
class UserCreationFormTest(TestCase): class UserCreationFormTest(TestCase):
@ -19,7 +22,7 @@ class UserCreationFormTest(TestCase):
form = UserCreationForm(data) form = UserCreationForm(data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form["username"].errors, self.assertEqual(form["username"].errors,
[u'A user with that username already exists.']) [force_unicode(form.error_messages['duplicate_username'])])
def test_invalid_data(self): def test_invalid_data(self):
data = { data = {
@ -30,8 +33,7 @@ class UserCreationFormTest(TestCase):
form = UserCreationForm(data) form = UserCreationForm(data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form["username"].errors, self.assertEqual(form["username"].errors,
[u'This value may contain only letters, numbers and @/./+/-/_ characters.']) [force_unicode(form.fields['username'].error_messages['invalid'])])
def test_password_verification(self): def test_password_verification(self):
# The verification password is incorrect. # The verification password is incorrect.
@ -43,25 +45,21 @@ class UserCreationFormTest(TestCase):
form = UserCreationForm(data) form = UserCreationForm(data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form["password2"].errors, self.assertEqual(form["password2"].errors,
[u"The two password fields didn't match."]) [force_unicode(form.error_messages['password_mismatch'])])
def test_both_passwords(self): def test_both_passwords(self):
# One (or both) passwords weren't given # One (or both) passwords weren't given
data = {'username': 'jsmith'} data = {'username': 'jsmith'}
form = UserCreationForm(data) form = UserCreationForm(data)
required_error = [force_unicode(Field.default_error_messages['required'])]
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form['password1'].errors, self.assertEqual(form['password1'].errors, required_error)
[u'This field is required.']) self.assertEqual(form['password2'].errors, required_error)
self.assertEqual(form['password2'].errors,
[u'This field is required.'])
data['password2'] = 'test123' data['password2'] = 'test123'
form = UserCreationForm(data) form = UserCreationForm(data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form['password1'].errors, self.assertEqual(form['password1'].errors, required_error)
[u'This field is required.'])
def test_success(self): def test_success(self):
# The success case. # The success case.
@ -91,7 +89,7 @@ class AuthenticationFormTest(TestCase):
form = AuthenticationForm(None, data) form = AuthenticationForm(None, data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form.non_field_errors(), self.assertEqual(form.non_field_errors(),
[u'Please enter a correct username and password. Note that both fields are case-sensitive.']) [force_unicode(form.error_messages['invalid_login'])])
def test_inactive_user(self): def test_inactive_user(self):
# The user is inactive. # The user is inactive.
@ -102,8 +100,20 @@ class AuthenticationFormTest(TestCase):
form = AuthenticationForm(None, data) form = AuthenticationForm(None, data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form.non_field_errors(), self.assertEqual(form.non_field_errors(),
[u'This account is inactive.']) [force_unicode(form.error_messages['inactive'])])
def test_inactive_user_i18n(self):
with self.settings(USE_I18N=True):
with translation.override('pt-br', deactivate=True):
# The user is inactive.
data = {
'username': 'inactive',
'password': 'password',
}
form = AuthenticationForm(None, data)
self.assertFalse(form.is_valid())
self.assertEqual(form.non_field_errors(),
[force_unicode(form.error_messages['inactive'])])
def test_success(self): def test_success(self):
# The success case # The success case
@ -130,7 +140,7 @@ class SetPasswordFormTest(TestCase):
form = SetPasswordForm(user, data) form = SetPasswordForm(user, data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form["new_password2"].errors, self.assertEqual(form["new_password2"].errors,
[u"The two password fields didn't match."]) [force_unicode(form.error_messages['password_mismatch'])])
def test_success(self): def test_success(self):
user = User.objects.get(username='testclient') user = User.objects.get(username='testclient')
@ -156,8 +166,7 @@ class PasswordChangeFormTest(TestCase):
form = PasswordChangeForm(user, data) form = PasswordChangeForm(user, data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form["old_password"].errors, self.assertEqual(form["old_password"].errors,
[u'Your old password was entered incorrectly. Please enter it again.']) [force_unicode(form.error_messages['password_incorrect'])])
def test_password_verification(self): def test_password_verification(self):
# The two new passwords do not match. # The two new passwords do not match.
@ -170,8 +179,7 @@ class PasswordChangeFormTest(TestCase):
form = PasswordChangeForm(user, data) form = PasswordChangeForm(user, data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form["new_password2"].errors, self.assertEqual(form["new_password2"].errors,
[u"The two password fields didn't match."]) [force_unicode(form.error_messages['password_mismatch'])])
def test_success(self): def test_success(self):
# The success case. # The success case.
@ -190,6 +198,7 @@ class PasswordChangeFormTest(TestCase):
self.assertEqual(PasswordChangeForm(user, {}).fields.keys(), self.assertEqual(PasswordChangeForm(user, {}).fields.keys(),
['old_password', 'new_password1', 'new_password2']) ['old_password', 'new_password1', 'new_password2'])
class UserChangeFormTest(TestCase): class UserChangeFormTest(TestCase):
fixtures = ['authtestdata.json'] fixtures = ['authtestdata.json']
@ -200,7 +209,7 @@ class UserChangeFormTest(TestCase):
form = UserChangeForm(data, instance=user) form = UserChangeForm(data, instance=user)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form['username'].errors, self.assertEqual(form['username'].errors,
[u'This value may contain only letters, numbers and @/./+/-/_ characters.']) [force_unicode(form.fields['username'].error_messages['invalid'])])
def test_bug_14242(self): def test_bug_14242(self):
# A regression test, introduce by adding an optimization for the # A regression test, introduce by adding an optimization for the
@ -232,19 +241,19 @@ class PasswordResetFormTest(TestCase):
return (user, username, email) return (user, username, email)
def test_invalid_email(self): def test_invalid_email(self):
data = {'email':'not valid'} data = {'email': 'not valid'}
form = PasswordResetForm(data) form = PasswordResetForm(data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form['email'].errors, self.assertEqual(form['email'].errors,
[u'Enter a valid e-mail address.']) [force_unicode(EmailField.default_error_messages['invalid'])])
def test_nonexistant_email(self): def test_nonexistant_email(self):
# Test nonexistant email address # Test nonexistant email address
data = {'email':'foo@bar.com'} data = {'email': 'foo@bar.com'}
form = PasswordResetForm(data) form = PasswordResetForm(data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form.errors, self.assertEqual(form.errors,
{'email': [u"That e-mail address doesn't have an associated user account. Are you sure you've registered?"]}) {'email': [force_unicode(form.error_messages['unknown'])]})
def test_cleaned_data(self): def test_cleaned_data(self):
# Regression test # Regression test
@ -284,7 +293,6 @@ class PasswordResetFormTest(TestCase):
form = PasswordResetForm({'email': email}) form = PasswordResetForm({'email': email})
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
def test_unusable_password(self): def test_unusable_password(self):
user = User.objects.create_user('testuser', 'test@example.com', 'test') user = User.objects.create_user('testuser', 'test@example.com', 'test')
data = {"email": "test@example.com"} data = {"email": "test@example.com"}

View File

@ -4,15 +4,18 @@ import re
import urllib import urllib
from django.conf import settings from django.conf import settings
from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.sites.models import Site, RequestSite from django.contrib.sites.models import Site, RequestSite
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import NoReverseMatch
from django.test import TestCase
from django.core import mail from django.core import mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse, NoReverseMatch
from django.http import QueryDict from django.http import QueryDict
from django.utils.encoding import force_unicode
from django.utils.html import escape
from django.test import TestCase
from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm,
SetPasswordForm, PasswordResetForm)
class AuthViewsTestCase(TestCase): class AuthViewsTestCase(TestCase):
@ -40,13 +43,15 @@ class AuthViewsTestCase(TestCase):
def login(self, password='password'): def login(self, password='password'):
response = self.client.post('/login/', { response = self.client.post('/login/', {
'username': 'testclient', 'username': 'testclient',
'password': password 'password': password,
} })
)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) self.assertTrue(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
self.assertTrue(SESSION_KEY in self.client.session) self.assertTrue(SESSION_KEY in self.client.session)
def assertContainsEscaped(self, response, text, **kwargs):
return self.assertContains(response, escape(force_unicode(text)), **kwargs)
class AuthViewNamedURLTests(AuthViewsTestCase): class AuthViewNamedURLTests(AuthViewsTestCase):
urls = 'django.contrib.auth.urls' urls = 'django.contrib.auth.urls'
@ -80,7 +85,7 @@ class PasswordResetTest(AuthViewsTestCase):
response = self.client.get('/password_reset/') response = self.client.get('/password_reset/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'}) response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
self.assertContains(response, "That e-mail address doesn't have an associated user account") self.assertContainsEscaped(response, PasswordResetForm.error_messages['unknown'])
self.assertEqual(len(mail.outbox), 0) self.assertEqual(len(mail.outbox), 0)
def test_email_found(self): def test_email_found(self):
@ -121,7 +126,7 @@ class PasswordResetTest(AuthViewsTestCase):
url, path = self._test_confirm_start() url, path = self._test_confirm_start()
# Let's munge the token in the path, but keep the same length, # Let's munge the token in the path, but keep the same length,
# in case the URLconf will reject a different length. # in case the URLconf will reject a different length.
path = path[:-5] + ("0"*4) + path[-1] path = path[:-5] + ("0" * 4) + path[-1]
response = self.client.get(path) response = self.client.get(path)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@ -143,10 +148,12 @@ class PasswordResetTest(AuthViewsTestCase):
# Same as test_confirm_invalid, but trying # Same as test_confirm_invalid, but trying
# to do a POST instead. # to do a POST instead.
url, path = self._test_confirm_start() url, path = self._test_confirm_start()
path = path[:-5] + ("0"*4) + path[-1] path = path[:-5] + ("0" * 4) + path[-1]
response = self.client.post(path, {'new_password1': 'anewpassword', self.client.post(path, {
'new_password2':' anewpassword'}) 'new_password1': 'anewpassword',
'new_password2': ' anewpassword',
})
# Check the password has not been changed # Check the password has not been changed
u = User.objects.get(email='staffmember@example.com') u = User.objects.get(email='staffmember@example.com')
self.assertTrue(not u.check_password("anewpassword")) self.assertTrue(not u.check_password("anewpassword"))
@ -169,20 +176,20 @@ class PasswordResetTest(AuthViewsTestCase):
def test_confirm_different_passwords(self): def test_confirm_different_passwords(self):
url, path = self._test_confirm_start() url, path = self._test_confirm_start()
response = self.client.post(path, {'new_password1': 'anewpassword', response = self.client.post(path, {'new_password1': 'anewpassword',
'new_password2':' x'}) 'new_password2': 'x'})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue("The two password fields didn't match" in response.content) self.assertContainsEscaped(response, SetPasswordForm.error_messages['password_mismatch'])
class ChangePasswordTest(AuthViewsTestCase): class ChangePasswordTest(AuthViewsTestCase):
def fail_login(self, password='password'): def fail_login(self, password='password'):
response = self.client.post('/login/', { response = self.client.post('/login/', {
'username': 'testclient', 'username': 'testclient',
'password': password 'password': password,
} })
)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue("Please enter a correct username and password. Note that both fields are case-sensitive." in response.content) self.assertContainsEscaped(response, AuthenticationForm.error_messages['invalid_login'])
def logout(self): def logout(self):
response = self.client.get('/logout/') response = self.client.get('/logout/')
@ -193,10 +200,9 @@ class ChangePasswordTest(AuthViewsTestCase):
'old_password': 'donuts', 'old_password': 'donuts',
'new_password1': 'password1', 'new_password1': 'password1',
'new_password2': 'password1', 'new_password2': 'password1',
} })
)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue("Your old password was entered incorrectly. Please enter it again." in response.content) self.assertContainsEscaped(response, PasswordChangeForm.error_messages['password_incorrect'])
def test_password_change_fails_with_mismatched_passwords(self): def test_password_change_fails_with_mismatched_passwords(self):
self.login() self.login()
@ -204,10 +210,9 @@ class ChangePasswordTest(AuthViewsTestCase):
'old_password': 'password', 'old_password': 'password',
'new_password1': 'password1', 'new_password1': 'password1',
'new_password2': 'donuts', 'new_password2': 'donuts',
} })
)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue("The two password fields didn't match." in response.content) self.assertContainsEscaped(response, SetPasswordForm.error_messages['password_mismatch'])
def test_password_change_succeeds(self): def test_password_change_succeeds(self):
self.login() self.login()
@ -215,8 +220,7 @@ class ChangePasswordTest(AuthViewsTestCase):
'old_password': 'password', 'old_password': 'password',
'new_password1': 'password1', 'new_password1': 'password1',
'new_password2': 'password1', 'new_password2': 'password1',
} })
)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response['Location'].endswith('/password_change/done/')) self.assertTrue(response['Location'].endswith('/password_change/done/'))
self.fail_login() self.fail_login()
@ -228,8 +232,7 @@ class ChangePasswordTest(AuthViewsTestCase):
'old_password': 'password', 'old_password': 'password',
'new_password1': 'password1', 'new_password1': 'password1',
'new_password2': 'password1', 'new_password2': 'password1',
} })
)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response['Location'].endswith('/password_change/done/')) self.assertTrue(response['Location'].endswith('/password_change/done/'))
@ -266,13 +269,12 @@ class LoginTest(AuthViewsTestCase):
nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
'url': login_url, 'url': login_url,
'next': REDIRECT_FIELD_NAME, 'next': REDIRECT_FIELD_NAME,
'bad_url': urllib.quote(bad_url) 'bad_url': urllib.quote(bad_url),
} }
response = self.client.post(nasty_url, { response = self.client.post(nasty_url, {
'username': 'testclient', 'username': 'testclient',
'password': password, 'password': password,
} })
)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertFalse(bad_url in response['Location'], self.assertFalse(bad_url in response['Location'],
"%s should be blocked" % bad_url) "%s should be blocked" % bad_url)
@ -284,18 +286,16 @@ class LoginTest(AuthViewsTestCase):
'view/?param=//example.com', 'view/?param=//example.com',
'https:///', 'https:///',
'//testserver/', '//testserver/',
'/url%20with%20spaces/', # see ticket #12534 '/url%20with%20spaces/'): # see ticket #12534
):
safe_url = '%(url)s?%(next)s=%(good_url)s' % { safe_url = '%(url)s?%(next)s=%(good_url)s' % {
'url': login_url, 'url': login_url,
'next': REDIRECT_FIELD_NAME, 'next': REDIRECT_FIELD_NAME,
'good_url': urllib.quote(good_url) 'good_url': urllib.quote(good_url),
} }
response = self.client.post(safe_url, { response = self.client.post(safe_url, {
'username': 'testclient', 'username': 'testclient',
'password': password, 'password': password,
} })
)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(good_url in response['Location'], self.assertTrue(good_url in response['Location'],
"%s should be allowed" % good_url) "%s should be allowed" % good_url)
@ -322,8 +322,8 @@ class LoginURLSettings(AuthViewsTestCase):
login_required_url = self.get_login_required_url(login_url) login_required_url = self.get_login_required_url(login_url)
querystring = QueryDict('', mutable=True) querystring = QueryDict('', mutable=True)
querystring['next'] = '/login_required/' querystring['next'] = '/login_required/'
self.assertEqual(login_required_url, self.assertEqual(login_required_url, 'http://testserver%s?%s' %
'http://testserver%s?%s' % (login_url, querystring.urlencode('/'))) (login_url, querystring.urlencode('/')))
def test_remote_login_url(self): def test_remote_login_url(self):
login_url = 'http://remote.example.com/login' login_url = 'http://remote.example.com/login'
@ -422,12 +422,11 @@ class LogoutTest(AuthViewsTestCase):
for bad_url in ('http://example.com', for bad_url in ('http://example.com',
'https://example.com', 'https://example.com',
'ftp://exampel.com', 'ftp://exampel.com',
'//example.com' '//example.com'):
):
nasty_url = '%(url)s?%(next)s=%(bad_url)s' % { nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
'url': logout_url, 'url': logout_url,
'next': REDIRECT_FIELD_NAME, 'next': REDIRECT_FIELD_NAME,
'bad_url': urllib.quote(bad_url) 'bad_url': urllib.quote(bad_url),
} }
self.login() self.login()
response = self.client.get(nasty_url) response = self.client.get(nasty_url)
@ -443,12 +442,11 @@ class LogoutTest(AuthViewsTestCase):
'view/?param=//example.com', 'view/?param=//example.com',
'https:///', 'https:///',
'//testserver/', '//testserver/',
'/url%20with%20spaces/', # see ticket #12534 '/url%20with%20spaces/'): # see ticket #12534
):
safe_url = '%(url)s?%(next)s=%(good_url)s' % { safe_url = '%(url)s?%(next)s=%(good_url)s' % {
'url': logout_url, 'url': logout_url,
'next': REDIRECT_FIELD_NAME, 'next': REDIRECT_FIELD_NAME,
'good_url': urllib.quote(good_url) 'good_url': urllib.quote(good_url),
} }
self.login() self.login()
response = self.client.get(safe_url) response = self.client.get(safe_url)