requests_wrapper: sign URL of prepared requests (#35225)
gitea-wip/combo/pipeline/head Build started... Details
gitea/combo/pipeline/head Build started... Details

This commit is contained in:
Benjamin Dauvergne 2019-08-05 18:57:06 +02:00 committed by Serghei Mihai
parent ce2210a108
commit b29f723540
4 changed files with 44 additions and 34 deletions

View File

@ -18,6 +18,7 @@ import hashlib
import logging import logging
from requests import Response, Session as RequestsSession from requests import Response, Session as RequestsSession
from requests.auth import AuthBase
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
@ -32,6 +33,15 @@ class NothingInCacheException(Exception):
pass 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): class Requests(RequestsSession):
def request(self, method, url, **kwargs): def request(self, method, url, **kwargs):
@ -117,8 +127,8 @@ class Requests(RequestsSession):
elif raise_if_not_cached: elif raise_if_not_cached:
raise NothingInCacheException() raise NothingInCacheException()
if remote_service: # sign if remote_service: # sign
url = sign_url(url, remote_service.get('secret')) kwargs['auth'] = PublikSignature(remote_service.get('secret'))
kwargs['timeout'] = kwargs.get('timeout') or settings.REQUESTS_TIMEOUT kwargs['timeout'] = kwargs.get('timeout') or settings.REQUESTS_TIMEOUT

View File

@ -83,8 +83,8 @@ class MockUser(object):
return 'r2d2' return 'r2d2'
@mock.patch('combo.utils.requests_wrapper.RequestsSession.request') @mock.patch('combo.utils.requests_wrapper.RequestsSession.send')
def test_remote_regie_active_invoices_cell(mock_request, remote_regie): def test_remote_regie_active_invoices_cell(mock_send, remote_regie):
assert remote_regie.is_remote() == True assert remote_regie.is_remote() == True
page = Page(title='xxx', slug='test_basket_cell', template_name='standard') 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} ws_invoices = {'err': 0, 'data': INVOICES}
mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices))
mock_response.json.return_value = 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) content = cell.render(context)
assert 'F-2016-One' in content assert 'F-2016-One' in content
assert '123.45' in content assert '123.45' in content
assert '?page=%s' % page.pk in content assert '?page=%s' % page.pk in content
# check if regie webservice has been correctly called # check if regie webservice has been correctly called
assert mock_request.call_args[0][0] == 'GET' assert mock_send.call_args[0][0].method == 'GET'
url = mock_request.call_args[0][1] url = mock_send.call_args[0][0].url
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
assert scheme == 'http' assert scheme == 'http'
assert netloc == 'example.org' assert netloc == 'example.org'
@ -125,12 +125,12 @@ def test_remote_regie_active_invoices_cell(mock_request, remote_regie):
ws_invoices = {'err': 0, 'data': []} ws_invoices = {'err': 0, 'data': []}
mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices))
mock_response.json.return_value = 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) content = cell.render(context)
assert 'No items yet' in content assert 'No items yet' in content
@mock.patch('combo.utils.requests_wrapper.RequestsSession.request') @mock.patch('combo.utils.requests_wrapper.RequestsSession.send')
def test_remote_regie_past_invoices_cell(mock_request, remote_regie): def test_remote_regie_past_invoices_cell(mock_send, remote_regie):
assert remote_regie.is_remote() == True assert remote_regie.is_remote() == True
page = Page(title='xxx', slug='test_basket_cell', template_name='standard') 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} ws_invoices = {'err': 0, 'data': INVOICES}
mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices))
mock_response.json.return_value = 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) content = cell.render(context)
assert 'F-2016-One' in content assert 'F-2016-One' in content
assert '123.45' in content assert '123.45' in content
# check if regie webservice has been correctly called # check if regie webservice has been correctly called
assert mock_request.call_args[0][0] == 'GET' assert mock_send.call_args[0][0].method == 'GET'
url = mock_request.call_args[0][1] url = mock_send.call_args[0][0].url
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
assert scheme == 'http' assert scheme == 'http'
assert netloc == 'example.org' assert netloc == 'example.org'
@ -170,7 +170,7 @@ def test_remote_regie_past_invoices_cell(mock_request, remote_regie):
ws_invoices = {'err': 0, 'data': []} ws_invoices = {'err': 0, 'data': []}
mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices))
mock_response.json.return_value = 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) content = cell.render(context)
assert 'No items yet' in content assert 'No items yet' in content

View File

@ -10,6 +10,7 @@ from django.contrib.auth.models import User
from combo.data.models import Page from combo.data.models import Page
from combo.apps.newsletters.models import NewslettersCell, SubscriptionsSaveError from combo.apps.newsletters.models import NewslettersCell, SubscriptionsSaveError
from combo.apps.newsletters.forms import NewslettersManageForm from combo.apps.newsletters.forms import NewslettersManageForm
from combo.utils import check_query
pytestmark = pytest.mark.django_db 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 cell.get_subscriptions(user) == expected_subscriptions
assert mock_get.call_args[1]['user'].email == USER_EMAIL assert mock_get.call_args[1]['user'].email == USER_EMAIL
@mock.patch('combo.utils.requests_wrapper.RequestsSession.request') @mock.patch('combo.utils.requests_wrapper.RequestsSession.send')
def test_get_subscriptions_signature_check(mock_get, cell, user): def test_get_subscriptions_signature_check(mock_send, cell, user):
restrictions = ('mail', 'sms') restrictions = ('mail', 'sms')
cell.transports_restrictions = ','.join(restrictions) cell.transports_restrictions = ','.join(restrictions)
expected_subscriptions = [] 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 = mock.Mock(status_code=200)
mock_json.json.return_value = {'err': 0, mock_json.json.return_value = {'err': 0,
'data': SUBSCRIPTIONS} 'data': SUBSCRIPTIONS}
mock_get.return_value = mock_json mock_send.return_value = mock_json
cell.get_subscriptions(user) cell.get_subscriptions(user)
assert 'orig=combo' in mock_get.call_args[0][1] url = mock_send.call_args[0][0].url
assert 'signature=' in mock_get.call_args[0][1] assert check_query(url.split('?', 1)[-1], 'combo')
assert 'nonce=' in mock_get.call_args[0][1]
def mocked_requests_connection_error(*args, **kwargs): def mocked_requests_connection_error(*args, **kwargs):

View File

@ -23,15 +23,15 @@ class MockUser(object):
def test_nosign(): 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/') 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(): def test_sign():
remote_service = {'url': 'http://example.org', 'secret': 'secret', 'orig': 'myself'} 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) 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/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) query = urlparse.parse_qs(querystring, keep_blank_values=True)
@ -41,7 +41,7 @@ def test_sign():
assert check_query(querystring, 'secret') == True assert check_query(querystring, 'secret') == True
requests.get('/foo/bar/', remote_service=remote_service, without_user=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/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) query = urlparse.parse_qs(querystring, keep_blank_values=True)
@ -52,9 +52,9 @@ def test_sign():
def test_auto_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') 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/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) query = urlparse.parse_qs(querystring, keep_blank_values=True)
@ -62,17 +62,17 @@ def test_auto_sign():
assert check_query(querystring, 'combo') == True assert check_query(querystring, 'combo') == True
requests.get('http://doesnotexist/foo/bar/', remote_service='auto') 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(): def test_sign_user():
remote_service = {'url': 'http://example.org', 'secret': 'secret', 'orig': 'myself'} 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) user = MockUser(samlized=True)
requests.get('/foo/bar/', remote_service=remote_service, user=user) 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/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) 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, requests.get('/foo/bar/', remote_service=remote_service, user=user,
federation_key='email') federation_key='email')
url = request.call_args[0][1] url = send.call_args[0][0].url
assert url.startswith('http://example.org/foo/bar/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) query = urlparse.parse_qs(querystring, keep_blank_values=True)
@ -96,7 +96,7 @@ def test_sign_user():
user = MockUser(samlized=False) user = MockUser(samlized=False)
requests.get('/foo/bar/', remote_service=remote_service, user=user) 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/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) query = urlparse.parse_qs(querystring, keep_blank_values=True)
@ -108,12 +108,12 @@ def test_sign_user():
def test_sign_anonymous_user(): def test_sign_anonymous_user():
remote_service = {'url': 'http://example.org', 'secret': 'secret', 'orig': 'myself'} 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() user = AnonymousUser()
requests.get('/foo/bar/', remote_service=remote_service, user=user) 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/?') assert url.startswith('http://example.org/foo/bar/?')
scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url) scheme, netloc, path, params, querystring, fragment = urlparse.urlparse(url)
query = urlparse.parse_qs(querystring, keep_blank_values=True) query = urlparse.parse_qs(querystring, keep_blank_values=True)