api: add filter backend for secret key to allow access to tenants and certificates

closes #4182

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-12-28 18:59:25 +01:00
parent 89a3f7d004
commit f0e121c064
No known key found for this signature in database
3 changed files with 27 additions and 0 deletions

View file

@ -1,9 +1,15 @@
"""API Authorization""" """API Authorization"""
from django.conf import settings
from django.db.models import Model from django.db.models import Model
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.authentication import get_authorization_header
from rest_framework.filters import BaseFilterBackend from rest_framework.filters import BaseFilterBackend
from rest_framework.permissions import BasePermission from rest_framework.permissions import BasePermission
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework_guardian.filters import ObjectPermissionsFilter
from authentik.api.authentication import validate_auth
class OwnerFilter(BaseFilterBackend): class OwnerFilter(BaseFilterBackend):
@ -17,6 +23,20 @@ class OwnerFilter(BaseFilterBackend):
return queryset.filter(**{self.owner_key: request.user}) return queryset.filter(**{self.owner_key: request.user})
class SecretKeyFilter(DjangoFilterBackend):
"""Allow access to all objects when authenticated with secret key as token.
Replaces both DjangoFilterBackend and ObjectPermissionsFilter"""
def filter_queryset(self, request: Request, queryset: QuerySet, view) -> QuerySet:
auth_header = get_authorization_header(request)
token = validate_auth(auth_header)
if token and token == settings.SECRET_KEY:
return queryset
queryset = ObjectPermissionsFilter().filter_queryset(request, queryset, view)
return super().filter_queryset(request, queryset, view)
class OwnerPermissions(BasePermission): class OwnerPermissions(BasePermission):
"""Authorize requests by an object's owner matching the requesting user""" """Authorize requests by an object's owner matching the requesting user"""

View file

@ -15,12 +15,14 @@ from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_sche
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField, IntegerField, SerializerMethodField from rest_framework.fields import CharField, DateTimeField, IntegerField, SerializerMethodField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.api.authorization import SecretKeyFilter
from authentik.api.decorators import permission_required from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
@ -203,6 +205,7 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
filterset_class = CertificateKeyPairFilter filterset_class = CertificateKeyPairFilter
ordering = ["name"] ordering = ["name"]
search_fields = ["name"] search_fields = ["name"]
filter_backends = [SecretKeyFilter, OrderingFilter, SearchFilter]
@extend_schema( @extend_schema(
parameters=[ parameters=[

View file

@ -5,12 +5,14 @@ from drf_spectacular.utils import extend_schema
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, ListField from rest_framework.fields import CharField, ListField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.api.authorization import SecretKeyFilter
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
@ -109,6 +111,8 @@ class TenantViewSet(UsedByMixin, ModelViewSet):
] ]
ordering = ["domain"] ordering = ["domain"]
filter_backends = [SecretKeyFilter, OrderingFilter, SearchFilter]
@extend_schema( @extend_schema(
responses=CurrentTenantSerializer(many=False), responses=CurrentTenantSerializer(many=False),
) )