From 546336acc75f1922929b01b88463d54d568a5eea Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 5 Aug 2019 18:57:06 +0200 Subject: [PATCH] requests_wrapper: sign URL of prepared requests (#35225) --- combo/utils/requests_wrapper.py | 14 ++++++++++++-- tests/test_lingo_remote_regie.py | 24 ++++++++++++------------ tests/test_newsletters_cell.py | 12 ++++++------ tests/test_requests.py | 28 ++++++++++++++-------------- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/combo/utils/requests_wrapper.py b/combo/utils/requests_wrapper.py index 38827c2..aecdec1 100644 --- a/combo/utils/requests_wrapper.py +++ b/combo/utils/requests_wrapper.py @@ -18,6 +18,7 @@ import hashlib import logging from requests import Response, Session as RequestsSession +from requests.auth import AuthBase from django.conf import settings from django.core.cache import cache @@ -32,6 +33,15 @@ class NothingInCacheException(Exception): pass +class PublikSignature(AuthBase): + def __init__(self, secret): + self.secret = secret + + def __call__(self, request): + request.url = sign_url(request.url, self.secret) + return request + + class Requests(RequestsSession): def request(self, method, url, **kwargs): @@ -117,8 +127,8 @@ class Requests(RequestsSession): elif raise_if_not_cached: raise NothingInCacheException() - if remote_service: # sign - url = sign_url(url, remote_service.get('secret')) + if remote_service: # sign + kwargs['auth'] = PublikSignature(remote_service.get('secret')) kwargs['timeout'] = kwargs.get('timeout') or settings.REQUESTS_TIMEOUT diff --git a/tests/test_lingo_remote_regie.py b/tests/test_lingo_remote_regie.py index b26240d..355bb07 100644 --- a/tests/test_lingo_remote_regie.py +++ b/tests/test_lingo_remote_regie.py @@ -83,8 +83,8 @@ class MockUser(object): return 'r2d2' -@mock.patch('combo.utils.requests_wrapper.RequestsSession.request') -def test_remote_regie_active_invoices_cell(mock_request, remote_regie): +@mock.patch('combo.utils.requests_wrapper.RequestsSession.send') +def test_remote_regie_active_invoices_cell(mock_send, remote_regie): assert remote_regie.is_remote() == True page = Page(title='xxx', slug='test_basket_cell', template_name='standard') @@ -103,15 +103,15 @@ def test_remote_regie_active_invoices_cell(mock_request, remote_regie): ws_invoices = {'err': 0, 'data': INVOICES} mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response.json.return_value = ws_invoices - mock_request.return_value = mock_response + mock_send.return_value = mock_response content = cell.render(context) assert 'F-2016-One' in content assert '123.45' in content assert '?page=%s' % page.pk in content # check if regie webservice has been correctly called - assert mock_request.call_args[0][0] == 'GET' - url = mock_request.call_args[0][1] + assert mock_send.call_args[0][0].method == 'GET' + url = mock_send.call_args[0][0].url scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) assert scheme == 'http' assert netloc == 'example.org' @@ -125,12 +125,12 @@ def test_remote_regie_active_invoices_cell(mock_request, remote_regie): ws_invoices = {'err': 0, 'data': []} mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response.json.return_value = ws_invoices - mock_request.return_value = mock_response + mock_send.return_value = mock_response content = cell.render(context) assert 'No items yet' in content -@mock.patch('combo.utils.requests_wrapper.RequestsSession.request') -def test_remote_regie_past_invoices_cell(mock_request, remote_regie): +@mock.patch('combo.utils.requests_wrapper.RequestsSession.send') +def test_remote_regie_past_invoices_cell(mock_send, remote_regie): assert remote_regie.is_remote() == True page = Page(title='xxx', slug='test_basket_cell', template_name='standard') @@ -149,14 +149,14 @@ def test_remote_regie_past_invoices_cell(mock_request, remote_regie): ws_invoices = {'err': 0, 'data': INVOICES} mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response.json.return_value = ws_invoices - mock_request.return_value = mock_response + mock_send.return_value = mock_response content = cell.render(context) assert 'F-2016-One' in content assert '123.45' in content # check if regie webservice has been correctly called - assert mock_request.call_args[0][0] == 'GET' - url = mock_request.call_args[0][1] + assert mock_send.call_args[0][0].method == 'GET' + url = mock_send.call_args[0][0].url scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) assert scheme == 'http' assert netloc == 'example.org' @@ -170,7 +170,7 @@ def test_remote_regie_past_invoices_cell(mock_request, remote_regie): ws_invoices = {'err': 0, 'data': []} mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response.json.return_value = ws_invoices - mock_request.return_value = mock_response + mock_send.return_value = mock_response content = cell.render(context) assert 'No items yet' in content diff --git a/tests/test_newsletters_cell.py b/tests/test_newsletters_cell.py index 3071978..4e4f349 100644 --- a/tests/test_newsletters_cell.py +++ b/tests/test_newsletters_cell.py @@ -10,6 +10,7 @@ from django.contrib.auth.models import User from combo.data.models import Page from combo.apps.newsletters.models import NewslettersCell, SubscriptionsSaveError from combo.apps.newsletters.forms import NewslettersManageForm +from combo.utils import check_query pytestmark = pytest.mark.django_db @@ -147,8 +148,8 @@ def test_get_subscriptions(mock_get, cell, user): assert cell.get_subscriptions(user) == expected_subscriptions assert mock_get.call_args[1]['user'].email == USER_EMAIL -@mock.patch('combo.utils.requests_wrapper.RequestsSession.request') -def test_get_subscriptions_signature_check(mock_get, cell, user): +@mock.patch('combo.utils.requests_wrapper.RequestsSession.send') +def test_get_subscriptions_signature_check(mock_send, cell, user): restrictions = ('mail', 'sms') cell.transports_restrictions = ','.join(restrictions) expected_subscriptions = [] @@ -160,11 +161,10 @@ def test_get_subscriptions_signature_check(mock_get, cell, user): mock_json = mock.Mock(status_code=200) mock_json.json.return_value = {'err': 0, 'data': SUBSCRIPTIONS} - mock_get.return_value = mock_json + mock_send.return_value = mock_json cell.get_subscriptions(user) - assert 'orig=combo' in mock_get.call_args[0][1] - assert 'signature=' in mock_get.call_args[0][1] - assert 'nonce=' in mock_get.call_args[0][1] + url = mock_send.call_args[0][0].url + assert check_query(url.split('?', 1)[-1], 'combo') def mocked_requests_connection_error(*args, **kwargs): diff --git a/tests/test_requests.py b/tests/test_requests.py index 4d3b3a0..a116cd0 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -23,15 +23,15 @@ class MockUser(object): def test_nosign(): - with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request: + with mock.patch('combo.utils.requests_wrapper.RequestsSession.send') as send: requests.get('http://example.org/foo/bar/') - assert request.call_args[0][1] == 'http://example.org/foo/bar/' + assert send.call_args[0][0].url == 'http://example.org/foo/bar/' def test_sign(): remote_service = {'url': 'http://example.org', 'secret': 'secret', 'orig': 'myself'} - with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request: + with mock.patch('combo.utils.requests_wrapper.RequestsSession.send') as send: requests.get('/foo/bar/', remote_service=remote_service) - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) @@ -41,7 +41,7 @@ def test_sign(): assert check_query(querystring, 'secret') == True requests.get('/foo/bar/', remote_service=remote_service, without_user=True) - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) @@ -52,9 +52,9 @@ def test_sign(): def test_auto_sign(): - with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request: + with mock.patch('combo.utils.requests_wrapper.RequestsSession.send') as send: requests.get('http://example.org/foo/bar/', remote_service='auto') - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) @@ -62,17 +62,17 @@ def test_auto_sign(): assert check_query(querystring, 'combo') == True requests.get('http://doesnotexist/foo/bar/', remote_service='auto') - assert request.call_args[0][1] == 'http://doesnotexist/foo/bar/' + assert send.call_args[0][0].url == 'http://doesnotexist/foo/bar/' def test_sign_user(): remote_service = {'url': 'http://example.org', 'secret': 'secret', 'orig': 'myself'} - with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request: + with mock.patch('combo.utils.requests_wrapper.RequestsSession.send') as send: user = MockUser(samlized=True) requests.get('/foo/bar/', remote_service=remote_service, user=user) - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) @@ -83,7 +83,7 @@ def test_sign_user(): requests.get('/foo/bar/', remote_service=remote_service, user=user, federation_key='email') - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) @@ -96,7 +96,7 @@ def test_sign_user(): user = MockUser(samlized=False) requests.get('/foo/bar/', remote_service=remote_service, user=user) - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) @@ -108,12 +108,12 @@ def test_sign_user(): def test_sign_anonymous_user(): remote_service = {'url': 'http://example.org', 'secret': 'secret', 'orig': 'myself'} - with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request: + with mock.patch('combo.utils.requests_wrapper.RequestsSession.send') as send: user = AnonymousUser() requests.get('/foo/bar/', remote_service=remote_service, user=user) - url = request.call_args[0][1] + url = send.call_args[0][0].url assert url.startswith('http://example.org/foo/bar/?') scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) query = urlparse.parse_qs(querystring, keep_blank_values=True) -- 2.22.0