diff --git a/runtests.sh b/runtests.sh index a95762b..663ce0f 100755 --- a/runtests.sh +++ b/runtests.sh @@ -35,12 +35,13 @@ INSTALLED_APPS = ( 'django.contrib.sessions', 'session_csrf', ) +SECRET_KEY = 'asdf' EOF export PYTHONPATH=. export DJANGO_SETTINGS_MODULE=settings -django-admin.py test session_csrf +django-admin.py test session_csrf $@ rm -f $SETTINGS* rm -f test.db diff --git a/session_csrf/__init__.py b/session_csrf/__init__.py index 6b7aa53..eeaf021 100644 --- a/session_csrf/__init__.py +++ b/session_csrf/__init__.py @@ -50,16 +50,24 @@ class CsrfMiddleware(object): token = '' if ANON_COOKIE in request.COOKIES: key = request.COOKIES[ANON_COOKIE] - token = cache.get(PREFIX + key, '') + token = cache.get(self._prefix(key), '') if ANON_ALWAYS: if not key: key = django_csrf._get_new_csrf_key() if not token: token = django_csrf._get_new_csrf_key() request._anon_csrf_key = key - cache.set(PREFIX + key, token, ANON_TIMEOUT) + cache.set(self._prefix(key), token, ANON_TIMEOUT) request.csrf_token = token + def _prefix(self, key): + # In case a bogus request comes in with a massive faked anoncsrf + # cookie value, memcache will raise a MemcachedKeyLengthError + # The limit is 250 but we cut it shorter because of the possible + # configuration prefix. + prefixed = PREFIX + key + return prefixed[:100] + def process_view(self, request, view_func, args, kwargs): """Check the CSRF token if this is a POST.""" if getattr(request, 'csrf_processing_done', False): diff --git a/session_csrf/tests.py b/session_csrf/tests.py index 7c11a4e..b953686 100644 --- a/session_csrf/tests.py +++ b/session_csrf/tests.py @@ -2,7 +2,9 @@ import django.test from django import http from django.conf.urls.defaults import patterns from django.contrib.auth import logout +from django.contrib.auth.middleware import AuthenticationMiddleware from django.contrib.auth.models import User +from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.models import Session from django.core import signals from django.core.cache import cache @@ -86,12 +88,8 @@ class TestCsrfMiddleware(django.test.TestCase): rf.cookies['anoncsrf'] = self.token cache.set(PREFIX + self.token, 'woo') request = rf.get('/') - request.session = {} - r = { - 'wsgi.input': django.test.client.FakePayload('') - } - # Hack to set up request middleware. - ClientHandler()(self.rf._base_environ(**r)) + SessionMiddleware().process_request(request) + AuthenticationMiddleware().process_request(request) self.mw.process_request(request) self.assertEqual(request.csrf_token, 'woo') @@ -336,6 +334,15 @@ class TestAnonAlways(django.test.TestCase): response = self.client.get('/') self.assertEqual(len(response._request.csrf_token), 32) + def test_massive_anon_cookie(self): + # if the key + PREFIX + setting prefix is greater than 250 + # memcache will cry and you get a warning if you use LocMemCache + junk = 'x' * 300 + with mock.patch('warnings.warn') as warner: + response = self.client.get('/', HTTP_COOKIE='anoncsrf=%s' % junk) + self.assertEqual(response.status_code, 200) + self.assertEqual(warner.call_count, 0) + class ClientHandler(django.test.client.ClientHandler): """