I have just updated my copy of OSQA from SVN r670 to r1082, and the new CSRF protection (introduced in r988-r989) is causing errors on my OSQA setup. What could be wrong with my setup?

The problem appears to be that CookiePreHandlerMiddleware and CookiePostHandlerMiddleware (in forum.middleware.django_cookies) are interfering with CsrfViewMiddleware and CsrfResponseMiddleware, which are unable to use the “enhanced” cookies that they create. I don’t see how this is possible, however, because CsrfViewMiddleware and CsrfResponseMiddleware are loading before CookiePreHandlerMiddleware:

MIDDLEWARE_CLASSES = [
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.csrf.CsrfResponseMiddleware',
    'forum.middleware.django_cookies.CookiePreHandlerMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    …
    'django.middleware.transaction.TransactionMiddleware',
    'forum.middleware.django_cookies.CookiePostHandlerMiddleware',
]

Here are the symptoms that I’m seeing: if I clear my browser cookies and load an OSQA page containing a form, the page loads correctly. The form contains two hidden csrfmiddlewaretoken fields (one generated by the {% csrf_token %} tag, and one generated by the CsrfResponseMiddleware:

<form id="fmanswer" action="/q-and-a/questions/3239/answer/" method="post">
    <div style="display:none;"><input type="hidden" name="csrfmiddlewaretoken" value="7e6ceb6ec7c7512f3a3052c807b5b66a"></div>  
    <div style="display:none"><input type="hidden" name="csrfmiddlewaretoken" value="7e6ceb6ec7c7512f3a3052c807b5b66a"></div>

Additionally, the server sets a cookie:

Set-Cookie:csrftoken=7e6ceb6ec7c7512f3a3052c807b5b66a; Max-Age=31449600; Path=/

If I then refresh the page (sending the cookie with my request), Apache serves an Internal Server Error page, and I get this stack trace in my error log:

mod_wsgi (pid=3493): Exception occurred processing WSGI script '/home/kyank/learnable/osqa/osqa.wsgi'.
Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/wsgi.py", line 245, in __call__
    response = middleware_method(request, response)
  File "/usr/local/lib/python2.6/dist-packages/django/middleware/csrf.py", line 226, in process_response
    response.content, n = _POST_FORM_RE.subn(add_csrf_field, response.content)
  File "/usr/local/lib/python2.6/dist-packages/django/middleware/csrf.py", line 222, in add_csrf_field
    " name='csrfmiddlewaretoken' value='" + csrf_token + \\\\
TypeError: cannot concatenate 'str' and 'StringMorsel' objects

This error is generated by CsrfResponseMiddleware in its attempt to inject the CSRF token retrieved from the cookie into the form. The StringMorsel object referrred to on the last line indicates that, rather than getting a simple str value for the cookie, it got a StringMorsel object (as generated by forum.middleware.django_cookies.CookiePreHandlerMiddleware)! How this is happening given the middleware load order defined above is a mystery to me.

Since CsrfResponseMiddleware is not needed if all forms contain a {% csrf_token %} tag, I tried commenting it out, so that only CsrfViewMiddleware is loaded. This avoids the 500 error, but causes a TemplateSyntaxError when processing the {% csrf_token %} tag:

TemplateSyntaxError at /questions/1234/question-slug-here
Caught TypeError while rendering: Lazy object returned unexpected type.

Again, this appears to be caused by the {% csrf_token %} tag expecting to find a str in the cookie, and finding a StringMorsel there instead.

The stack trace looks like this:

Environment:

Request Method: GET
Request URL: http://courses.mythrildev.vm/q-and-a/questions/1234/question-slug-here
Django Version: 1.2.1
Python Version: 2.6.5
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.admin',
 'django.contrib.humanize',
 'django.contrib.sitemaps',
 'django.contrib.markup',
 'forum',
 'debug_toolbar',
 'south']
Installed Middleware:
['django.middleware.csrf.CsrfViewMiddleware',
 'forum.middleware.django_cookies.CookiePreHandlerMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'forum.middleware.extended_user.ExtendedUser',
 'forum_modules.learnable.middleware.AutoLoginMiddleware',
 'forum_modules.learnable.middleware.ContentAwareUserMiddleware',
 'djexceptional.ExceptionalMiddleware',
 'forum.middleware.anon_user.ConnectToSessionMessagesMiddleware',
 'forum.middleware.request_utils.RequestUtils',
 'forum.middleware.cancel.CancelActionMiddleware',
 'forum.middleware.admin_messages.AdminMessagesMiddleware',
 'django.middleware.transaction.TransactionMiddleware',
 'forum.middleware.django_cookies.CookiePostHandlerMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware']

…

Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
  100.                     response = callback(request, *callback_args, **callback_kwargs)
File "/home/kyank/learnable/osqa/forum/modules/decorators.py" in decorated
  95.                 return decoratable(*args, **kwargs)
File "/home/kyank/learnable/osqa/forum/modules/decorators.py" in __call__
  60.                     res = dec(res, *args, **kwargs)
File "/home/kyank/learnable/osqa/forum/views/decorators.py" in decorated
  32.                                       context_instance=RequestContext(request))
File "/usr/local/lib/python2.6/dist-packages/django/shortcuts/__init__.py" in render_to_response
  20.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/template/loader.py" in render_to_string
  186.     return t.render(context_instance)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in render
  173.             return self._render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in _render
  167.         return self.nodelist.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in render
  796.                 bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.6/dist-packages/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/loader_tags.py" in render
  125.         return compiled_parent._render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in _render
  167.         return self.nodelist.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in render
  796.                 bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.6/dist-packages/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/loader_tags.py" in render
  125.         return compiled_parent._render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in _render
  167.         return self.nodelist.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in render
  796.                 bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.6/dist-packages/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/loader_tags.py" in render
  139.             return self.template.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in render
  173.             return self._render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in _render
  167.         return self.nodelist.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/__init__.py" in render
  796.                 bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.6/dist-packages/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/usr/local/lib/python2.6/dist-packages/django/template/defaulttags.py" in render
  41.         if csrf_token:
File "/usr/local/lib/python2.6/dist-packages/django/utils/functional.py" in __wrapper__
  197.                 raise TypeError("Lazy object returned unexpected type.")

Exception Type: TemplateSyntaxError at /questions/3239/phpmyadmin-not-found
Exception Value: Caught TypeError while rendering: Lazy object returned unexpected type.

asked 01 Jul '11, 01:19

Kevin%20Yank's gravatar image

Kevin Yank
436111824
accept rate: 28%


Are you able to upgrade to Python 2.7 + Django 1.3? Does this problem go away if you do? (that is to say, I'm running in Python 2.7+Django1.3 and don't have this problem)

link

answered 01 Jul '11, 02:36

Andrew_S's gravatar image

Andrew_S ♦
5.6k45674
accept rate: 21%

Thanks, @Andrew_S! I’ll give it a try and get back to you.

(01 Jul '11, 02:44) Kevin Yank
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Tags:

×113
×23
×7

Asked: 01 Jul '11, 01:19

Seen: 513 times

Last updated: 01 Jul '11, 02:44

powered by OSQA