Code

Ticket #11457: 11457-4.patch

File 11457-4.patch, 3.9 KB (added by brutasse, 4 years ago)

Added some readability thank to Jacob's comments

  • 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', 
     
    2628        form = authentication_form(data=request.POST) 
    2729        if form.is_valid(): 
    2830            # Light security check -- make sure redirect_to isn't garbage. 
    29             if not redirect_to or '//' in redirect_to or ' ' in redirect_to: 
     31            if not redirect_to or ' ' in redirect_to: 
    3032                redirect_to = settings.LOGIN_REDIRECT_URL 
     33            elif '//' in redirect_to: 
     34                # Heavier security check -- http://example.com should not be 
     35                # allowed, but /view/?param=http://example.com is fine 
     36                # This regex checks if there is a '//' *before* a question mark 
     37                if re.match(r'[^\?]*//', redirect_to): 
     38                    redirect_to = settings.LOGIN_REDIRECT_URL 
    3139            from django.contrib.auth import login 
    3240            login(request, form.get_user()) 
    3341            if request.session.test_cookie_worked(): 
  • 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'