2015-08-10 8 views
4

Я пытаюсь создать простой тест входа, используя Django и Selenium, но получаю 403 из-за сбоя CSRF. Я ожидаю, что промежуточное ПО добавит файл cookie в запрос GET, а затем проанализирует его на POST.Почему Selenium вызывает CSRF 403?

Вот что я проверил до сих пор:

1. Является ли печенье быть установлен на запрос GET к /accounts/login/?

Да, печенье создается в process_response методом

2. Является ли куки доступны на драйвере Selenium?

Да

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. Является ли печенье найден во время запроса POST?

Нет, это попытка/за исключением из django.middleware.CsrfViewMiddleware.process_view не удается:

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() 

Код

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() 

Вопрос

Что я могу попробовать, чтобы отладить это?

ответ

1

Одинокий вопрос, но после того, как вы застряли с этим в течение нескольких часов, ответ был прост.

От docs:

Если браузер подключается сначала через HTTP, который является по умолчанию для большинства браузеров, возможно существующих куки утечка. Для этой причине вы должны установить для параметров SESSION_COOKIE_SECURE и CSRF_COOKIE_SECURE значение True. Это указывает браузеру отправлять только эти файлы cookie через соединения HTTPS. Обратите внимание, что это будет означает, что сеансы не будут работать через HTTP, а защита CSRF предотвратит прием любых POST-данных по HTTP (что будет штрафом, если вы перенаправляете весь HTTP-трафик на HTTPS).

Как и я, вы, вероятно, с помощью django_extensions + Werkzeug для большинства вашей работы, и по умолчанию работает все вашей локальной работы над SSL.

Если вы используете unittest или версию Djangos этого, я бы рекомендовал вам изменить эти настройки в тестовом режиме исполнения, например, так:

... 
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() 

Это должно остановить вопросы проверки CSRF.

+1

Я бы использовал декоратор djangos override_settings, чтобы гарантировать, что настройки будут сброшены после выполнения теста. https://docs.djangoproject.com/ru/1.9/topics/testing/tools/#django.test.override_settings –

Смежные вопросы