Fixed #19019 -- Fixed UserAdmin to log password change.

Thanks Tuttle for the report.
This commit is contained in:
Kirill Fomichev 2012-10-24 21:11:41 +06:00 committed by Tim Graham
parent 6b4967e883
commit 33242fe015
3 changed files with 72 additions and 4 deletions

View File

@ -127,6 +127,8 @@ class UserAdmin(admin.ModelAdmin):
form = self.change_password_form(user, request.POST) form = self.change_password_form(user, request.POST)
if form.is_valid(): if form.is_valid():
form.save() form.save()
change_message = self.construct_change_message(request, form, None)
self.log_change(request, request.user, change_message)
msg = ugettext('Password changed successfully.') msg = ugettext('Password changed successfully.')
messages.success(request, msg) messages.success(request, msg)
return HttpResponseRedirect('..') return HttpResponseRedirect('..')

View File

@ -350,3 +350,11 @@ class AdminPasswordChangeForm(forms.Form):
if commit: if commit:
self.user.save() self.user.save()
return self.user return self.user
def _get_changed_data(self):
data = super(AdminPasswordChangeForm, self).changed_data
for name in self.fields.keys():
if name not in data:
return []
return ['password']
changed_data = property(_get_changed_data)

View File

@ -8,6 +8,7 @@ except ImportError: # Python 2
from django.conf import global_settings, settings from django.conf import global_settings, settings
from django.contrib.sites.models import Site, RequestSite from django.contrib.sites.models import Site, RequestSite
from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import mail from django.core import mail
from django.core.urlresolvers import reverse, NoReverseMatch from django.core.urlresolvers import reverse, NoReverseMatch
@ -54,6 +55,11 @@ class AuthViewsTestCase(TestCase):
self.assertTrue(SESSION_KEY in self.client.session) self.assertTrue(SESSION_KEY in self.client.session)
return response return response
def logout(self):
response = self.client.get('/admin/logout/')
self.assertEqual(response.status_code, 200)
self.assertTrue(SESSION_KEY not in self.client.session)
def assertFormError(self, response, error): def assertFormError(self, response, error):
"""Assert that error is found in response.context['form'] errors""" """Assert that error is found in response.context['form'] errors"""
form_errors = list(itertools.chain(*response.context['form'].errors.values())) form_errors = list(itertools.chain(*response.context['form'].errors.values()))
@ -670,18 +676,70 @@ class LogoutTest(AuthViewsTestCase):
self.confirm_logged_out() self.confirm_logged_out()
@skipIfCustomUser @skipIfCustomUser
@override_settings(
PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
)
class ChangelistTests(AuthViewsTestCase): class ChangelistTests(AuthViewsTestCase):
urls = 'django.contrib.auth.tests.urls_admin' urls = 'django.contrib.auth.tests.urls_admin'
def setUp(self):
# Make me a superuser before logging in.
User.objects.filter(username='testclient').update(is_staff=True, is_superuser=True)
self.login()
self.admin = User.objects.get(pk=1)
def get_user_data(self, user):
return {
'username': user.username,
'password': user.password,
'email': user.email,
'is_active': user.is_active,
'is_staff': user.is_staff,
'is_superuser': user.is_superuser,
'last_login_0': user.last_login.strftime('%Y-%m-%d'),
'last_login_1': user.last_login.strftime('%H:%M:%S'),
'initial-last_login_0': user.last_login.strftime('%Y-%m-%d'),
'initial-last_login_1': user.last_login.strftime('%H:%M:%S'),
'date_joined_0': user.date_joined.strftime('%Y-%m-%d'),
'date_joined_1': user.date_joined.strftime('%H:%M:%S'),
'initial-date_joined_0': user.date_joined.strftime('%Y-%m-%d'),
'initial-date_joined_1': user.date_joined.strftime('%H:%M:%S'),
'first_name': user.first_name,
'last_name': user.last_name,
}
# #20078 - users shouldn't be allowed to guess password hashes via # #20078 - users shouldn't be allowed to guess password hashes via
# repeated password__startswith queries. # repeated password__startswith queries.
def test_changelist_disallows_password_lookups(self): def test_changelist_disallows_password_lookups(self):
# Make me a superuser before loging in.
User.objects.filter(username='testclient').update(is_staff=True, is_superuser=True)
self.login()
# A lookup that tries to filter on password isn't OK # A lookup that tries to filter on password isn't OK
with patch_logger('django.security.DisallowedModelAdminLookup', 'error') as logger_calls: with patch_logger('django.security.DisallowedModelAdminLookup', 'error') as logger_calls:
response = self.client.get('/admin/auth/user/?password__startswith=sha1$') response = self.client.get('/admin/auth/user/?password__startswith=sha1$')
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertEqual(len(logger_calls), 1) self.assertEqual(len(logger_calls), 1)
def test_user_change_email(self):
data = self.get_user_data(self.admin)
data['email'] = 'new_' + data['email']
response = self.client.post('/admin/auth/user/%s/' % self.admin.pk, data)
self.assertRedirects(response, '/admin/auth/user/')
row = LogEntry.objects.latest('id')
self.assertEqual(row.change_message, 'Changed email.')
def test_user_not_change(self):
response = self.client.post('/admin/auth/user/%s/' % self.admin.pk,
self.get_user_data(self.admin)
)
self.assertRedirects(response, '/admin/auth/user/')
row = LogEntry.objects.latest('id')
self.assertEqual(row.change_message, 'No fields changed.')
def test_user_change_password(self):
response = self.client.post('/admin/auth/user/%s/password/' % self.admin.pk, {
'password1': 'password1',
'password2': 'password1',
})
self.assertRedirects(response, '/admin/auth/user/%s/' % self.admin.pk)
row = LogEntry.objects.latest('id')
self.assertEqual(row.change_message, 'Changed password.')
self.logout()
self.login(password='password1')