Permalink
Browse files

Made staff_member_required redirect to login

Refs #21911.
  • Loading branch information...
claudep committed Jan 31, 2014
1 parent 35cecb1 commit 5848bea9dc9458a9517d4c98993d742976771342
Showing with 44 additions and 175 deletions.
  1. +4 −1 django/contrib/admin/sites.py
  2. +7 −23 django/contrib/admin/views/decorators.py
  3. +1 −1 tests/admin_docs/tests.py
  4. +32 −150 tests/admin_views/tests.py
@@ -226,6 +226,7 @@ def wrapper(*args, **kwargs):
# 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 @@ def login(self, request, extra_context=None):
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 = {
@@ -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)
@@ -38,7 +38,7 @@ def setUp(self):
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
@@ -1297,11 +1297,11 @@ def testDisabledPermissionsWhenLoggedIn(self):
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 @@ def testDisabledStaffPermissionsWhenLoggedIn(self):
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 @@ def testAppIndexFailEarly(self):
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 @@ def test_change_view_history_link(self):
@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/')
- 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.
+ Ensure that we see the admin login form.
"""
- 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)
+ 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')
-
- # 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',))

0 comments on commit 5848bea

Please sign in to comment.