Commit c3c35f07 by Régis Behmo

Fix csrf error on studio login

Context: We have witnessed multiple, seemingly random "CSRF verification
failed" errors while signing in (with valid ID) to the Studio.

Explanation: The login form does not initially include a CSRF field.
The CSRF header of the request is appended to the studio login request
headers by intercepting the form validation. This intercept is performed
by the login.js script. Unfortunately, the login.js script is loaded
pretty late (at the end of the template). So if the login form is
validated sufficiently fast, the login.js script has no time to load and
append the X-CSRFToken header to the request.

Proposed solution: the CSRF token is already passed to the template via
the login view, so we just add a hidden field to the login form to
include the csrf token.
parent a260579a
......@@ -4,7 +4,7 @@ import copy
import mock
from mock import patch
import shutil
import lxml
import lxml.html
from datetime import timedelta
from fs.osfs import OSFS
......@@ -26,7 +26,7 @@ from contentstore.views.component import ADVANCED_COMPONENT_TYPES
from xmodule.contentstore.django import contentstore
from xmodule.contentstore.utils import restore_asset_from_trashcan, empty_asset_trashcan
from xmodule.exceptions import NotFoundError, InvalidVersionError
from xmodule.exceptions import InvalidVersionError
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.inheritance import own_metadata
......@@ -1747,6 +1747,35 @@ class EntryPageTestCase(TestCase):
self._test_page("/logout", 302)
class SigninPageTestCase(TestCase):
"""
Tests that the CSRF token is directly included in the signin form. This is
important to make sure that the script is functional independently of any
other script.
"""
def test_csrf_token_is_present_in_form(self):
# Expected html:
# <form>
# ...
# <fieldset>
# ...
# <input name="csrfmiddlewaretoken" value="...">
# ...
# </fieldset>
# ...
#</form>
response = self.client.get("/signin")
csrf_token = response.cookies.get("csrftoken")
form = lxml.html.fromstring(response.content).get_element_by_id("login_form")
csrf_input_field = form.find(".//input[@name='csrfmiddlewaretoken']")
self.assertIsNotNone(csrf_token)
self.assertIsNotNone(csrf_token.value)
self.assertIsNotNone(csrf_input_field)
self.assertEqual(csrf_token.value, csrf_input_field.attrib["value"])
def _create_course(test, course_key, course_data):
"""
Creates a course via an AJAX request and verifies the URL returned in the response.
......
......@@ -8,7 +8,6 @@ define(['jquery.cookie', 'utility'], function() {
dataType: 'json',
data: data,
success: callback,
headers : {'X-CSRFToken':$.cookie('csrftoken')}
});
}
......
......@@ -21,6 +21,7 @@ from django.utils.translation import ugettext as _
<fieldset>
<legend class="sr">${_("Required Information to Sign In to {studio_name}").format(studio_name=settings.STUDIO_NAME)}</legend>
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf }" />
<ol class="list-input">
<li class="field text required" id="field-email">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment