2018-03-24 14:20:15 +00:00
|
|
|
import cryptography.exceptions
|
2018-06-24 17:17:56 +00:00
|
|
|
import datetime
|
|
|
|
from django.utils.http import http_date
|
|
|
|
from django import forms
|
2018-03-24 14:20:15 +00:00
|
|
|
import pytest
|
|
|
|
|
2018-06-10 08:55:16 +00:00
|
|
|
from funkwhale_api.federation import keys, signing
|
2018-03-24 14:20:15 +00:00
|
|
|
|
|
|
|
|
2018-03-30 19:59:58 +00:00
|
|
|
def test_can_sign_and_verify_request(nodb_factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
private, public = nodb_factories["federation.KeyPair"]()
|
|
|
|
auth = nodb_factories["federation.SignatureAuth"](key=private)
|
|
|
|
request = nodb_factories["federation.SignedRequest"](auth=auth)
|
2018-03-24 14:20:15 +00:00
|
|
|
prepared_request = request.prepare()
|
2018-06-09 13:36:16 +00:00
|
|
|
assert "date" in prepared_request.headers
|
|
|
|
assert "signature" in prepared_request.headers
|
|
|
|
assert signing.verify(prepared_request, public) is None
|
2018-03-24 15:24:10 +00:00
|
|
|
|
|
|
|
|
2018-03-30 19:59:58 +00:00
|
|
|
def test_can_sign_and_verify_request_digest(nodb_factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
private, public = nodb_factories["federation.KeyPair"]()
|
|
|
|
auth = nodb_factories["federation.SignatureAuth"](key=private)
|
|
|
|
request = nodb_factories["federation.SignedRequest"](
|
|
|
|
auth=auth, method="post", data=b"hello=world"
|
2018-03-24 15:24:10 +00:00
|
|
|
)
|
|
|
|
prepared_request = request.prepare()
|
2018-06-09 13:36:16 +00:00
|
|
|
assert "date" in prepared_request.headers
|
|
|
|
assert "digest" in prepared_request.headers
|
|
|
|
assert "signature" in prepared_request.headers
|
2018-03-24 15:24:10 +00:00
|
|
|
assert signing.verify(prepared_request, public) is None
|
2018-03-24 14:20:15 +00:00
|
|
|
|
|
|
|
|
2018-03-30 19:59:58 +00:00
|
|
|
def test_verify_fails_with_wrong_key(nodb_factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
wrong_private, wrong_public = nodb_factories["federation.KeyPair"]()
|
|
|
|
request = nodb_factories["federation.SignedRequest"]()
|
2018-03-24 14:20:15 +00:00
|
|
|
prepared_request = request.prepare()
|
|
|
|
|
|
|
|
with pytest.raises(cryptography.exceptions.InvalidSignature):
|
2018-03-24 15:24:10 +00:00
|
|
|
signing.verify(prepared_request, wrong_public)
|
|
|
|
|
|
|
|
|
2018-06-24 17:17:56 +00:00
|
|
|
def test_verify_fails_with_wrong_date(nodb_factories, now):
|
|
|
|
too_old = now - datetime.timedelta(seconds=31)
|
|
|
|
too_old = http_date(too_old.timestamp())
|
|
|
|
private, public = nodb_factories["federation.KeyPair"]()
|
|
|
|
auth = nodb_factories["federation.SignatureAuth"](key=private)
|
|
|
|
request = nodb_factories["federation.SignedRequest"](
|
|
|
|
auth=auth, headers={"Date": too_old}
|
|
|
|
)
|
|
|
|
prepared_request = request.prepare()
|
|
|
|
|
|
|
|
with pytest.raises(forms.ValidationError):
|
|
|
|
signing.verify(prepared_request, public)
|
|
|
|
|
|
|
|
|
2018-03-31 16:40:41 +00:00
|
|
|
def test_can_verify_django_request(factories, fake_request):
|
2018-03-28 16:04:21 +00:00
|
|
|
private_key, public_key = keys.get_key_pair()
|
2018-06-09 13:36:16 +00:00
|
|
|
signed_request = factories["federation.SignedRequest"](
|
|
|
|
auth__key=private_key, auth__headers=["date"]
|
2018-03-24 15:24:10 +00:00
|
|
|
)
|
|
|
|
prepared = signed_request.prepare()
|
2018-03-31 16:40:41 +00:00
|
|
|
django_request = fake_request.get(
|
2018-06-09 13:36:16 +00:00
|
|
|
"/",
|
2018-03-31 16:40:41 +00:00
|
|
|
**{
|
2018-06-09 13:36:16 +00:00
|
|
|
"HTTP_DATE": prepared.headers["date"],
|
|
|
|
"HTTP_SIGNATURE": prepared.headers["signature"],
|
2018-03-24 15:24:10 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
assert signing.verify_django(django_request, public_key) is None
|
|
|
|
|
|
|
|
|
2018-03-31 16:40:41 +00:00
|
|
|
def test_can_verify_django_request_digest(factories, fake_request):
|
2018-03-28 16:04:21 +00:00
|
|
|
private_key, public_key = keys.get_key_pair()
|
2018-06-09 13:36:16 +00:00
|
|
|
signed_request = factories["federation.SignedRequest"](
|
2018-03-24 15:24:10 +00:00
|
|
|
auth__key=private_key,
|
2018-06-09 13:36:16 +00:00
|
|
|
method="post",
|
|
|
|
data=b"hello=world",
|
|
|
|
auth__headers=["date", "digest"],
|
2018-03-24 15:24:10 +00:00
|
|
|
)
|
|
|
|
prepared = signed_request.prepare()
|
2018-03-31 16:40:41 +00:00
|
|
|
django_request = fake_request.post(
|
2018-06-09 13:36:16 +00:00
|
|
|
"/",
|
2018-03-31 16:40:41 +00:00
|
|
|
**{
|
2018-06-09 13:36:16 +00:00
|
|
|
"HTTP_DATE": prepared.headers["date"],
|
|
|
|
"HTTP_DIGEST": prepared.headers["digest"],
|
|
|
|
"HTTP_SIGNATURE": prepared.headers["signature"],
|
2018-03-24 15:24:10 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert signing.verify_django(django_request, public_key) is None
|
|
|
|
|
|
|
|
|
2018-03-31 16:40:41 +00:00
|
|
|
def test_can_verify_django_request_digest_failure(factories, fake_request):
|
2018-03-28 16:04:21 +00:00
|
|
|
private_key, public_key = keys.get_key_pair()
|
2018-06-09 13:36:16 +00:00
|
|
|
signed_request = factories["federation.SignedRequest"](
|
2018-03-24 15:24:10 +00:00
|
|
|
auth__key=private_key,
|
2018-06-09 13:36:16 +00:00
|
|
|
method="post",
|
|
|
|
data=b"hello=world",
|
|
|
|
auth__headers=["date", "digest"],
|
2018-03-24 15:24:10 +00:00
|
|
|
)
|
|
|
|
prepared = signed_request.prepare()
|
2018-03-31 16:40:41 +00:00
|
|
|
django_request = fake_request.post(
|
2018-06-09 13:36:16 +00:00
|
|
|
"/",
|
2018-03-31 16:40:41 +00:00
|
|
|
**{
|
2018-06-09 13:36:16 +00:00
|
|
|
"HTTP_DATE": prepared.headers["date"],
|
|
|
|
"HTTP_DIGEST": prepared.headers["digest"] + "noop",
|
|
|
|
"HTTP_SIGNATURE": prepared.headers["signature"],
|
2018-03-24 15:24:10 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
with pytest.raises(cryptography.exceptions.InvalidSignature):
|
|
|
|
signing.verify_django(django_request, public_key)
|
|
|
|
|
|
|
|
|
2018-06-24 17:17:56 +00:00
|
|
|
def test_can_verify_django_request_failure(factories, fake_request, now):
|
2018-03-28 16:04:21 +00:00
|
|
|
private_key, public_key = keys.get_key_pair()
|
2018-06-09 13:36:16 +00:00
|
|
|
signed_request = factories["federation.SignedRequest"](
|
|
|
|
auth__key=private_key, auth__headers=["date"]
|
2018-03-24 15:24:10 +00:00
|
|
|
)
|
|
|
|
prepared = signed_request.prepare()
|
2018-03-31 16:40:41 +00:00
|
|
|
django_request = fake_request.get(
|
2018-06-24 17:17:56 +00:00
|
|
|
"/",
|
|
|
|
**{
|
|
|
|
"HTTP_DATE": http_date((now + datetime.timedelta(seconds=31)).timestamp()),
|
|
|
|
"HTTP_SIGNATURE": prepared.headers["signature"],
|
|
|
|
}
|
2018-03-24 15:24:10 +00:00
|
|
|
)
|
2018-06-24 17:17:56 +00:00
|
|
|
with pytest.raises(forms.ValidationError):
|
2018-03-24 15:24:10 +00:00
|
|
|
signing.verify_django(django_request, public_key)
|