I'm trying to create a simple login test using Django and Selenium, but getting a 403 due to a CSRF failure. I'm expecting the middleware to add the cookie on the GET request and then parse it back out on the POST.
Here's what I've checked so far:
1. Is the cookie being set on the GET request to /accounts/login/
?
Yes, the cookie is being set in the
process_response
method
2. Is the cookie available on the Selenium driver?
Yes
ipdb> self.selenium.get_cookies()
[{u'domain': u'localhost', u'name': u'csrftoken', u'value': u'DzNbEn9kZw0WZQ4OsRLouriFN5MOIQos', u'expiry': 1470691410, u'path': u'/', u'httpOnly': False, u'secure': True}]
3. Is the cookie found during the POST request?
No, this try/except from
django.middleware.CsrfViewMiddleware.process_view
fails:
source
try:
csrf_token = _sanitize_token(
request.COOKIES[settings.CSRF_COOKIE_NAME])
# Use same token next time
request.META['CSRF_COOKIE'] = csrf_token
except KeyError:
csrf_token = None
# Generate token and store it in the request, so it's
# available to the view.
request.META["CSRF_COOKIE"] = _get_new_csrf_key()
Code
class TestLogin(StaticLiveServerTestCase):
@classmethod
def setUpClass(cls):
cls.selenium = getattr(webdriver, settings.SELENIUM_WEBDRIVER)()
cls.selenium.maximize_window()
cls.selenium.implicitly_wait(5)
super(TestLogin, cls).setUpClass()
@classmethod
def tearDownClass(cls):
cls.selenium.quit()
super(TestLogin, cls).tearDownClass()
def test_login(self):
self.selenium.get('{}{}'.format(self.live_server_url, '/accounts/login/?next=/'))
assert "Django" in self.selenium.title
un_el = self.selenium.find_element_by_id('id_username').send_keys('the_un')
pw_el = self.selenium.find_element_by_id('id_password')
pw_el.send_keys('the_pw')
pw_el.send_keys(Keys.RETURN)
try:
WebDriverWait(self.selenium, 5).until(EC.title_contains("New Title"))
except TimeoutException as e:
msg = "Could not find 'New Title' in title. Current title: {}".format(self.selenium.title)
raise TimeoutException(msg)
finally:
self.selenium.quit()
Question
What can I try next to debug this?
This error message means that your browser couldn't create a secure cookie, or couldn't access that cookie to authorize your login. This can be caused by ad- or script-blocking plugins, but also by the browser itself if it's not allowed to set cookies.
Chrome. Open Chrome Settings. In the Privacy and security section, click Cookies and other site data. Scroll down to Sites that can always use cookies and click Add.
The CSRF token generated automatically by spring security when you logged in. It will be shown at the response header. The CSRF token can be used on subsequent request by setting X-CSRF-TOKEN with CSRF token on header.
Oldish question, but after getting stuck with this for a few hours the answer was simple.
From the docs:
If a browser connects initially via HTTP, which is the default for most browsers, it is possible for existing cookies to be leaked. For this reason, you should set your SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE settings to True. This instructs the browser to only send these cookies over HTTPS connections. Note that this will mean that sessions will not work over HTTP, and the CSRF protection will prevent any POST data being accepted over HTTP (which will be fine if you are redirecting all HTTP traffic to HTTPS).
Like me, you are probably using django_extensions + Werkzeug for the majority of your work, and are by default running all of your local work over SSL.
If you're using unittest
or Djangos version of it, I'd recommend that you modify these settings at test runtime, like so:
...
from django.conf import settings
class ProfilePagetest(LiveServerTestCase):
def setUp(self):
settings.CSRF_COOKIE_SECURE = False
settings.SESSION_COOKIE_SECURE = False
self.url = reverse('clientpage:profile')
self.username = '[email protected]'
self.password = 'strange decisions...'
get_user_model().objects.create_user(self.username, self.username, self.password)
self.browser = webdriver.Firefox()
This should stop the CSRF validation issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With