Made staff_member_required redirect to login

Refs #21911.
This commit is contained in:
Claude Paroz 2014-01-31 11:59:27 +01:00
parent 35cecb1ebd
commit 5848bea9dc
4 changed files with 46 additions and 177 deletions

View File

@ -226,6 +226,7 @@ class AdminSite(object):
# Admin-site-wide views.
urlpatterns = patterns('',
url(r'^$', wrap(self.index), name='index'),
url(r'^login/$', self.login, name='login'),
url(r'^logout/$', wrap(self.logout), name='logout'),
url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'),
url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True), name='password_change_done'),
@ -337,7 +338,9 @@ class AdminSite(object):
title=_('Log in'),
app_path=request.get_full_path(),
)
context[REDIRECT_FIELD_NAME] = request.get_full_path()
if (REDIRECT_FIELD_NAME not in request.GET and
REDIRECT_FIELD_NAME not in request.POST):
context[REDIRECT_FIELD_NAME] = request.get_full_path()
context.update(extra_context or {})
defaults = {

View File

@ -1,30 +1,14 @@
from functools import wraps
from django.utils.translation import ugettext as _
from django.contrib.admin.forms import AdminAuthenticationForm
from django.contrib.auth.views import login
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test
def staff_member_required(view_func):
def staff_member_required(view_func, redirect_field_name=REDIRECT_FIELD_NAME, login_url='admin:login'):
"""
Decorator for views that checks that the user is logged in and is a staff
member, displaying the login page if necessary.
"""
@wraps(view_func)
def _checklogin(request, *args, **kwargs):
if request.user.is_active and request.user.is_staff:
# The user is valid. Continue to the admin page.
return view_func(request, *args, **kwargs)
assert hasattr(request, 'session'), "The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
defaults = {
'template_name': 'admin/login.html',
'authentication_form': AdminAuthenticationForm,
'extra_context': {
'title': _('Log in'),
'app_path': request.get_full_path(),
REDIRECT_FIELD_NAME: request.get_full_path(),
},
}
return login(request, **defaults)
return _checklogin
return user_passes_test(
lambda u: u.is_active and u.is_staff,
login_url=login_url,
redirect_field_name=redirect_field_name
)(view_func)

View File

@ -38,7 +38,7 @@ class AdminDocViewTests(TestCase):
def test_index(self):
self.client.logout()
response = self.client.get(reverse('django-admindocs-docroot'))
response = self.client.get(reverse('django-admindocs-docroot'), follow=True)
# Should display the login screen
self.assertContains(response,
'<input type="hidden" name="next" value="/admindocs/" />', html=True)

View File

@ -1297,11 +1297,11 @@ class AdminViewPermissionsTest(TestCase):
superuser.is_active = False
superuser.save()
response = self.client.get('/test_admin/admin/')
response = self.client.get('/test_admin/admin/', follow=True)
self.assertContains(response, 'id="login-form"')
self.assertNotContains(response, 'Log out')
response = self.client.get('/test_admin/admin/secure-view/')
response = self.client.get('/test_admin/admin/secure-view/', follow=True)
self.assertContains(response, 'id="login-form"')
def testDisabledStaffPermissionsWhenLoggedIn(self):
@ -1310,11 +1310,11 @@ class AdminViewPermissionsTest(TestCase):
superuser.is_staff = False
superuser.save()
response = self.client.get('/test_admin/admin/')
response = self.client.get('/test_admin/admin/', follow=True)
self.assertContains(response, 'id="login-form"')
self.assertNotContains(response, 'Log out')
response = self.client.get('/test_admin/admin/secure-view/')
response = self.client.get('/test_admin/admin/secure-view/', follow=True)
self.assertContains(response, 'id="login-form"')
def testAppIndexFailEarly(self):
@ -1338,6 +1338,25 @@ class AdminViewPermissionsTest(TestCase):
response = self.client.get('/test_admin/admin/admin_views/')
self.assertEqual(response.status_code, 200)
def test_shortcut_view_only_available_to_staff(self):
"""
Only admin users should be able to use the admin shortcut view.
"""
model_ctype = ContentType.objects.get_for_model(ModelWithStringPrimaryKey)
obj = ModelWithStringPrimaryKey.objects.create(string_pk='foo')
shortcut_url = "/test_admin/admin/r/%s/%s/" % (model_ctype.pk, obj.pk)
# Not logged in: we should see the login page.
response = self.client.get(shortcut_url, follow=False)
self.assertTemplateUsed(response, 'admin/login.html')
# Logged in? Redirect.
self.client.login(username='super', password='secret')
response = self.client.get(shortcut_url, follow=False)
# Can't use self.assertRedirects() because User.get_absolute_url() is silly.
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, 'http://example.com/dummy/foo/')
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class AdminViewsNoUrlTest(TestCase):
@ -1625,162 +1644,25 @@ class AdminViewStringPrimaryKeyTest(TestCase):
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class SecureViewTests(TestCase):
"""
Test behaviour of a view protected by the staff_member_required decorator.
"""
urls = "admin_views.urls"
fixtures = ['admin-views-users.xml']
def setUp(self):
# login POST dicts
self.super_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'super',
'password': 'secret',
}
self.super_email_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'super@example.com',
'password': 'secret',
}
self.super_email_bad_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'super@example.com',
'password': 'notsecret',
}
self.adduser_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'adduser',
'password': 'secret',
}
self.changeuser_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'changeuser',
'password': 'secret',
}
self.deleteuser_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'deleteuser',
'password': 'secret',
}
self.joepublic_login = {
LOGIN_FORM_KEY: 1,
REDIRECT_FIELD_NAME: '/test_admin/admin/secure-view/',
'username': 'joepublic',
'password': 'secret',
}
def tearDown(self):
self.client.logout()
def test_secure_view_shows_login_if_not_logged_in(self):
"Ensure that we see the login form"
response = self.client.get('/test_admin/admin/secure-view/')
"""
Ensure that we see the admin login form.
"""
secure_url = '/test_admin/admin/secure-view/'
response = self.client.get(secure_url)
self.assertRedirects(response, '%s?next=%s' % (reverse('admin:login'), secure_url))
response = self.client.get(secure_url, follow=True)
self.assertTemplateUsed(response, 'admin/login.html')
def test_secure_view_login_successfully_redirects_to_original_url(self):
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
query_string = 'the-answer=42'
redirect_url = '/test_admin/admin/secure-view/?%s' % query_string
new_next = {REDIRECT_FIELD_NAME: redirect_url}
login = self.client.post('/test_admin/admin/secure-view/', dict(self.super_login, **new_next), QUERY_STRING=query_string)
self.assertRedirects(login, redirect_url)
def test_staff_member_required_decorator_works_as_per_admin_login(self):
"""
Make sure only staff members can log in.
Successful posts to the login page will redirect to the orignal url.
Unsuccessfull attempts will continue to render the login page with
a 200 status code.
"""
# Super User
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.super_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# make sure the view removes test cookie
self.assertEqual(self.client.session.test_cookie_worked(), False)
# Test if user enters email address
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
self.assertContains(login, ERROR_MESSAGE)
# only correct passwords get a username hint
login = self.client.post('/test_admin/admin/secure-view/', self.super_email_bad_login)
self.assertContains(login, ERROR_MESSAGE)
new_user = User(username='jondoe', password='secret', email='super@example.com')
new_user.save()
# check to ensure if there are multiple email addresses a user doesn't get a 500
login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
self.assertContains(login, ERROR_MESSAGE)
# Add User
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.adduser_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Change User
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.changeuser_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Delete User
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.deleteuser_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Regular User should not be able to login.
response = self.client.get('/test_admin/admin/secure-view/')
self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.joepublic_login)
self.assertEqual(login.status_code, 200)
# Login.context is a list of context dicts we just need to check the first one.
self.assertContains(login, ERROR_MESSAGE)
# 8509 - if a normal user is already logged in, it is possible
# to change user into the superuser without error
login = self.client.login(username='joepublic', password='secret')
# Check and make sure that if user expires, data still persists
self.client.get('/test_admin/admin/secure-view/')
self.client.post('/test_admin/admin/secure-view/', self.super_login)
# make sure the view removes test cookie
self.assertEqual(self.client.session.test_cookie_worked(), False)
def test_shortcut_view_only_available_to_staff(self):
"""
Only admin users should be able to use the admin shortcut view.
"""
model_ctype = ContentType.objects.get_for_model(ModelWithStringPrimaryKey)
obj = ModelWithStringPrimaryKey.objects.create(string_pk='foo')
shortcut_url = "/test_admin/admin/r/%s/%s/" % (model_ctype.pk, obj.pk)
# Not logged in: we should see the login page.
response = self.client.get(shortcut_url, follow=False)
self.assertTemplateUsed(response, 'admin/login.html')
# Logged in? Redirect.
self.client.login(username='super', password='secret')
response = self.client.get(shortcut_url, follow=False)
# Can't use self.assertRedirects() because User.get_absolute_url() is silly.
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, 'http://example.com/dummy/foo/')
self.assertEqual(response.context[REDIRECT_FIELD_NAME], secure_url)
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))