Ticket #11457: 11457-5.patch

File 11457-5.patch, 3.9 KB (added by Bruno Renié, 14 years ago)

cleanup

  • django/contrib/auth/views.py

     
    1515from django.contrib.auth.models import User
    1616from django.views.decorators.cache import never_cache
    1717
     18import re
     19
     20not_secure = re.compile(r'[^\?]*//')
     21
    1822@csrf_protect
    1923@never_cache
    2024def login(request, template_name='registration/login.html',
     
    2630        form = authentication_form(data=request.POST)
    2731        if form.is_valid():
    2832            # Light security check -- make sure redirect_to isn't garbage.
    29             if not redirect_to or '//' in redirect_to or ' ' in redirect_to:
     33            if not redirect_to or ' ' in redirect_to:
    3034                redirect_to = settings.LOGIN_REDIRECT_URL
     35            elif '//' in redirect_to:
     36                # Heavier security check -- http://example.com should not be
     37                # allowed, but /view/?param=http://example.com is fine
     38                # The not_secure regex checks if there is a '//' *before* a
     39                # question mark
     40                if not_secure.match(redirect_to):
     41                    redirect_to = settings.LOGIN_REDIRECT_URL
    3142            from django.contrib.auth import login
    3243            login(request, form.get_user())
    3344            if request.session.test_cookie_worked():
  • django/contrib/auth/tests/views.py

     
    11import os
    22import re
     3import urllib
    34
    45from django.conf import settings
    5 from django.contrib.auth import SESSION_KEY
     6from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
    67from django.contrib.auth.forms import AuthenticationForm
    78from django.contrib.sites.models import Site, RequestSite
    89from django.contrib.auth.models import User
     
    183184        self.assertEquals(response.context['site_name'], site.name)
    184185        self.assert_(isinstance(response.context['form'], AuthenticationForm),
    185186                     'Login form is not an AuthenticationForm')
     187
     188    def test_security_check(self, password='password'):
     189        login_url = reverse('django.contrib.auth.views.login')
     190
     191        # Those URLs should not pass the security check
     192        for bad_url in ('http://example.com',
     193                        'https://example.com',
     194                        'ftp://exampel.com',
     195                        '//example.com'):
     196
     197            nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
     198                'url': login_url,
     199                'next': REDIRECT_FIELD_NAME,
     200                'bad_url': urllib.quote(bad_url)
     201            }
     202            response = self.client.post(nasty_url, {
     203                'username': 'testclient',
     204                'password': password,
     205                }
     206            )
     207            self.assertEquals(response.status_code, 302)
     208            self.assertFalse(bad_url in response['Location'], "%s should be blocked" % bad_url)
     209
     210        # Now, these URLs have an other URL as a GET parameter and therefore
     211        # should be allowed
     212        for url_ in ('http://example.com', 'https://example.com',
     213                    'ftp://exampel.com',  '//example.com'):
     214            safe_url = '%(url)s?%(next)s=/view/?param=%(safe_param)s' % {
     215                'url': login_url,
     216                'next': REDIRECT_FIELD_NAME,
     217                'safe_param': urllib.quote(url_)
     218            }
     219            response = self.client.post(safe_url, {
     220                    'username': 'testclient',
     221                    'password': password,
     222                }
     223            )
     224            self.assertEquals(response.status_code, 302)
     225            self.assertTrue('/view/?param=%s' % url_ in response['Location'], "/view/?param=%s should be allowed" % url_)
     226
    186227       
    187228class LogoutTest(AuthViewsTestCase):
    188229    urls = 'django.contrib.auth.tests.urls'
Back to Top