diff --git a/courseware/views.py b/courseware/views.py index 8a40e5e9be91099ddabbc35c058b269a7e630b26..62ba58bae22b58d185c94dde587354b036f3b4d5 100644 --- a/courseware/views.py +++ b/courseware/views.py @@ -13,6 +13,7 @@ from django.http import HttpResponse, Http404 from django.shortcuts import redirect from django.template import Context, loader from mitxmako.shortcuts import render_to_response, render_to_string +#from django.views.decorators.csrf import ensure_csrf_cookie from django.db import connection from lxml import etree diff --git a/django_future/__init__.py b/django_future/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/django_future/csrf.py b/django_future/csrf.py new file mode 100644 index 0000000000000000000000000000000000000000..ba5c3a7791df152771ab06f68ba3f22b9c347eb1 --- /dev/null +++ b/django_future/csrf.py @@ -0,0 +1,81 @@ +# Taken from Django 1.4 + +import warnings + +from django.middleware.csrf import CsrfViewMiddleware, get_token +from django.utils.decorators import decorator_from_middleware, available_attrs +from functools import wraps + +csrf_protect = decorator_from_middleware(CsrfViewMiddleware) +csrf_protect.__name__ = "csrf_protect" +csrf_protect.__doc__ = """ +This decorator adds CSRF protection in exactly the same way as +CsrfViewMiddleware, but it can be used on a per view basis. Using both, or +using the decorator multiple times, is harmless and efficient. +""" + + +class _EnsureCsrfToken(CsrfViewMiddleware): + # We need this to behave just like the CsrfViewMiddleware, but not reject + # requests. + def _reject(self, request, reason): + return None + + +requires_csrf_token = decorator_from_middleware(_EnsureCsrfToken) +requires_csrf_token.__name__ = 'requires_csrf_token' +requires_csrf_token.__doc__ = """ +Use this decorator on views that need a correct csrf_token available to +RequestContext, but without the CSRF protection that csrf_protect +enforces. +""" + + +class _EnsureCsrfCookie(CsrfViewMiddleware): + def _reject(self, request, reason): + return None + + def process_view(self, request, callback, callback_args, callback_kwargs): + retval = super(_EnsureCsrfCookie, self).process_view(request, callback, callback_args, callback_kwargs) + # Forces process_response to send the cookie + get_token(request) + return retval + + +ensure_csrf_cookie = decorator_from_middleware(_EnsureCsrfCookie) +ensure_csrf_cookie.__name__ = 'ensure_csrf_cookie' +ensure_csrf_cookie.__doc__ = """ +Use this decorator to ensure that a view sets a CSRF cookie, whether or not it +uses the csrf_token template tag, or the CsrfViewMiddleware is used. +""" + + +def csrf_response_exempt(view_func): + """ + Modifies a view function so that its response is exempt + from the post-processing of the CSRF middleware. + """ + warnings.warn("csrf_response_exempt is deprecated. It no longer performs a " + "function, and calls to it can be removed.", + PendingDeprecationWarning) + return view_func + +def csrf_view_exempt(view_func): + """ + Marks a view function as being exempt from CSRF view protection. + """ + warnings.warn("csrf_view_exempt is deprecated. Use csrf_exempt instead.", + PendingDeprecationWarning) + return csrf_exempt(view_func) + +def csrf_exempt(view_func): + """ + Marks a view function as being exempt from the CSRF view protection. + """ + # We could just do view_func.csrf_exempt = True, but decorators + # are nicer if they don't have side-effects, so we return a new + # function. + def wrapped_view(*args, **kwargs): + return view_func(*args, **kwargs) + wrapped_view.csrf_exempt = True + return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) diff --git a/student/views.py b/student/views.py index 0ccf51dbb56bd302d66df7dccffc966bf43450fc..b00986ad158d8c06338ee4f107eeb29ecaec5789 100644 --- a/student/views.py +++ b/student/views.py @@ -15,6 +15,7 @@ from django.shortcuts import redirect from mitxmako.shortcuts import render_to_response, render_to_string from models import Registration, UserProfile +from django_future.csrf import ensure_csrf_cookie log = logging.getLogger("mitx.user") @@ -24,7 +25,7 @@ def csrf_token(context): return '' return u'<div style="display:none"><input type="hidden" name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token) - +@ensure_csrf_cookie def index(request): if settings.COURSEWARE_ENABLED and request.user.is_authenticated(): return redirect('/courseware') @@ -44,6 +45,7 @@ def index(request): # 'csrf': csrf_token }) # Need different levels of logging +@ensure_csrf_cookie def login_user(request, error=""): if 'email' not in request.POST or 'password' not in request.POST: return render_to_response('login.html', {'error':error.replace('+',' ')}) @@ -83,11 +85,13 @@ def login_user(request, error=""): return HttpResponse(json.dumps({'success':False, 'error': 'Account not active. Check your e-mail.'})) +@ensure_csrf_cookie def logout_user(request): logout(request) # print len(connection.queries), connection.queries return redirect('/') +@ensure_csrf_cookie def change_setting(request): if not request.user.is_authenticated(): return redirect('/') @@ -104,6 +108,7 @@ def change_setting(request): 'language':up.language, 'location':up.location,})) +@ensure_csrf_cookie def create_account(request, post_override=None): js={'success':False} @@ -221,6 +226,7 @@ def create_random_account(create_account_function): if settings.GENERATE_RANDOM_USER_CREDENTIALS: create_account = create_random_account(create_account) +@ensure_csrf_cookie def activate_account(request, key): r=Registration.objects.filter(activation_key=key) if len(r)==1: @@ -232,6 +238,7 @@ def activate_account(request, key): return render_to_response("activation_invalid.html",{'csrf':csrf(request)['csrf_token']}) return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.") +@ensure_csrf_cookie def password_reset(request): ''' Attempts to send a password reset e-mail. ''' if request.method != "POST":