Ticket #11457: 11457-3.patch

File 11457-3.patch, 3.7 KB (added by brutasse, 6 years ago)

Are we there?

  • django/contrib/auth/views.py

     
    1515from django.contrib.auth.models import User
    1616from django.views.decorators.cache import never_cache
    1717
     18import re
     19
    1820@csrf_protect
    1921@never_cache
    2022def login(request, template_name='registration/login.html',
     
    2527    if request.method == "POST":
    2628        form = authentication_form(data=request.POST)
    2729        if form.is_valid():
     30            not_secure = re.compile(r'[^\?]*//') # URLs in redirect_to should
     31                                                 # be passed as GET parameters
    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 \
     34                or ('//' in redirect_to and not_secure.match(redirect_to)) \
     35                or ' ' in redirect_to:
    3036                redirect_to = settings.LOGIN_REDIRECT_URL
    3137            from django.contrib.auth import login
    3238            login(request, form.get_user())
  • django/contrib/auth/tests/views.py

     
    22import re
    33
    44from django.conf import settings
    5 from django.contrib.auth import SESSION_KEY
     5from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
    66from django.contrib.auth.forms import AuthenticationForm
    77from django.contrib.sites.models import Site, RequestSite
    88from django.contrib.auth.models import User
     
    183183        self.assertEquals(response.context['site_name'], site.name)
    184184        self.assert_(isinstance(response.context['form'], AuthenticationForm),
    185185                     'Login form is not an AuthenticationForm')
     186
     187    def test_security_check(self, password='password'):
     188        import urllib
     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