Author: russellm
Date: 2010-08-27 08:59:46 -0500 (Fri, 27 Aug 2010)
New Revision: 13643

Added:
   django/branches/releases/1.2.X/django/contrib/flatpages/fixtures/
   
django/branches/releases/1.2.X/django/contrib/flatpages/fixtures/sample_flatpages.json
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/__init__.py
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/csrf.py
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/middleware.py
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/
   
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/404.html
   
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/flatpages/
   
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/flatpages/default.html
   
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/registration/
   
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/registration/login.html
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/urls.py
   django/branches/releases/1.2.X/django/contrib/flatpages/tests/views.py
Modified:
   django/branches/releases/1.2.X/django/contrib/flatpages/views.py
Log:
[1.2.X] Fixed #14156 -- Modified the way CSRF protection is applied to 
flatpages so that the flatpage middleware doesn't cause all POSTs resulting in 
404s to turn into 403s. Thanks to patrys for the report.

Backport of r13641 from trunk.

Added: 
django/branches/releases/1.2.X/django/contrib/flatpages/fixtures/sample_flatpages.json
===================================================================
--- 
django/branches/releases/1.2.X/django/contrib/flatpages/fixtures/sample_flatpages.json
                              (rev 0)
+++ 
django/branches/releases/1.2.X/django/contrib/flatpages/fixtures/sample_flatpages.json
      2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,32 @@
+[
+    {
+        "pk": 1,
+        "model": "flatpages.flatpage",
+        "fields": {
+            "registration_required": false,
+            "title": "A Flatpage",
+            "url": "/flatpage/",
+            "template_name": "",
+            "sites": [
+                1
+            ],
+            "content": "Isn't it flat!",
+            "enable_comments": false
+        }
+    },
+    {
+        "pk": 2,
+        "model": "flatpages.flatpage",
+        "fields": {
+            "registration_required": true,
+            "title": "Sekrit Flatpage",
+            "url": "/sekrit/",
+            "template_name": "",
+            "sites": [
+                1
+            ],
+            "content": "Isn't it sekrit!",
+            "enable_comments": false
+        }
+    }
+]
\ No newline at end of file

Added: django/branches/releases/1.2.X/django/contrib/flatpages/tests/__init__.py
===================================================================
--- django/branches/releases/1.2.X/django/contrib/flatpages/tests/__init__.py   
                        (rev 0)
+++ django/branches/releases/1.2.X/django/contrib/flatpages/tests/__init__.py   
2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,3 @@
+from django.contrib.flatpages.tests.csrf import *
+from django.contrib.flatpages.tests.middleware import *
+from django.contrib.flatpages.tests.views import *

Added: django/branches/releases/1.2.X/django/contrib/flatpages/tests/csrf.py
===================================================================
--- django/branches/releases/1.2.X/django/contrib/flatpages/tests/csrf.py       
                        (rev 0)
+++ django/branches/releases/1.2.X/django/contrib/flatpages/tests/csrf.py       
2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,70 @@
+import os
+from django.conf import settings
+from django.test import TestCase, Client
+
+class FlatpageCSRFTests(TestCase):
+    fixtures = ['sample_flatpages']
+    urls = 'django.contrib.flatpages.tests.urls'
+
+    def setUp(self):
+        self.client = Client(enforce_csrf_checks=True)
+        self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES
+        flatpage_middleware_class = 
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
+        csrf_middleware_class = 'django.middleware.csrf.CsrfViewMiddleware'
+        if csrf_middleware_class not in settings.MIDDLEWARE_CLASSES:
+            settings.MIDDLEWARE_CLASSES += (csrf_middleware_class,)
+        if flatpage_middleware_class not in settings.MIDDLEWARE_CLASSES:
+            settings.MIDDLEWARE_CLASSES += (flatpage_middleware_class,)
+        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
+        settings.TEMPLATE_DIRS = (
+            os.path.join(
+                os.path.dirname(__file__),
+                'templates'
+            ),
+        )
+
+    def tearDown(self):
+        settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES
+        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
+
+    def test_view_flatpage(self):
+        "A flatpage can be served through a view, even when the middleware is 
in use"
+        response = self.client.get('/flatpage_root/flatpage/')
+        self.assertEquals(response.status_code, 200)
+        self.assertContains(response, "<p>Isn't it flat!</p>")
+
+    def test_view_non_existent_flatpage(self):
+        "A non-existent flatpage raises 404 when served through a view, even 
when the middleware is in use"
+        response = self.client.get('/flatpage_root/no_such_flatpage/')
+        self.assertEquals(response.status_code, 404)
+
+    def test_view_authenticated_flatpage(self):
+        "A flatpage served through a view can require authentication"
+        response = self.client.get('/flatpage_root/sekrit/')
+        self.assertRedirects(response, 
'/accounts/login/?next=/flatpage_root/sekrit/')
+
+    def test_fallback_flatpage(self):
+        "A flatpage can be served by the fallback middlware"
+        response = self.client.get('/flatpage/')
+        self.assertEquals(response.status_code, 200)
+        self.assertContains(response, "<p>Isn't it flat!</p>")
+
+    def test_fallback_non_existent_flatpage(self):
+        "A non-existent flatpage raises a 404 when served by the fallback 
middlware"
+        response = self.client.get('/no_such_flatpage/')
+        self.assertEquals(response.status_code, 404)
+
+    def test_post_view_flatpage(self):
+        "POSTing to a flatpage served through a view will raise a CSRF error 
if no token is provided (Refs #14156)"
+        response = self.client.post('/flatpage_root/flatpage/')
+        self.assertEquals(response.status_code, 403)
+
+    def test_post_fallback_flatpage(self):
+        "POSTing to a flatpage served by the middleware will raise a CSRF 
error if no token is provided (Refs #14156)"
+        response = self.client.post('/flatpage/')
+        self.assertEquals(response.status_code, 403)
+
+    def test_post_unknown_page(self):
+        "POSTing to an unknown page isn't caught as a 403 CSRF error"
+        response = self.client.post('/no_such_page/')
+        self.assertEquals(response.status_code, 404)

Added: 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/middleware.py
===================================================================
--- django/branches/releases/1.2.X/django/contrib/flatpages/tests/middleware.py 
                        (rev 0)
+++ django/branches/releases/1.2.X/django/contrib/flatpages/tests/middleware.py 
2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,56 @@
+import os
+from django.conf import settings
+from django.test import TestCase
+
+class FlatpageMiddlewareTests(TestCase):
+    fixtures = ['sample_flatpages']
+    urls = 'django.contrib.flatpages.tests.urls'
+
+    def setUp(self):
+        self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES
+        flatpage_middleware_class = 
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
+        if flatpage_middleware_class not in settings.MIDDLEWARE_CLASSES:
+            settings.MIDDLEWARE_CLASSES += (flatpage_middleware_class,)
+        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
+        settings.TEMPLATE_DIRS = (
+            os.path.join(
+                os.path.dirname(__file__),
+                'templates'
+            ),
+        )
+
+    def tearDown(self):
+        settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES
+        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
+
+    def test_view_flatpage(self):
+        "A flatpage can be served through a view, even when the middleware is 
in use"
+        response = self.client.get('/flatpage_root/flatpage/')
+        self.assertEquals(response.status_code, 200)
+        self.assertContains(response, "<p>Isn't it flat!</p>")
+
+    def test_view_non_existent_flatpage(self):
+        "A non-existent flatpage raises 404 when served through a view, even 
when the middleware is in use"
+        response = self.client.get('/flatpage_root/no_such_flatpage/')
+        self.assertEquals(response.status_code, 404)
+
+    def test_view_authenticated_flatpage(self):
+        "A flatpage served through a view can require authentication"
+        response = self.client.get('/flatpage_root/sekrit/')
+        self.assertRedirects(response, 
'/accounts/login/?next=/flatpage_root/sekrit/')
+
+    def test_fallback_flatpage(self):
+        "A flatpage can be served by the fallback middlware"
+        response = self.client.get('/flatpage/')
+        self.assertEquals(response.status_code, 200)
+        self.assertContains(response, "<p>Isn't it flat!</p>")
+
+    def test_fallback_non_existent_flatpage(self):
+        "A non-existent flatpage raises a 404 when served by the fallback 
middlware"
+        response = self.client.get('/no_such_flatpage/')
+        self.assertEquals(response.status_code, 404)
+
+    def test_fallback_authenticated_flatpage(self):
+        "A flatpage served by the middleware can require authentication"
+        response = self.client.get('/sekrit/')
+        self.assertRedirects(response, '/accounts/login/?next=/sekrit/')

Added: 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/404.html
===================================================================
--- 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/404.html
                            (rev 0)
+++ 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/404.html
    2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1 @@
+<h1>Oh Noes!</h1>
\ No newline at end of file

Added: 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/flatpages/default.html
===================================================================
--- 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/flatpages/default.html
                              (rev 0)
+++ 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/flatpages/default.html
      2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,2 @@
+<h1>{{ flatpage.title }}</h1>
+<p>{{ flatpage.content }}</p>
\ No newline at end of file

Added: 
django/branches/releases/1.2.X/django/contrib/flatpages/tests/templates/registration/login.html
===================================================================

Added: django/branches/releases/1.2.X/django/contrib/flatpages/tests/urls.py
===================================================================
--- django/branches/releases/1.2.X/django/contrib/flatpages/tests/urls.py       
                        (rev 0)
+++ django/branches/releases/1.2.X/django/contrib/flatpages/tests/urls.py       
2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,8 @@
+from django.conf.urls.defaults import *
+
+# special urls for flatpage test cases
+urlpatterns = patterns('',
+    (r'^flatpage_root', include('django.contrib.flatpages.urls')),
+    (r'^accounts/', include('django.contrib.auth.urls')),
+)
+

Added: django/branches/releases/1.2.X/django/contrib/flatpages/tests/views.py
===================================================================
--- django/branches/releases/1.2.X/django/contrib/flatpages/tests/views.py      
                        (rev 0)
+++ django/branches/releases/1.2.X/django/contrib/flatpages/tests/views.py      
2010-08-27 13:59:46 UTC (rev 13643)
@@ -0,0 +1,50 @@
+import os
+from django.conf import settings
+from django.test import TestCase
+
+class FlatpageViewTests(TestCase):
+    fixtures = ['sample_flatpages']
+    urls = 'django.contrib.flatpages.tests.urls'
+
+    def setUp(self):
+        self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES
+        flatpage_middleware_class = 
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
+        if flatpage_middleware_class in settings.MIDDLEWARE_CLASSES:
+            settings.MIDDLEWARE_CLASSES = tuple(m for m in 
settings.MIDDLEWARE_CLASSES if m != flatpage_middleware_class)
+        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
+        settings.TEMPLATE_DIRS = (
+            os.path.join(
+                os.path.dirname(__file__),
+                'templates'
+            ),
+        )
+        settings.DEBUG = True
+    def tearDown(self):
+        settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES
+        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
+
+    def test_view_flatpage(self):
+        "A flatpage can be served through a view"
+        response = self.client.get('/flatpage_root/flatpage/')
+        self.assertEquals(response.status_code, 200)
+        self.assertContains(response, "<p>Isn't it flat!</p>")
+
+    def test_view_non_existent_flatpage(self):
+        "A non-existent flatpage raises 404 when served through a view"
+        response = self.client.get('/flatpage_root/no_such_flatpage/')
+        self.assertEquals(response.status_code, 404)
+
+    def test_view_authenticated_flatpage(self):
+        "A flatpage served through a view can require authentication"
+        response = self.client.get('/flatpage_root/sekrit/')
+        self.assertRedirects(response, 
'/accounts/login/?next=/flatpage_root/sekrit/')
+
+    def test_fallback_flatpage(self):
+        "A fallback flatpage won't be served if the middleware is disabled"
+        response = self.client.get('/flatpage/')
+        self.assertEquals(response.status_code, 404)
+
+    def test_fallback_non_existent_flatpage(self):
+        "A non-existent flatpage won't be served if the fallback middlware is 
disabled"
+        response = self.client.get('/no_such_flatpage/')
+        self.assertEquals(response.status_code, 404)

Modified: django/branches/releases/1.2.X/django/contrib/flatpages/views.py
===================================================================
--- django/branches/releases/1.2.X/django/contrib/flatpages/views.py    
2010-08-27 13:58:36 UTC (rev 13642)
+++ django/branches/releases/1.2.X/django/contrib/flatpages/views.py    
2010-08-27 13:59:46 UTC (rev 13643)
@@ -13,10 +13,13 @@
 # when a 404 is raised, which often means CsrfViewMiddleware.process_view
 # has not been called even if CsrfViewMiddleware is installed. So we need
 # to use @csrf_protect, in case the template needs {% csrf_token %}.
-...@csrf_protect
+# However, we can't just wrap this view; if no matching flatpage exists,
+# or a redirect is required for authentication, the 404 needs to be returned
+# without any CSRF checks. Therefore, we only
+# CSRF protect the internal implementation.
 def flatpage(request, url):
     """
-    Flat page view.
+    Public interface to the flat page view.
 
     Models: `flatpages.flatpages`
     Templates: Uses the template defined by the ``template_name`` field,
@@ -30,6 +33,13 @@
     if not url.startswith('/'):
         url = "/" + url
     f = get_object_or_404(FlatPage, url__exact=url, 
sites__id__exact=settings.SITE_ID)
+    return render_flatpage(request, f)
+
+...@csrf_protect
+def render_flatpage(request, f):
+    """
+    Internal interface to the flat page view.
+    """
     # If registration is required for accessing this page, and the user isn't
     # logged in, redirect to the login page.
     if f.registration_required and not request.user.is_authenticated():

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to