Basic logic for signing/verifying requests

This commit is contained in:
Eliot Berriot 2018-03-24 15:20:15 +01:00
parent ae65190364
commit aa7365b71f
No known key found for this signature in database
GPG Key ID: DD6965E2476E5C27
7 changed files with 98 additions and 2 deletions

View File

@ -89,6 +89,7 @@ LOCAL_APPS = (
'funkwhale_api.music',
'funkwhale_api.requests',
'funkwhale_api.favorites',
'funkwhale_api.federation',
'funkwhale_api.radios',
'funkwhale_api.history',
'funkwhale_api.playlists',

View File

View File

@ -0,0 +1,30 @@
import factory
import requests
import requests_http_signature
from funkwhale_api.factories import registry
from . import signing
registry.register(signing.get_key_pair, name='federation.KeyPair')
@registry.register(name='federation.SignatureAuth')
class SignatureAuthFactory(factory.Factory):
algorithm = 'rsa-sha256'
key = factory.LazyFunction(lambda: signing.get_key_pair()[0])
key_id = factory.Faker('url')
class Meta:
model = requests_http_signature.HTTPSignatureAuth
@registry.register(name='federation.SignedRequest')
class SignedRequestFactory(factory.Factory):
url = factory.Faker('url')
method = 'get'
auth = factory.SubFactory(SignatureAuthFactory)
class Meta:
model = requests.Request

View File

@ -0,0 +1,21 @@
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend as crypto_default_backend
def get_key_pair(size=2048):
key = rsa.generate_private_key(
backend=crypto_default_backend(),
public_exponent=65537,
key_size=size
)
private_key = key.private_bytes(
crypto_serialization.Encoding.PEM,
crypto_serialization.PrivateFormat.PKCS8,
crypto_serialization.NoEncryption())
public_key = key.public_key().public_bytes(
crypto_serialization.Encoding.PEM,
crypto_serialization.PublicFormat.PKCS1
)
return private_key, public_key

View File

@ -60,3 +60,5 @@ channels_redis>=2.1,<2.2
django-cacheops>=4,<4.1
daphne==2.0.4
cryptography>=2,<3
requests-http-signature==0.0.3

View File

@ -31,7 +31,11 @@ def cache():
def factories(db):
from funkwhale_api import factories
for v in factories.registry.values():
v._meta.strategy = factory.CREATE_STRATEGY
try:
v._meta.strategy = factory.CREATE_STRATEGY
except AttributeError:
# probably not a class based factory
pass
yield factories.registry
@ -39,7 +43,11 @@ def factories(db):
def nodb_factories():
from funkwhale_api import factories
for v in factories.registry.values():
v._meta.strategy = factory.BUILD_STRATEGY
try:
v._meta.strategy = factory.BUILD_STRATEGY
except AttributeError:
# probably not a class based factory
pass
yield factories.registry

View File

@ -0,0 +1,34 @@
import cryptography.exceptions
import io
import pytest
import requests_http_signature
from funkwhale_api.federation import signing
def test_can_sign_and_verify_request(factories):
private, public = factories['federation.KeyPair']()
auth = factories['federation.SignatureAuth'](key=private)
request = factories['federation.SignedRequest'](
auth=auth
)
prepared_request = request.prepare()
assert 'date' in prepared_request.headers
assert 'authorization' in prepared_request.headers
assert prepared_request.headers['authorization'].startswith('Signature')
assert requests_http_signature.HTTPSignatureAuth.verify(
prepared_request,
key_resolver=lambda **kwargs: public
) is None
def test_verify_fails_with_wrong_key(factories):
wrong_private, wrong_public = factories['federation.KeyPair']()
request = factories['federation.SignedRequest']()
prepared_request = request.prepare()
with pytest.raises(cryptography.exceptions.InvalidSignature):
requests_http_signature.HTTPSignatureAuth.verify(
prepared_request,
key_resolver=lambda **kwargs: wrong_public
)