From d84475b7f996e47897c790c7f11934801e24e526 Mon Sep 17 00:00:00 2001 From: Emmanuel Cazenave Date: Thu, 1 Nov 2018 13:18:20 +0100 Subject: [PATCH] allow cookies usage in endpoint requests (#27654) --- passerelle/utils/__init__.py | 5 +++-- passerelle/views.py | 2 ++ tests/test_generic_endpoint.py | 28 ++++++++++++++++++++++++++++ tests/test_requests.py | 19 +++++++++++++++++++ tox.ini | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/passerelle/utils/__init__.py b/passerelle/utils/__init__.py index 815fe79..d5df1b6 100644 --- a/passerelle/utils/__init__.py +++ b/passerelle/utils/__init__.py @@ -214,8 +214,9 @@ class Request(RequestSession): if 'timeout' not in kwargs: kwargs['timeout'] = settings.REQUESTS_TIMEOUT - # don't use persistent cookies - self.cookies.clear() + if self.resource and hasattr(self.resource, 'cookiejar'): + # use cookies that will last the whole endpoint duration + self.cookies = self.resource.cookiejar response = super(Request, self).request(method, url, **kwargs) diff --git a/passerelle/views.py b/passerelle/views.py index 33b8ccc..6221a41 100644 --- a/passerelle/views.py +++ b/passerelle/views.py @@ -22,6 +22,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import force_text from django.forms.models import modelform_factory from django.forms.widgets import ClearableFileInput +import requests from dateutil import parser as date_parser @@ -287,6 +288,7 @@ class GenericEndpointView(GenericConnectorMixin, SingleObjectMixin, View): def dispatch(self, request, *args, **kwargs): self.init_stuff(request, *args, **kwargs) connector = self.get_object() + connector.cookiejar = requests.cookies.cookiejar_from_dict({}) self.endpoint = None endpoints = [] for name, method in inspect.getmembers(connector): diff --git a/tests/test_generic_endpoint.py b/tests/test_generic_endpoint.py index 664ab80..f8abae9 100644 --- a/tests/test_generic_endpoint.py +++ b/tests/test_generic_endpoint.py @@ -295,3 +295,31 @@ def test_endpoint_cache(app, db, monkeypatch): assert cache.get_calls == 5 assert cache.set_calls == 3 assert resp1.json_body != resp6.json_body + + +def test_endpoint_cookies(app, db, monkeypatch, httpbin): + + @endpoint(methods=['get']) + def httpcall(obj, request): + response = obj.requests.get(httpbin.url + '/cookies/set?foo=bar', allow_redirects=False) + cookie1 = response.request.headers.get('Cookie') + response = obj.requests.get(httpbin.url + '/get') + cookie2 = response.request.headers.get('Cookie') + return { + 'cookie1': cookie1, + 'cookie2': cookie2 + } + + monkeypatch.setattr(StubInvoicesConnector, 'httpcall', httpcall, raising=False) + + connector = StubInvoicesConnector(slug='fake') + connector.save() + + json_res = app.get('/stub-invoices/fake/httpcall').json + assert json_res['cookie1'] is None + assert json_res['cookie2'] == 'foo=bar' + # Do it a second time to test that no cookies are leaking from one call + # to the other + json_res = app.get('/stub-invoices/fake/httpcall').json + assert json_res['cookie1'] is None + assert json_res['cookie2'] == 'foo=bar' diff --git a/tests/test_requests.py b/tests/test_requests.py index 60bba9c..76d099f 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -6,6 +6,7 @@ import mock from httmock import urlmatch, HTTMock, response from django.test import override_settings +import requests from passerelle.utils import Request, CaseInsensitiveDict from passerelle.utils.http_authenticators import HawkAuth @@ -327,3 +328,21 @@ def test_timeout(mocked_get, caplog, endpoint_response): assert mocked_get.call_args[1]['timeout'] == 42 Request(logger=logger).get('http://example.net/whatever', timeout=None) assert mocked_get.call_args[1]['timeout'] is None + + +def test_requests_cookies(httpbin): + resource = MockResource() + resource.cookiejar = requests.cookies.cookiejar_from_dict({}) + logger = logging.getLogger('requests') + request = Request(resource=resource, logger=logger) + + request.get(httpbin.url + '/cookies/set?foo=bar') + + # cookies are sent back + response = request.get(httpbin.url + '/get') + assert response.request.headers['Cookie'] == 'foo=bar' + + # cookies sent back even with a new Request obj + request = Request(resource=resource, logger=logger) + response = request.get(httpbin.url + '/get') + assert response.request.headers['Cookie'] == 'foo=bar' diff --git a/tox.ini b/tox.ini index 8b050e2..9635f85 100644 --- a/tox.ini +++ b/tox.ini @@ -25,6 +25,7 @@ deps = lxml mohawk pytest-freezegun + pytest-httpbin commands = django18: py.test {posargs: {env:FAST:} --junitxml=test_{envname}_results.xml --cov-report xml --cov-report html --cov=passerelle/ --cov-config .coveragerc tests/} django18: ./pylint.sh passerelle/ -- 2.19.1