This commit is contained in:
parent
0b92db278b
commit
91cd5c57b3
15 changed files with 251 additions and 17 deletions
|
|
@ -91,6 +91,10 @@ class ToolshedUser(AbstractUser):
|
|||
def __str__(self):
|
||||
return f"{self.username}@{self.domain}"
|
||||
|
||||
@property
|
||||
def friends(self):
|
||||
return self.public_identity.friends
|
||||
|
||||
def sign(self, message):
|
||||
if type(message) != str:
|
||||
raise TypeError('Message must be a string')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from rest_framework import authentication
|
||||
from authentication.models import ToolshedUser
|
||||
|
||||
from authentication.models import KnownIdentity, ToolshedUser
|
||||
|
||||
|
||||
def split_userhandle_or_throw(userhandle):
|
||||
|
|
@ -47,6 +48,21 @@ def verify_request(request, raw_request_body):
|
|||
return username, domain, signed_data, signature_bytes_hex
|
||||
|
||||
|
||||
def authenticate_request_against_known_identities(request, raw_request_body):
|
||||
try:
|
||||
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
||||
except ValueError:
|
||||
return None
|
||||
try:
|
||||
author_identity = KnownIdentity.objects.get(username=username, domain=domain)
|
||||
except KnownIdentity.DoesNotExist:
|
||||
return None
|
||||
if author_identity.verify(signed_data, signature_bytes_hex):
|
||||
return author_identity
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def authenticate_request_against_local_users(request, raw_request_body):
|
||||
try:
|
||||
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
||||
|
|
@ -62,6 +78,12 @@ def authenticate_request_against_local_users(request, raw_request_body):
|
|||
return None
|
||||
|
||||
|
||||
class SignatureAuthentication(authentication.BaseAuthentication):
|
||||
def authenticate(self, request):
|
||||
return authenticate_request_against_known_identities(
|
||||
request, request.body.decode('utf-8')), None
|
||||
|
||||
|
||||
class SignatureAuthenticationLocal(authentication.BaseAuthentication):
|
||||
def authenticate(self, request):
|
||||
return authenticate_request_against_local_users(
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ class DummyExternalUser:
|
|||
self.username = username
|
||||
self.domain = domain
|
||||
self.__signing_key = SigningKey.generate()
|
||||
self.public_identity, _ = KnownIdentity.objects.get_or_create(
|
||||
self.public_identity = KnownIdentity.objects.get_or_create(
|
||||
username=username,
|
||||
domain=domain,
|
||||
public_key=self.public_key()) if known else None
|
||||
public_key=self.public_key())[0] if known else None
|
||||
|
||||
def __str__(self):
|
||||
return self.username + '@' + self.domain
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from nacl.encoding import HexEncoder
|
|||
from nacl.signing import SigningKey
|
||||
|
||||
from authentication.models import ToolshedUser, KnownIdentity
|
||||
from authentication.tests import UserTestCase, SignatureAuthClient
|
||||
from authentication.tests import UserTestCase, SignatureAuthClient, DummyExternalUser
|
||||
from hostadmin.models import Domain
|
||||
|
||||
|
||||
|
|
@ -307,6 +307,50 @@ class UserApiTestCase(UserTestCase):
|
|||
self.assertEqual(reply.status_code, 403)
|
||||
|
||||
|
||||
class FriendApiTestCase(UserTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.local_user1.friends.add(self.local_user2.public_identity)
|
||||
self.local_user1.friends.add(self.ext_user1.public_identity)
|
||||
self.ext_user1.friends.add(self.local_user1.public_identity)
|
||||
self.anonymous_client = Client(SERVER_NAME='testserver')
|
||||
self.client = SignatureAuthClient()
|
||||
|
||||
def test_friend_local(self):
|
||||
reply = self.client.get('/api/friends/', self.local_user1)
|
||||
self.assertEqual(reply.status_code, 200)
|
||||
|
||||
def test_friend_external(self):
|
||||
reply = self.client.get('/api/friends/', self.ext_user1)
|
||||
self.assertEqual(reply.status_code, 200)
|
||||
|
||||
def test_friend_fail(self):
|
||||
reply = self.anonymous_client.get('/api/friends/')
|
||||
self.assertEqual(reply.status_code, 403)
|
||||
|
||||
def test_friend_fail2(self):
|
||||
target = "/api/friends/"
|
||||
signature = self.local_user1.sign("http://testserver2" + target)
|
||||
header = {'HTTP_AUTHORIZATION': 'Signature ' + str(self.local_user1) + ':' + signature}
|
||||
reply = self.anonymous_client.get(target, **header)
|
||||
self.assertEqual(reply.status_code, 403)
|
||||
|
||||
def test_friend_fail3(self):
|
||||
target = "/api/friends/"
|
||||
unknown_user = DummyExternalUser('extuser3', 'external.org', False)
|
||||
signature = unknown_user.sign("http://testserver" + target)
|
||||
header = {'HTTP_AUTHORIZATION': 'Signature ' + str(unknown_user) + ':' + signature}
|
||||
reply = self.anonymous_client.get(target, **header)
|
||||
self.assertEqual(reply.status_code, 403)
|
||||
|
||||
def test_friend_fail4(self):
|
||||
target = "/api/friends/"
|
||||
signature = self.local_user1.sign("http://testserver" + target)
|
||||
header = {'HTTP_AUTHORIZATION': 'Auth ' + str(self.local_user1) + ':' + signature}
|
||||
reply = self.anonymous_client.get(target, **header)
|
||||
self.assertEqual(reply.status_code, 403)
|
||||
|
||||
|
||||
class LoginApiTestCase(UserTestCase):
|
||||
user = None
|
||||
client = Client(SERVER_NAME='testserver')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue