Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #5801: admin requests with GET args now get properly bounced th…

…rough login with those args intact. Thanks for the patch, Rozza.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8271 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 4747347385fa5c3a1e948a892fd5e60fb8f53bed 1 parent 400a6b2
Jacob Kaplan-Moss authored August 09, 2008
1  AUTHORS
@@ -335,6 +335,7 @@ answer newbie questions, and generally made Django that much better:
335 335
     Armin Ronacher
336 336
     Daniel Roseman <http://roseman.org.uk/>    
337 337
     Brian Rosner <brosner@gmail.com>
  338
+    Rozza <ross.lawley@gmail.com>
338 339
     Oliver Rutherfurd <http://rutherfurd.net/>
339 340
     ryankanno
340 341
     Manuel Saelices <msaelices@yaco.es>
4  django/contrib/admin/sites.py
@@ -269,7 +269,7 @@ def login(self, request):
269 269
                         return self.root(request, request.path.split(self.root_path)[-1])
270 270
                     else:
271 271
                         request.session.delete_test_cookie()
272  
-                        return http.HttpResponseRedirect(request.path)
  272
+                        return http.HttpResponseRedirect(request.get_full_path())
273 273
             else:
274 274
                 return self.display_login_form(request, ERROR_MESSAGE)
275 275
     login = never_cache(login)
@@ -341,7 +341,7 @@ def display_login_form(self, request, error_message='', extra_context=None):
341 341
 
342 342
         context = {
343 343
             'title': _('Log in'),
344  
-            'app_path': request.path,
  344
+            'app_path': request.get_full_path(),
345 345
             'post_data': post_data,
346 346
             'error_message': error_message,
347 347
             'root_path': self.root_path,
6  django/contrib/admin/views/decorators.py
@@ -28,7 +28,7 @@ def _display_login_form(request, error_message=''):
28 28
         post_data = _encode_post_data({})
29 29
     return render_to_response('admin/login.html', {
30 30
         'title': _('Log in'),
31  
-        'app_path': request.path,
  31
+        'app_path': request.get_full_path(),
32 32
         'post_data': post_data,
33 33
         'error_message': error_message
34 34
     }, context_instance=template.RequestContext(request))
@@ -84,7 +84,7 @@ def _checklogin(request, *args, **kwargs):
84 84
             if '@' in username:
85 85
                 # Mistakenly entered e-mail address instead of username? Look it up.
86 86
                 users = list(User.objects.filter(email=username))
87  
-                if len(users) == 1:
  87
+                if len(users) == 1 and users[0].check_password(password):
88 88
                     message = _("Your e-mail address is not your username. Try '%s' instead.") % users[0].username
89 89
                 else:
90 90
                     # Either we cannot find the user, or if more than 1
@@ -106,7 +106,7 @@ def _checklogin(request, *args, **kwargs):
106 106
                         return view_func(request, *args, **kwargs)
107 107
                     else:
108 108
                         request.session.delete_test_cookie()
109  
-                        return http.HttpResponseRedirect(request.path)
  109
+                        return http.HttpResponseRedirect(request.get_full_path())
110 110
             else:
111 111
                 return _display_login_form(request, ERROR_MESSAGE)
112 112
 
118  tests/regressiontests/admin_views/tests.py
@@ -152,6 +152,13 @@ def testLogin(self):
152 152
         # Login.context is a list of context dicts we just need to check the first one.
153 153
         self.assert_(login.context[0].get('error_message'))
154 154
 
  155
+    def testLoginSuccessfullyRedirectsToOriginalUrl(self):
  156
+        request = self.client.get('/test_admin/admin/')
  157
+        self.failUnlessEqual(request.status_code, 200)
  158
+        query_string = "the-answer=42"
  159
+        login = self.client.post('/test_admin/admin/', self.super_login, QUERY_STRING = query_string )
  160
+        self.assertRedirects(login, '/test_admin/admin/?%s' % query_string)
  161
+
155 162
     def testAddView(self):
156 163
         """Test add view restricts access and actually adds items."""
157 164
 
@@ -363,3 +370,114 @@ def test_deleteconfirmation_link(self):
363 370
         response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk))
364 371
         should_contain = """<a href="../../%s/">%s</a>""" % (quote(self.pk), escape(self.pk))
365 372
         self.assertContains(response, should_contain)
  373
+
  374
+class SecureViewTest(TestCase):
  375
+    fixtures = ['admin-views-users.xml']
  376
+
  377
+    def setUp(self):
  378
+        # login POST dicts
  379
+        self.super_login = {'post_data': _encode_post_data({}),
  380
+                     LOGIN_FORM_KEY: 1,
  381
+                     'username': 'super',
  382
+                     'password': 'secret'}
  383
+        self.super_email_login = {'post_data': _encode_post_data({}),
  384
+                     LOGIN_FORM_KEY: 1,
  385
+                     'username': 'super@example.com',
  386
+                     'password': 'secret'}
  387
+        self.super_email_bad_login = {'post_data': _encode_post_data({}),
  388
+                      LOGIN_FORM_KEY: 1,
  389
+                      'username': 'super@example.com',
  390
+                      'password': 'notsecret'}
  391
+        self.adduser_login = {'post_data': _encode_post_data({}),
  392
+                     LOGIN_FORM_KEY: 1,
  393
+                     'username': 'adduser',
  394
+                     'password': 'secret'}
  395
+        self.changeuser_login = {'post_data': _encode_post_data({}),
  396
+                     LOGIN_FORM_KEY: 1,
  397
+                     'username': 'changeuser',
  398
+                     'password': 'secret'}
  399
+        self.deleteuser_login = {'post_data': _encode_post_data({}),
  400
+                     LOGIN_FORM_KEY: 1,
  401
+                     'username': 'deleteuser',
  402
+                     'password': 'secret'}
  403
+        self.joepublic_login = {'post_data': _encode_post_data({}),
  404
+                     LOGIN_FORM_KEY: 1,
  405
+                     'username': 'joepublic',
  406
+                     'password': 'secret'}
  407
+    
  408
+    def tearDown(self):
  409
+        self.client.logout()
  410
+    
  411
+    def test_secure_view_shows_login_if_not_logged_in(self):
  412
+        "Ensure that we see the login form"
  413
+        response = self.client.get('/test_admin/admin/secure-view/' )
  414
+        self.assertTemplateUsed(response, 'admin/login.html')
  415
+    
  416
+    def test_secure_view_login_successfully_redirects_to_original_url(self):
  417
+        request = self.client.get('/test_admin/admin/secure-view/')
  418
+        self.failUnlessEqual(request.status_code, 200)
  419
+        query_string = "the-answer=42"
  420
+        login = self.client.post('/test_admin/admin/secure-view/', self.super_login, QUERY_STRING = query_string )
  421
+        self.assertRedirects(login, '/test_admin/admin/secure-view/?%s' % query_string)
  422
+    
  423
+    def test_staff_member_required_decorator_works_as_per_admin_login(self):
  424
+        """
  425
+        Make sure only staff members can log in.
  426
+
  427
+        Successful posts to the login page will redirect to the orignal url.
  428
+        Unsuccessfull attempts will continue to render the login page with 
  429
+        a 200 status code.
  430
+        """
  431
+        # Super User
  432
+        request = self.client.get('/test_admin/admin/secure-view/')
  433
+        self.failUnlessEqual(request.status_code, 200)
  434
+        login = self.client.post('/test_admin/admin/secure-view/', self.super_login)
  435
+        self.assertRedirects(login, '/test_admin/admin/secure-view/')
  436
+        self.assertFalse(login.context)
  437
+        self.client.get('/test_admin/admin/logout/')
  438
+
  439
+        # Test if user enters e-mail address
  440
+        request = self.client.get('/test_admin/admin/secure-view/')
  441
+        self.failUnlessEqual(request.status_code, 200)
  442
+        login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
  443
+        self.assertContains(login, "Your e-mail address is not your username")
  444
+        # only correct passwords get a username hint
  445
+        login = self.client.post('/test_admin/admin/secure-view/', self.super_email_bad_login)
  446
+        self.assertContains(login, "Usernames cannot contain the &#39;@&#39; character")
  447
+        new_user = User(username='jondoe', password='secret', email='super@example.com')
  448
+        new_user.save()
  449
+        # check to ensure if there are multiple e-mail addresses a user doesn't get a 500
  450
+        login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
  451
+        self.assertContains(login, "Usernames cannot contain the &#39;@&#39; character")
  452
+
  453
+        # Add User
  454
+        request = self.client.get('/test_admin/admin/secure-view/')
  455
+        self.failUnlessEqual(request.status_code, 200)
  456
+        login = self.client.post('/test_admin/admin/secure-view/', self.adduser_login)
  457
+        self.assertRedirects(login, '/test_admin/admin/secure-view/')
  458
+        self.assertFalse(login.context)
  459
+        self.client.get('/test_admin/admin/logout/')
  460
+
  461
+        # Change User
  462
+        request = self.client.get('/test_admin/admin/secure-view/')
  463
+        self.failUnlessEqual(request.status_code, 200)
  464
+        login = self.client.post('/test_admin/admin/secure-view/', self.changeuser_login)
  465
+        self.assertRedirects(login, '/test_admin/admin/secure-view/')
  466
+        self.assertFalse(login.context)
  467
+        self.client.get('/test_admin/admin/logout/')
  468
+
  469
+        # Delete User
  470
+        request = self.client.get('/test_admin/admin/secure-view/')
  471
+        self.failUnlessEqual(request.status_code, 200)
  472
+        login = self.client.post('/test_admin/admin/secure-view/', self.deleteuser_login)
  473
+        self.assertRedirects(login, '/test_admin/admin/secure-view/')
  474
+        self.assertFalse(login.context)
  475
+        self.client.get('/test_admin/admin/logout/')
  476
+
  477
+        # Regular User should not be able to login.
  478
+        request = self.client.get('/test_admin/admin/secure-view/')
  479
+        self.failUnlessEqual(request.status_code, 200)
  480
+        login = self.client.post('/test_admin/admin/secure-view/', self.joepublic_login)
  481
+        self.failUnlessEqual(login.status_code, 200)
  482
+        # Login.context is a list of context dicts we just need to check the first one.
  483
+        self.assert_(login.context[0].get('error_message'))
2  tests/regressiontests/admin_views/urls.py
... ...
@@ -1,7 +1,9 @@
1 1
 from django.conf.urls.defaults import *
2 2
 from django.contrib import admin
  3
+import views
3 4
 
4 5
 urlpatterns = patterns('',
5 6
     (r'^admin/doc/', include('django.contrib.admindocs.urls')),
  7
+    (r'^admin/secure-view/$', views.secure_view),
6 8
     (r'^admin/(.*)', admin.site.root),
7 9
 )
6  tests/regressiontests/admin_views/views.py
... ...
@@ -0,0 +1,6 @@
  1
+from django.contrib.admin.views.decorators import staff_member_required
  2
+from django.http import HttpResponse
  3
+
  4
+def secure_view(request):
  5
+    return HttpResponse('')
  6
+secure_view = staff_member_required(secure_view)

0 notes on commit 4747347

Please sign in to comment.
Something went wrong with that request. Please try again.