Ticket #5801: admin_login.patch

File admin_login.patch, 10.2 KB (added by Rozza, 7 years ago)

Full fix with tests

  • django/contrib/admin/views/decorators.py

     
    2828        post_data = _encode_post_data({})
    2929    return render_to_response('admin/login.html', {
    3030        'title': _('Log in'),
    31         'app_path': request.path,
     31        'app_path': request.get_full_path(),
    3232        'post_data': post_data,
    3333        'error_message': error_message
    3434    }, context_instance=template.RequestContext(request))
     
    8484            if '@' in username:
    8585                # Mistakenly entered e-mail address instead of username? Look it up.
    8686                users = list(User.objects.filter(email=username))
    87                 if len(users) == 1:
     87                if len(users) == 1 and users[0].check_password(password):
    8888                    message = _("Your e-mail address is not your username. Try '%s' instead.") % users[0].username
    8989                else:
    9090                    # Either we cannot find the user, or if more than 1
     
    106106                        return view_func(request, *args, **kwargs)
    107107                    else:
    108108                        request.session.delete_test_cookie()
    109                         return http.HttpResponseRedirect(request.path)
     109                        return http.HttpResponseRedirect(request.get_full_path())
    110110            else:
    111111                return _display_login_form(request, ERROR_MESSAGE)
    112112
  • django/contrib/admin/sites.py

     
    261261                        return self.root(request, request.path.split(self.root_path)[-1])
    262262                    else:
    263263                        request.session.delete_test_cookie()
    264                         return http.HttpResponseRedirect(request.path)
     264                        return http.HttpResponseRedirect(request.get_full_path())
    265265            else:
    266266                return self.display_login_form(request, ERROR_MESSAGE)
    267267    login = never_cache(login)
     
    333333       
    334334        context = {
    335335            'title': _('Log in'),
    336             'app_path': request.path,
     336            'app_path': request.get_full_path(),
    337337            'post_data': post_data,
    338338            'error_message': error_message,
    339339            'root_path': self.root_path,
  • tests/regressiontests/admin_views/views.py

     
     1from django.contrib.admin.views.decorators import staff_member_required
     2from django.http import HttpResponse
     3
     4@staff_member_required
     5def secure_view(request):
     6    return HttpResponse('')
  • tests/regressiontests/admin_views/tests.py

     
    151151        # Login.context is a list of context dicts we just need to check the first one.
    152152        self.assert_(login.context[0].get('error_message'))
    153153
     154    def testLoginSuccessfullyRedirectsToOriginalUrl(self):
     155        request = self.client.get('/test_admin/admin/')
     156        self.failUnlessEqual(request.status_code, 200)
     157        query_string = "the-answer=42"
     158        login = self.client.post('/test_admin/admin/', self.super_login, QUERY_STRING = query_string )
     159        self.assertRedirects(login, '/test_admin/admin/?%s' % query_string)
     160
    154161    def testAddView(self):
    155162        """Test add view restricts access and actually adds items."""
    156163       
     
    360367        response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk))
    361368        should_contain = """<a href="../../%s/">%s</a>""" % (quote(self.pk), escape(self.pk))
    362369        self.assertContains(response, should_contain)
     370
     371class SecureViewTest(TestCase):
     372    fixtures = ['admin-views-users.xml']
     373
     374    def setUp(self):
     375        # login POST dicts
     376        self.super_login = {'post_data': _encode_post_data({}),
     377                     LOGIN_FORM_KEY: 1,
     378                     'username': 'super',
     379                     'password': 'secret'}
     380        self.super_email_login = {'post_data': _encode_post_data({}),
     381                     LOGIN_FORM_KEY: 1,
     382                     'username': 'super@example.com',
     383                     'password': 'secret'}
     384        self.super_email_bad_login = {'post_data': _encode_post_data({}),
     385                      LOGIN_FORM_KEY: 1,
     386                      'username': 'super@example.com',
     387                      'password': 'notsecret'}
     388        self.adduser_login = {'post_data': _encode_post_data({}),
     389                     LOGIN_FORM_KEY: 1,
     390                     'username': 'adduser',
     391                     'password': 'secret'}
     392        self.changeuser_login = {'post_data': _encode_post_data({}),
     393                     LOGIN_FORM_KEY: 1,
     394                     'username': 'changeuser',
     395                     'password': 'secret'}
     396        self.deleteuser_login = {'post_data': _encode_post_data({}),
     397                     LOGIN_FORM_KEY: 1,
     398                     'username': 'deleteuser',
     399                     'password': 'secret'}
     400        self.joepublic_login = {'post_data': _encode_post_data({}),
     401                     LOGIN_FORM_KEY: 1,
     402                     'username': 'joepublic',
     403                     'password': 'secret'}
     404   
     405    def tearDown(self):
     406        self.client.logout()
     407   
     408    def test_secure_view_shows_login_if_not_logged_in(self):
     409        "Ensure that we see the login form"
     410        response = self.client.get('/test_admin/admin/secure-view/' )
     411        self.assertTemplateUsed(response, 'admin/login.html')
     412   
     413    def test_secure_view_login_successfully_redirects_to_original_url(self):
     414        request = self.client.get('/test_admin/admin/secure-view/')
     415        self.failUnlessEqual(request.status_code, 200)
     416        query_string = "the-answer=42"
     417        login = self.client.post('/test_admin/admin/secure-view/', self.super_login, QUERY_STRING = query_string )
     418        self.assertRedirects(login, '/test_admin/admin/secure-view/?%s' % query_string)
     419   
     420    def test_staff_member_required_decorator_works_as_per_admin_login(self):
     421        """
     422        Make sure only staff members can log in.
     423
     424        Successful posts to the login page will redirect to the orignal url.
     425        Unsuccessfull attempts will continue to render the login page with
     426        a 200 status code.
     427        """
     428        # Super User
     429        request = self.client.get('/test_admin/admin/secure-view/')
     430        self.failUnlessEqual(request.status_code, 200)
     431        login = self.client.post('/test_admin/admin/secure-view/', self.super_login)
     432        self.assertRedirects(login, '/test_admin/admin/secure-view/')
     433        self.assertFalse(login.context)
     434        self.client.get('/test_admin/admin/logout/')
     435
     436        # Test if user enters e-mail address
     437        request = self.client.get('/test_admin/admin/secure-view/')
     438        self.failUnlessEqual(request.status_code, 200)
     439        login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
     440        self.assertContains(login, "Your e-mail address is not your username")
     441        # only correct passwords get a username hint
     442        login = self.client.post('/test_admin/admin/secure-view/', self.super_email_bad_login)
     443        self.assertContains(login, "Usernames cannot contain the &#39;@&#39; character")
     444        new_user = User(username='jondoe', password='secret', email='super@example.com')
     445        new_user.save()
     446        # check to ensure if there are multiple e-mail addresses a user doesn't get a 500
     447        login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
     448        self.assertContains(login, "Usernames cannot contain the &#39;@&#39; character")
     449
     450        # Add User
     451        request = self.client.get('/test_admin/admin/secure-view/')
     452        self.failUnlessEqual(request.status_code, 200)
     453        login = self.client.post('/test_admin/admin/secure-view/', self.adduser_login)
     454        self.assertRedirects(login, '/test_admin/admin/secure-view/')
     455        self.assertFalse(login.context)
     456        self.client.get('/test_admin/admin/logout/')
     457
     458        # Change User
     459        request = self.client.get('/test_admin/admin/secure-view/')
     460        self.failUnlessEqual(request.status_code, 200)
     461        login = self.client.post('/test_admin/admin/secure-view/', self.changeuser_login)
     462        self.assertRedirects(login, '/test_admin/admin/secure-view/')
     463        self.assertFalse(login.context)
     464        self.client.get('/test_admin/admin/logout/')
     465
     466        # Delete User
     467        request = self.client.get('/test_admin/admin/secure-view/')
     468        self.failUnlessEqual(request.status_code, 200)
     469        login = self.client.post('/test_admin/admin/secure-view/', self.deleteuser_login)
     470        self.assertRedirects(login, '/test_admin/admin/secure-view/')
     471        self.assertFalse(login.context)
     472        self.client.get('/test_admin/admin/logout/')
     473
     474        # Regular User should not be able to login.
     475        request = self.client.get('/test_admin/admin/secure-view/')
     476        self.failUnlessEqual(request.status_code, 200)
     477        login = self.client.post('/test_admin/admin/secure-view/', self.joepublic_login)
     478        self.failUnlessEqual(login.status_code, 200)
     479        # Login.context is a list of context dicts we just need to check the first one.
     480        self.assert_(login.context[0].get('error_message'))
  • tests/regressiontests/admin_views/urls.py

     
    11from django.conf.urls.defaults import *
    22from django.contrib import admin
     3import views
    34
    45urlpatterns = patterns('',
    56    (r'^admin/doc/', include('django.contrib.admindocs.urls')),
     7    (r'^admin/secure-view/$', views.secure_view),
    68    (r'^admin/(.*)', admin.site.root),
    79)
Back to Top