diff --git a/authentik/core/api/groups.py b/authentik/core/api/groups.py index 46e220855..de30d1ee4 100644 --- a/authentik/core/api/groups.py +++ b/authentik/core/api/groups.py @@ -1,7 +1,9 @@ """Groups API Viewset""" +from django.db.models.query import QuerySet from rest_framework.fields import JSONField from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import ModelViewSet +from rest_framework_guardian.filters import ObjectPermissionsFilter from authentik.core.api.utils import is_dict from authentik.core.models import Group @@ -26,3 +28,16 @@ class GroupViewSet(ModelViewSet): search_fields = ["name", "is_superuser"] filterset_fields = ["name", "is_superuser"] ordering = ["name"] + + def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet: + """Custom filter_queryset method which ignores guardian, but still supports sorting""" + for backend in list(self.filter_backends): + if backend == ObjectPermissionsFilter: + continue + queryset = backend().filter_queryset(self.request, queryset, self) + return queryset + + def filter_queryset(self, queryset): + if self.request.user.has_perm("authentik_core.view_group"): + return self._filter_queryset_for_list(queryset) + return super().filter_queryset(queryset) diff --git a/authentik/core/api/users.py b/authentik/core/api/users.py index dfb78eba3..c4d1f6bb9 100644 --- a/authentik/core/api/users.py +++ b/authentik/core/api/users.py @@ -1,6 +1,7 @@ """User API Views""" from json import loads +from django.db.models.query import QuerySet from django.http.response import Http404 from django.urls import reverse_lazy from django.utils.http import urlencode @@ -19,6 +20,7 @@ from rest_framework.serializers import ( ValidationError, ) from rest_framework.viewsets import ModelViewSet +from rest_framework_guardian.filters import ObjectPermissionsFilter from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h from authentik.api.decorators import permission_required @@ -185,3 +187,16 @@ class UserViewSet(ModelViewSet): reverse_lazy("authentik_flows:default-recovery") + f"?{querystring}" ) return Response({"link": link}) + + def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet: + """Custom filter_queryset method which ignores guardian, but still supports sorting""" + for backend in list(self.filter_backends): + if backend == ObjectPermissionsFilter: + continue + queryset = backend().filter_queryset(self.request, queryset, self) + return queryset + + def filter_queryset(self, queryset): + if self.request.user.has_perm("authentik_core.view_group"): + return self._filter_queryset_for_list(queryset) + return super().filter_queryset(queryset) diff --git a/authentik/lib/config.py b/authentik/lib/config.py index bd143a785..615c8c9d2 100644 --- a/authentik/lib/config.py +++ b/authentik/lib/config.py @@ -87,7 +87,7 @@ class ConfigLoader: if url.scheme == "env": value = os.getenv(url.netloc, url.query) if url.scheme == "file": - with open(url.netloc, 'r') as _file: + with open(url.netloc, "r") as _file: value = _file.read() return value diff --git a/authentik/outposts/models.py b/authentik/outposts/models.py index 88591ee2b..2cf24c6a1 100644 --- a/authentik/outposts/models.py +++ b/authentik/outposts/models.py @@ -1,7 +1,7 @@ """Outpost models""" from dataclasses import asdict, dataclass, field from datetime import datetime -from typing import Any, Iterable, Optional, Union +from typing import Iterable, Optional, Union from uuid import uuid4 from dacite import from_dict @@ -336,7 +336,7 @@ class Outpost(models.Model): # the ones the user needs with transaction.atomic(): UserObjectPermission.objects.filter(user=user).delete() - Permission.objects.filter(user=user).delete() + user.user_permissions.clear() for model_or_perm in self.get_required_objects(): if isinstance(model_or_perm, models.Model): model_or_perm: models.Model @@ -346,7 +346,15 @@ class Outpost(models.Model): ) assign_perm(code_name, user, model_or_perm) else: - assign_perm(model_or_perm, user) + app_label, perm = model_or_perm.split(".") + permission = Permission.objects.filter( + codename=perm, + content_type__app_label=app_label, + ) + if not permission.exists(): + LOGGER.warning("permission doesn't exist", perm=model_or_perm) + continue + user.user_permissions.add(permission.first()) LOGGER.debug("Updated service account's permissions") return user