diff --git a/authentik/api/authorization.py b/authentik/api/authorization.py index 1ff4da61b..05cd45819 100644 --- a/authentik/api/authorization.py +++ b/authentik/api/authorization.py @@ -1,9 +1,15 @@ """API Authorization""" +from django.conf import settings from django.db.models import Model 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.permissions import BasePermission from rest_framework.request import Request +from rest_framework_guardian.filters import ObjectPermissionsFilter + +from authentik.api.authentication import validate_auth class OwnerFilter(BaseFilterBackend): @@ -17,6 +23,20 @@ class OwnerFilter(BaseFilterBackend): 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): """Authorize requests by an object's owner matching the requesting user""" diff --git a/authentik/crypto/api.py b/authentik/crypto/api.py index bac8d05af..aab6ae09f 100644 --- a/authentik/crypto/api.py +++ b/authentik/crypto/api.py @@ -15,12 +15,14 @@ from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_sche from rest_framework.decorators import action from rest_framework.exceptions import ValidationError 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.response import Response from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import ModelViewSet from structlog.stdlib import get_logger +from authentik.api.authorization import SecretKeyFilter from authentik.api.decorators import permission_required from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import PassiveSerializer @@ -203,6 +205,7 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet): filterset_class = CertificateKeyPairFilter ordering = ["name"] search_fields = ["name"] + filter_backends = [SecretKeyFilter, OrderingFilter, SearchFilter] @extend_schema( parameters=[ diff --git a/authentik/tenants/api.py b/authentik/tenants/api.py index 0c3a33fec..e27c6d50a 100644 --- a/authentik/tenants/api.py +++ b/authentik/tenants/api.py @@ -5,12 +5,14 @@ from drf_spectacular.utils import extend_schema from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.fields import CharField, ListField +from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.permissions import AllowAny from rest_framework.request import Request from rest_framework.response import Response from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import ModelViewSet +from authentik.api.authorization import SecretKeyFilter from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import PassiveSerializer from authentik.lib.config import CONFIG @@ -109,6 +111,8 @@ class TenantViewSet(UsedByMixin, ModelViewSet): ] ordering = ["domain"] + filter_backends = [SecretKeyFilter, OrderingFilter, SearchFilter] + @extend_schema( responses=CurrentTenantSerializer(many=False), )