handle redirects of signed requests manually, generate a new HTTP sig each time

fixes #326
pull/373/head
Ryan Barrett 2023-01-16 13:00:38 -08:00
rodzic 6860d49dd1
commit e6d4441292
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
4 zmienionych plików z 24 dodań i 6 usunięć

Wyświetl plik

@ -124,6 +124,7 @@ def signed_request(fn, url, data=None, user=None, headers=None, **kwargs):
logging.info(f'Sending AS2 object: {json_dumps(data, indent=2)}')
data = kwargs['data'] = json_dumps(data).encode()
headers = copy.deepcopy(headers)
headers.update({
# required for HTTP Signature
# https://tools.ietf.org/html/draft-cavage-http-signatures-07#section-2.1.3
@ -145,9 +146,13 @@ def signed_request(fn, url, data=None, user=None, headers=None, **kwargs):
# make HTTP request
kwargs.setdefault('gateway', True)
resp = fn(url, auth=auth, headers=headers, **kwargs)
resp = fn(url, auth=auth, headers=headers, allow_redirects=False, **kwargs)
logger.info(f'Got {resp.status_code} headers: {resp.headers}')
# handle redirects manually so that we generate a new HTTP signature
if resp.is_redirect:
return signed_request(fn, resp.headers['Location'], data=data, user=user,
headers=headers, **kwargs)
type = content_type(resp)
if (type and type != 'text/html' and
(type.startswith('text/') or type.endswith('+json') or type.endswith('/json'))):

Wyświetl plik

@ -168,3 +168,17 @@ class CommonTest(testutil.TestCase):
with app.test_request_context(base_url='http://bridgy-federated.uc.r.appspot.com'):
self.assertEqual('https://fed.brid.gy/asdf', common.host_url('asdf'))
@mock.patch('requests.get')
def test_signed_request_redirects_manually_with_new_sig_headers(self, mock_get):
mock_get.side_effect = [
requests_response(status=302, redirected_url='http://second',
allow_redirects=False),
requests_response(status=200, allow_redirects=False),
]
resp = common.signed_get('https://first')
first = mock_get.call_args_list[0][1]
second = mock_get.call_args_list[1][1]
self.assertNotEqual(first['headers'], second['headers'])
self.assertNotEqual(first['auth'].header_signer.sign(first['headers']),
second['auth'].header_signer.sign(second['headers']))

Wyświetl plik

@ -586,7 +586,7 @@ class WebmentionTest(testutil.TestCase):
self.req('http://a/reply'),
self.as2_req('http://not/fediverse'),
self.as2_req('http://orig/post'),
self.req('http://orig/as2', auth=mock.ANY, headers=as2.CONNEG_HEADERS),
self.as2_req('http://orig/as2', headers=as2.CONNEG_HEADERS),
self.as2_req('http://orig/author'),
))

Wyświetl plik

@ -45,17 +45,16 @@ class TestCase(unittest.TestCase, testutil.Asserts):
return call(url, **kwargs)
def as2_req(self, url, **kwargs):
# TODO: these aren't currently getting checked?!
headers = {
'Date': 'Wed, 23 Nov 2022 22:29:19 GMT',
'Date': 'Sun, 02 Jan 2022 03:04:05 GMT',
'Host': util.domain_from_link(url, minimize=False),
'Content-Type': 'application/activity+json',
'Digest': ANY,
**common.CONNEG_HEADERS_AS2_HTML,
**kwargs.pop('headers', {}),
}
return self.req(url, auth=ANY, headers=headers, **kwargs)
return self.req(url, auth=ANY, headers=headers, allow_redirects=False,
**kwargs)
def as2_resp(self, obj):
return requests_response(obj, content_type=as2.CONTENT_TYPE)