Skip to content
Snippets Groups Projects
Verified Commit e1ebd498 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Fixed inconsistencies between test and prod requests

parent de777764
No related branches found
No related tags found
No related merge requests found
......@@ -9,15 +9,17 @@ from . import actors
from . import keys
from . import serializers
from . import signing
from . import utils
class SignatureAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
def authenticate_actor(self, request):
headers = utils.clean_wsgi_headers(request.META)
try:
signature = request.META['headers']['Signature']
signature = headers['Signature']
key_id = keys.get_key_id_from_signature_header(signature)
except KeyError:
raise exceptions.AuthenticationFailed('No signature')
return
except ValueError as e:
raise exceptions.AuthenticationFailed(str(e))
......@@ -33,14 +35,17 @@ class SignatureAuthentication(authentication.BaseAuthentication):
serializer = serializers.ActorSerializer(data=actor_data)
if not serializer.is_valid():
raise exceptions.AuthenticationFailed('Invalid actor payload')
raise exceptions.AuthenticationFailed('Invalid actor payload: {}'.format(serializer.errors))
try:
signing.verify_django(request, public_key.encode('utf-8'))
except cryptography.exceptions.InvalidSignature:
raise exceptions.AuthenticationFailed('Invalid signature')
return serializer.build()
def authenticate(self, request):
actor = self.authenticate_actor(request)
user = AnonymousUser()
ac = serializer.build()
setattr(request, 'actor', ac)
setattr(request, 'actor', actor)
return (user, None)
import logging
import requests
import requests_http_signature
from . import exceptions
from . import utils
logger = logging.getLogger(__name__)
def verify(request, public_key):
return requests_http_signature.HTTPSignatureAuth.verify(
......@@ -15,21 +21,35 @@ def verify_django(django_request, public_key):
Given a django WSGI request, create an underlying requests.PreparedRequest
instance we can verify
"""
headers = django_request.META.get('headers', {}).copy()
headers = utils.clean_wsgi_headers(django_request.META)
for h, v in list(headers.items()):
# we include lower-cased version of the headers for compatibility
# with requests_http_signature
headers[h.lower()] = v
try:
signature = headers['signature']
signature = headers['Signature']
except KeyError:
raise exceptions.MissingSignature
url = 'http://noop{}'.format(django_request.path)
query = django_request.META['QUERY_STRING']
if query:
url += '?{}'.format(query)
signature_headers = signature.split('headers="')[1].split('",')[0]
expected = signature_headers.split(' ')
logger.debug('Signature expected headers: %s', expected)
for header in expected:
try:
headers[header]
except KeyError:
logger.debug('Missing header: %s', header)
request = requests.Request(
method=django_request.method,
url='http://noop',
url=url,
data=django_request.body,
headers=headers)
for h in request.headers.keys():
v = request.headers[h]
if v:
request.headers[h] = str(v)
prepared_request = request.prepare()
return verify(request, public_key)
......@@ -20,14 +20,17 @@ def test_authenticate(nodb_factories, mocker, api_request):
})
signed_request = nodb_factories['federation.SignedRequest'](
auth__key=private,
auth__key_id=actor_url + '#main-key'
auth__key_id=actor_url + '#main-key',
auth__headers=[
'date',
]
)
prepared = signed_request.prepare()
django_request = api_request.get(
'/',
headers={
'Date': prepared.headers['date'],
'Signature': prepared.headers['signature'],
**{
'HTTP_DATE': prepared.headers['date'],
'HTTP_SIGNATURE': prepared.headers['signature'],
}
)
authenticator = authentication.SignatureAuthentication()
......
......@@ -44,56 +44,67 @@ def test_verify_fails_with_wrong_key(nodb_factories):
signing.verify(prepared_request, wrong_public)
def test_can_verify_django_request(factories, api_request):
def test_can_verify_django_request(factories, fake_request):
private_key, public_key = keys.get_key_pair()
signed_request = factories['federation.SignedRequest'](
auth__key=private_key
auth__key=private_key,
auth__headers=[
'date',
]
)
prepared = signed_request.prepare()
django_request = api_request.get(
django_request = fake_request.get(
'/',
headers={
'Date': prepared.headers['date'],
'Signature': prepared.headers['signature'],
**{
'HTTP_DATE': prepared.headers['date'],
'HTTP_SIGNATURE': prepared.headers['signature'],
}
)
assert signing.verify_django(django_request, public_key) is None
def test_can_verify_django_request_digest(factories, api_request):
def test_can_verify_django_request_digest(factories, fake_request):
private_key, public_key = keys.get_key_pair()
signed_request = factories['federation.SignedRequest'](
auth__key=private_key,
method='post',
data=b'hello=world'
data=b'hello=world',
auth__headers=[
'date',
'digest',
]
)
prepared = signed_request.prepare()
django_request = api_request.post(
django_request = fake_request.post(
'/',
headers={
'Date': prepared.headers['date'],
'Digest': prepared.headers['digest'],
'Signature': prepared.headers['signature'],
**{
'HTTP_DATE': prepared.headers['date'],
'HTTP_DIGEST': prepared.headers['digest'],
'HTTP_SIGNATURE': prepared.headers['signature'],
}
)
assert signing.verify_django(django_request, public_key) is None
def test_can_verify_django_request_digest_failure(factories, api_request):
def test_can_verify_django_request_digest_failure(factories, fake_request):
private_key, public_key = keys.get_key_pair()
signed_request = factories['federation.SignedRequest'](
auth__key=private_key,
method='post',
data=b'hello=world'
data=b'hello=world',
auth__headers=[
'date',
'digest',
]
)
prepared = signed_request.prepare()
django_request = api_request.post(
django_request = fake_request.post(
'/',
headers={
'Date': prepared.headers['date'],
'Digest': prepared.headers['digest'] + 'noop',
'Signature': prepared.headers['signature'],
**{
'HTTP_DATE': prepared.headers['date'],
'HTTP_DIGEST': prepared.headers['digest'] + 'noop',
'HTTP_SIGNATURE': prepared.headers['signature'],
}
)
......@@ -101,17 +112,20 @@ def test_can_verify_django_request_digest_failure(factories, api_request):
signing.verify_django(django_request, public_key)
def test_can_verify_django_request_failure(factories, api_request):
def test_can_verify_django_request_failure(factories, fake_request):
private_key, public_key = keys.get_key_pair()
signed_request = factories['federation.SignedRequest'](
auth__key=private_key
auth__key=private_key,
auth__headers=[
'date',
]
)
prepared = signed_request.prepare()
django_request = api_request.get(
django_request = fake_request.get(
'/',
headers={
'Date': 'Wrong',
'Signature': prepared.headers['signature'],
**{
'HTTP_DATE': 'Wrong',
'HTTP_SIGNATURE': prepared.headers['signature'],
}
)
with pytest.raises(cryptography.exceptions.InvalidSignature):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment