diff --git a/.travis.yml b/.travis.yml index 5ab03d2..ea3cf62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ python: - "2.7" env: - - DJANGO="Django==1.7.11" - - DJANGO="Django==1.8.11" - - DJANGO="Django==1.9.4" + - DJANGO="Django==1.8.15" + - DJANGO="Django==1.9.10" + - DJANGO="Django==1.10.1" install: pip install $DJANGO diff --git a/runtests.sh b/runtests.sh index 5ea052a..d04c3af 100755 --- a/runtests.sh +++ b/runtests.sh @@ -10,22 +10,29 @@ DATABASES = { }, } -MIDDLEWARE_CLASSES = ( +MIDDLEWARE_CLASSES = MIDDLEWARE = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'session_csrf.CsrfMiddleware', ) -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.static', - 'django.contrib.messages.context_processors.messages', - 'session_csrf.context_processor', -) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.contrib.messages.context_processors.messages', + 'session_csrf.context_processor', + ], + }, + }, +] ROOT_URLCONF = 'session_csrf.tests' diff --git a/session_csrf/__init__.py b/session_csrf/__init__.py index 84a3894..888d188 100644 --- a/session_csrf/__init__.py +++ b/session_csrf/__init__.py @@ -3,9 +3,14 @@ import hashlib from django.conf import settings +from django import VERSION as DJANGO_VERSION from django.core.cache import cache from django.middleware import csrf as django_csrf -from django.utils import crypto +try: + from django.middleware.csrf import _get_new_csrf_key as django_get_new_csrf_string +except ImportError: + from django.middleware.csrf import _get_new_csrf_string as django_get_new_csrf_string +from django.utils import crypto, deprecation from django.utils.cache import patch_vary_headers @@ -32,7 +37,17 @@ def prep_key(key): prefixed = PREFIX + key return hashlib.md5(prefixed).hexdigest() -class CsrfMiddleware(object): + +def is_user_authenticated(request): + if DJANGO_VERSION < (1, 10, 0): + return request.user.is_authenticated() + else: + return request.user.is_authenticated + +# Inherit from deprecation.MiddlewareMixin to ensure it works +# with the new style middleware in Django 1.10 - see +# https://docs.djangoproject.com/en/1.10/topics/http/middleware/#django.utils.deprecation.MiddlewareMixin +class CsrfMiddleware(deprecation.MiddlewareMixin if DJANGO_VERSION >= (1, 10, 0) else object): # csrf_processing_done prevents checking CSRF more than once. That could # happen if the requires_csrf_token decorator is used. @@ -50,9 +65,9 @@ def process_request(self, request): """ if hasattr(request, 'csrf_token'): return - if request.user.is_authenticated(): + if is_user_authenticated(request): if 'csrf_token' not in request.session: - token = django_csrf._get_new_csrf_key() + token = django_get_new_csrf_string() request.csrf_token = request.session['csrf_token'] = token else: request.csrf_token = request.session['csrf_token'] @@ -64,9 +79,9 @@ def process_request(self, request): token = cache.get(prep_key(key), '') if ANON_ALWAYS: if not key: - key = django_csrf._get_new_csrf_key() + key = django_get_new_csrf_string() if not token: - token = django_csrf._get_new_csrf_key() + token = django_get_new_csrf_string() request._anon_csrf_key = key cache.set(prep_key(key), token, ANON_TIMEOUT) request.csrf_token = token @@ -81,7 +96,7 @@ def process_view(self, request, view_func, args, kwargs): return if (getattr(view_func, 'anonymous_csrf_exempt', False) - and not request.user.is_authenticated()): + and not is_user_authenticated(request)): return # Bail if this is a safe method. @@ -125,14 +140,14 @@ def anonymous_csrf(f): """Decorator that assigns a CSRF token to an anonymous user.""" @functools.wraps(f) def wrapper(request, *args, **kw): - use_anon_cookie = not (request.user.is_authenticated() or ANON_ALWAYS) + use_anon_cookie = not (is_user_authenticated(request) or ANON_ALWAYS) if use_anon_cookie: if ANON_COOKIE in request.COOKIES: key = request.COOKIES[ANON_COOKIE] - token = cache.get(prep_key(key)) or django_csrf._get_new_csrf_key() + token = cache.get(prep_key(key)) or django_get_new_csrf_string() else: - key = django_csrf._get_new_csrf_key() - token = django_csrf._get_new_csrf_key() + key = django_get_new_csrf_string() + token = django_get_new_csrf_string() cache.set(prep_key(key), token, ANON_TIMEOUT) request.csrf_token = token response = f(request, *args, **kw) diff --git a/session_csrf/tests.py b/session_csrf/tests.py index f4035b2..cb2b5a3 100644 --- a/session_csrf/tests.py +++ b/session_csrf/tests.py @@ -2,7 +2,7 @@ import django.test from django import http -from django.conf.urls import patterns +from django.conf.urls import url from django.contrib.auth import logout from django.contrib.auth.middleware import AuthenticationMiddleware from django.contrib.auth.models import User @@ -20,12 +20,12 @@ CsrfMiddleware, prep_key) -urlpatterns = patterns('', - ('^$', lambda r: http.HttpResponse()), - ('^anon$', anonymous_csrf(lambda r: http.HttpResponse())), - ('^no-anon-csrf$', anonymous_csrf_exempt(lambda r: http.HttpResponse())), - ('^logout$', anonymous_csrf(lambda r: logout(r) or http.HttpResponse())), -) +urlpatterns = [ + url('^$', lambda r: http.HttpResponse()), + url('^anon$', anonymous_csrf(lambda r: http.HttpResponse())), + url('^no-anon-csrf$', anonymous_csrf_exempt(lambda r: http.HttpResponse())), + url('^logout$', anonymous_csrf(lambda r: logout(r) or http.HttpResponse())), +] class TestCsrfToken(django.test.TestCase): diff --git a/setup.py b/setup.py index 362ec01..7208396 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='django-session-csrf', - version='0.6', + version='0.7.0', description='CSRF protection for Django without cookies.', long_description=open(os.path.join(ROOT, 'README.rst')).read(), author='Jeff Balogh',