Skip to content
Snippets Groups Projects
authentication.py 2.05 KiB
Newer Older
import cryptography
from django.contrib.auth.models import AnonymousUser
Eliot Berriot's avatar
Eliot Berriot committed
from rest_framework import authentication, exceptions as rest_exceptions
from funkwhale_api.moderation import models as moderation_models
from . import actors, exceptions, keys, signing, utils


logger = logging.getLogger(__name__)


class SignatureAuthentication(authentication.BaseAuthentication):
    def authenticate_actor(self, request):
        headers = utils.clean_wsgi_headers(request.META)
Eliot Berriot's avatar
Eliot Berriot committed
            signature = headers["Signature"]
            key_id = keys.get_key_id_from_signature_header(signature)
        except KeyError:
        except ValueError as e:
Eliot Berriot's avatar
Eliot Berriot committed
            raise rest_exceptions.AuthenticationFailed(str(e))
            actor_url = key_id.split("#")[0]
        except (TypeError, IndexError, AttributeError):
Eliot Berriot's avatar
Eliot Berriot committed
            raise rest_exceptions.AuthenticationFailed("Invalid key id")

        policies = (
            moderation_models.InstancePolicy.objects.active()
            .filter(block_all=True)
            .matching_url(actor_url)
        )
        if policies.exists():
            raise exceptions.BlockedActorOrDomain()

        try:
            actor = actors.get_actor(actor_url)
        except Exception as e:
            logger.info(
                "Discarding HTTP request from blocked actor/domain %s", actor_url
            )
Eliot Berriot's avatar
Eliot Berriot committed
            raise rest_exceptions.AuthenticationFailed(str(e))
Eliot Berriot's avatar
Eliot Berriot committed
            raise rest_exceptions.AuthenticationFailed("No public key found")
Eliot Berriot's avatar
Eliot Berriot committed
            signing.verify_django(request, actor.public_key.encode("utf-8"))
        except cryptography.exceptions.InvalidSignature:
Eliot Berriot's avatar
Eliot Berriot committed
            raise rest_exceptions.AuthenticationFailed("Invalid signature")

    def authenticate(self, request):
Eliot Berriot's avatar
Eliot Berriot committed
        setattr(request, "actor", None)
        actor = self.authenticate_actor(request)
        if not actor:
            return
        user = AnonymousUser()
Eliot Berriot's avatar
Eliot Berriot committed
        setattr(request, "actor", actor)
        return (user, None)