authentik.rbac.api.rbac_assigned_by_roles

common RBAC serializers

  1"""common RBAC serializers"""
  2
  3from django.contrib.auth.models import Permission
  4from django.db.models import Q, QuerySet
  5from django.db.transaction import atomic
  6from django_filters.filters import CharFilter, ChoiceFilter
  7from django_filters.filterset import FilterSet
  8from drf_spectacular.utils import OpenApiResponse, extend_schema
  9from guardian.models import RoleModelPermission, RoleObjectPermission
 10from guardian.shortcuts import assign_perm, remove_perm
 11from rest_framework.decorators import action
 12from rest_framework.fields import CharField, ReadOnlyField
 13from rest_framework.mixins import ListModelMixin
 14from rest_framework.request import Request
 15from rest_framework.response import Response
 16from rest_framework.viewsets import GenericViewSet
 17
 18from authentik.core.api.utils import ModelSerializer, PassiveSerializer
 19from authentik.lib.api import model_choices
 20from authentik.rbac.api.rbac import PermissionAssignResultSerializer, PermissionAssignSerializer
 21from authentik.rbac.decorators import permission_required
 22from authentik.rbac.models import Role
 23
 24
 25class RoleObjectPermissionSerializer(ModelSerializer):
 26    """Role-bound object level permission"""
 27
 28    app_label = ReadOnlyField(source="content_type.app_label")
 29    model = ReadOnlyField(source="content_type.model")
 30    codename = ReadOnlyField(source="permission.codename")
 31    name = ReadOnlyField(source="permission.name")
 32    object_pk = CharField()
 33
 34    class Meta:
 35        model = RoleObjectPermission
 36        fields = ["id", "codename", "model", "app_label", "object_pk", "name"]
 37
 38
 39class RoleModelPermissionSerializer(ModelSerializer):
 40    """Role-bound object level permission"""
 41
 42    app_label = ReadOnlyField(source="content_type.app_label")
 43    model = ReadOnlyField(source="content_type.model")
 44    codename = ReadOnlyField(source="permission.codename")
 45    name = ReadOnlyField(source="permission.name")
 46
 47    class Meta:
 48        model = RoleModelPermission
 49        fields = ["id", "codename", "model", "app_label", "name"]
 50
 51
 52class RoleAssignedObjectPermissionSerializer(PassiveSerializer):
 53    """Roles assigned object permission serializer"""
 54
 55    role_pk = CharField(source="pk", read_only=True)
 56    name = CharField(read_only=True)
 57    object_permissions = RoleObjectPermissionSerializer(
 58        many=True, source="roleobjectpermission_set"
 59    )
 60    model_permissions = RoleModelPermissionSerializer(many=True, source="rolemodelpermission_set")
 61
 62    class Meta:
 63        model = Role
 64        fields = ["role_pk", "name", "object_permissions", "model_permissions"]
 65
 66
 67class RoleAssignedPermissionFilter(FilterSet):
 68    """Assigned permission filter"""
 69
 70    model = ChoiceFilter(choices=model_choices(), method="filter_model", required=True)
 71    object_pk = CharFilter(method="filter_object_pk")
 72
 73    def filter_queryset(self, queryset):
 74        queryset = super().filter_queryset(queryset)
 75        data = self.form.cleaned_data
 76        model: str = data["model"]
 77        object_pk: str | None = data.get("object_pk", None)
 78        app, _, model = model.partition(".")
 79
 80        permissions = Permission.objects.filter(
 81            content_type__app_label=app,
 82            content_type__model=model,
 83        )
 84
 85        role_pks_with_model_permission = (
 86            permissions.order_by().values_list("rolemodelpermission__role", flat=True).distinct()
 87        )
 88        role_pks_with_object_permission = []
 89        if object_pk:
 90            role_pks_with_object_permission = (
 91                RoleObjectPermission.objects.filter(
 92                    permission__in=permissions,
 93                    object_pk=object_pk,
 94                )
 95                .order_by()
 96                .values_list("role", flat=True)
 97                .distinct()
 98            )
 99
100        return queryset.filter(
101            Q(pk__in=role_pks_with_model_permission) | Q(pk__in=role_pks_with_object_permission)
102        )
103
104    def filter_model(self, queryset: QuerySet, name, value: str) -> QuerySet:
105        """Filter by object type"""
106        # Actual filtering is handled by the above method where both `model` and `object_pk` are
107        # available. Don't do anything here, this method is only left here to avoid overriding too
108        # much of filter_queryset.
109        return queryset
110
111    def filter_object_pk(self, queryset: QuerySet, name, value: str) -> QuerySet:
112        """Filter by object primary key"""
113        # Actual filtering is handled by the above method where both `model` and `object_pk` are
114        # available. Don't do anything here, this method is only left here to avoid overriding too
115        # much of filter_queryset.
116        return queryset
117
118
119class RoleAssignedPermissionViewSet(ListModelMixin, GenericViewSet):
120    """Get assigned object permissions for a single object"""
121
122    serializer_class = RoleAssignedObjectPermissionSerializer
123    ordering = ["name"]
124    # The filtering is done in the filterset,
125    # which has a required filter that does the heavy lifting
126    queryset = Role.objects.all()
127    filterset_class = RoleAssignedPermissionFilter
128    search_fields = ["name"]
129
130    @permission_required("authentik_rbac.assign_role_permissions")
131    @extend_schema(
132        request=PermissionAssignSerializer(),
133        responses={
134            200: PermissionAssignResultSerializer(many=True),
135        },
136        operation_id="rbac_permissions_assigned_by_roles_assign",
137    )
138    @action(methods=["POST"], detail=True, pagination_class=None, filter_backends=[])
139    def assign(self, request: Request, *args, **kwargs) -> Response:
140        """Assign permission(s) to role. When `object_pk` is set, the permissions
141        are only assigned to the specific object, otherwise they are assigned globally."""
142        role: Role = self.get_object()
143        data = PermissionAssignSerializer(data=request.data)
144        data.is_valid(raise_exception=True)
145        ids = []
146        with atomic():
147            for perm in data.validated_data["permissions"]:
148                assigned_perm = assign_perm(perm, role, data.validated_data["model_instance"])
149                ids.append(PermissionAssignResultSerializer(instance={"id": assigned_perm.pk}).data)
150        return Response(ids, status=200)
151
152    @permission_required("authentik_rbac.unassign_role_permissions")
153    @extend_schema(
154        request=PermissionAssignSerializer(),
155        responses={
156            204: OpenApiResponse(description="Successfully unassigned"),
157        },
158    )
159    @action(methods=["PATCH"], detail=True, pagination_class=None, filter_backends=[])
160    def unassign(self, request: Request, *args, **kwargs) -> Response:
161        """Unassign permission(s) to role. When `object_pk` is set, the permissions
162        are only assigned to the specific object, otherwise they are assigned globally."""
163        role: Role = self.get_object()
164        data = PermissionAssignSerializer(data=request.data)
165        data.is_valid(raise_exception=True)
166        with atomic():
167            for perm in data.validated_data["permissions"]:
168                remove_perm(perm, role, data.validated_data["model_instance"])
169        return Response(status=204)
class RoleObjectPermissionSerializer(authentik.core.api.utils.ModelSerializer):
26class RoleObjectPermissionSerializer(ModelSerializer):
27    """Role-bound object level permission"""
28
29    app_label = ReadOnlyField(source="content_type.app_label")
30    model = ReadOnlyField(source="content_type.model")
31    codename = ReadOnlyField(source="permission.codename")
32    name = ReadOnlyField(source="permission.name")
33    object_pk = CharField()
34
35    class Meta:
36        model = RoleObjectPermission
37        fields = ["id", "codename", "model", "app_label", "object_pk", "name"]

Role-bound object level permission

app_label
model
codename
name
object_pk
class RoleObjectPermissionSerializer.Meta:
35    class Meta:
36        model = RoleObjectPermission
37        fields = ["id", "codename", "model", "app_label", "object_pk", "name"]
model = <class 'guardian.models.RoleObjectPermission'>
fields = ['id', 'codename', 'model', 'app_label', 'object_pk', 'name']
class RoleModelPermissionSerializer(authentik.core.api.utils.ModelSerializer):
40class RoleModelPermissionSerializer(ModelSerializer):
41    """Role-bound object level permission"""
42
43    app_label = ReadOnlyField(source="content_type.app_label")
44    model = ReadOnlyField(source="content_type.model")
45    codename = ReadOnlyField(source="permission.codename")
46    name = ReadOnlyField(source="permission.name")
47
48    class Meta:
49        model = RoleModelPermission
50        fields = ["id", "codename", "model", "app_label", "name"]

Role-bound object level permission

app_label
model
codename
name
class RoleModelPermissionSerializer.Meta:
48    class Meta:
49        model = RoleModelPermission
50        fields = ["id", "codename", "model", "app_label", "name"]
model = <class 'guardian.models.RoleModelPermission'>
fields = ['id', 'codename', 'model', 'app_label', 'name']
class RoleAssignedObjectPermissionSerializer(authentik.core.api.utils.PassiveSerializer):
53class RoleAssignedObjectPermissionSerializer(PassiveSerializer):
54    """Roles assigned object permission serializer"""
55
56    role_pk = CharField(source="pk", read_only=True)
57    name = CharField(read_only=True)
58    object_permissions = RoleObjectPermissionSerializer(
59        many=True, source="roleobjectpermission_set"
60    )
61    model_permissions = RoleModelPermissionSerializer(many=True, source="rolemodelpermission_set")
62
63    class Meta:
64        model = Role
65        fields = ["role_pk", "name", "object_permissions", "model_permissions"]

Roles assigned object permission serializer

role_pk
name
object_permissions
model_permissions
class RoleAssignedObjectPermissionSerializer.Meta:
63    class Meta:
64        model = Role
65        fields = ["role_pk", "name", "object_permissions", "model_permissions"]
model = <class 'authentik.rbac.models.Role'>
fields = ['role_pk', 'name', 'object_permissions', 'model_permissions']
class RoleAssignedPermissionFilter(django_filters.filterset.FilterSet):
 68class RoleAssignedPermissionFilter(FilterSet):
 69    """Assigned permission filter"""
 70
 71    model = ChoiceFilter(choices=model_choices(), method="filter_model", required=True)
 72    object_pk = CharFilter(method="filter_object_pk")
 73
 74    def filter_queryset(self, queryset):
 75        queryset = super().filter_queryset(queryset)
 76        data = self.form.cleaned_data
 77        model: str = data["model"]
 78        object_pk: str | None = data.get("object_pk", None)
 79        app, _, model = model.partition(".")
 80
 81        permissions = Permission.objects.filter(
 82            content_type__app_label=app,
 83            content_type__model=model,
 84        )
 85
 86        role_pks_with_model_permission = (
 87            permissions.order_by().values_list("rolemodelpermission__role", flat=True).distinct()
 88        )
 89        role_pks_with_object_permission = []
 90        if object_pk:
 91            role_pks_with_object_permission = (
 92                RoleObjectPermission.objects.filter(
 93                    permission__in=permissions,
 94                    object_pk=object_pk,
 95                )
 96                .order_by()
 97                .values_list("role", flat=True)
 98                .distinct()
 99            )
100
101        return queryset.filter(
102            Q(pk__in=role_pks_with_model_permission) | Q(pk__in=role_pks_with_object_permission)
103        )
104
105    def filter_model(self, queryset: QuerySet, name, value: str) -> QuerySet:
106        """Filter by object type"""
107        # Actual filtering is handled by the above method where both `model` and `object_pk` are
108        # available. Don't do anything here, this method is only left here to avoid overriding too
109        # much of filter_queryset.
110        return queryset
111
112    def filter_object_pk(self, queryset: QuerySet, name, value: str) -> QuerySet:
113        """Filter by object primary key"""
114        # Actual filtering is handled by the above method where both `model` and `object_pk` are
115        # available. Don't do anything here, this method is only left here to avoid overriding too
116        # much of filter_queryset.
117        return queryset

Assigned permission filter

model
object_pk
def filter_queryset(self, queryset):
 74    def filter_queryset(self, queryset):
 75        queryset = super().filter_queryset(queryset)
 76        data = self.form.cleaned_data
 77        model: str = data["model"]
 78        object_pk: str | None = data.get("object_pk", None)
 79        app, _, model = model.partition(".")
 80
 81        permissions = Permission.objects.filter(
 82            content_type__app_label=app,
 83            content_type__model=model,
 84        )
 85
 86        role_pks_with_model_permission = (
 87            permissions.order_by().values_list("rolemodelpermission__role", flat=True).distinct()
 88        )
 89        role_pks_with_object_permission = []
 90        if object_pk:
 91            role_pks_with_object_permission = (
 92                RoleObjectPermission.objects.filter(
 93                    permission__in=permissions,
 94                    object_pk=object_pk,
 95                )
 96                .order_by()
 97                .values_list("role", flat=True)
 98                .distinct()
 99            )
100
101        return queryset.filter(
102            Q(pk__in=role_pks_with_model_permission) | Q(pk__in=role_pks_with_object_permission)
103        )

Filter the queryset with the underlying form's cleaned_data. You must call is_valid() or errors before calling this method.

This method should be overridden if additional filtering needs to be applied to the queryset before it is cached.

def filter_model( self, queryset: django.db.models.query.QuerySet, name, value: str) -> django.db.models.query.QuerySet:
105    def filter_model(self, queryset: QuerySet, name, value: str) -> QuerySet:
106        """Filter by object type"""
107        # Actual filtering is handled by the above method where both `model` and `object_pk` are
108        # available. Don't do anything here, this method is only left here to avoid overriding too
109        # much of filter_queryset.
110        return queryset

Filter by object type

def filter_object_pk( self, queryset: django.db.models.query.QuerySet, name, value: str) -> django.db.models.query.QuerySet:
112    def filter_object_pk(self, queryset: QuerySet, name, value: str) -> QuerySet:
113        """Filter by object primary key"""
114        # Actual filtering is handled by the above method where both `model` and `object_pk` are
115        # available. Don't do anything here, this method is only left here to avoid overriding too
116        # much of filter_queryset.
117        return queryset

Filter by object primary key

declared_filters = OrderedDict({'model': <django_filters.filters.ChoiceFilter object>, 'object_pk': <django_filters.filters.CharFilter object>})
base_filters = OrderedDict({'model': <django_filters.filters.ChoiceFilter object>, 'object_pk': <django_filters.filters.CharFilter object>})
class RoleAssignedPermissionViewSet(rest_framework.mixins.ListModelMixin, rest_framework.viewsets.GenericViewSet):
120class RoleAssignedPermissionViewSet(ListModelMixin, GenericViewSet):
121    """Get assigned object permissions for a single object"""
122
123    serializer_class = RoleAssignedObjectPermissionSerializer
124    ordering = ["name"]
125    # The filtering is done in the filterset,
126    # which has a required filter that does the heavy lifting
127    queryset = Role.objects.all()
128    filterset_class = RoleAssignedPermissionFilter
129    search_fields = ["name"]
130
131    @permission_required("authentik_rbac.assign_role_permissions")
132    @extend_schema(
133        request=PermissionAssignSerializer(),
134        responses={
135            200: PermissionAssignResultSerializer(many=True),
136        },
137        operation_id="rbac_permissions_assigned_by_roles_assign",
138    )
139    @action(methods=["POST"], detail=True, pagination_class=None, filter_backends=[])
140    def assign(self, request: Request, *args, **kwargs) -> Response:
141        """Assign permission(s) to role. When `object_pk` is set, the permissions
142        are only assigned to the specific object, otherwise they are assigned globally."""
143        role: Role = self.get_object()
144        data = PermissionAssignSerializer(data=request.data)
145        data.is_valid(raise_exception=True)
146        ids = []
147        with atomic():
148            for perm in data.validated_data["permissions"]:
149                assigned_perm = assign_perm(perm, role, data.validated_data["model_instance"])
150                ids.append(PermissionAssignResultSerializer(instance={"id": assigned_perm.pk}).data)
151        return Response(ids, status=200)
152
153    @permission_required("authentik_rbac.unassign_role_permissions")
154    @extend_schema(
155        request=PermissionAssignSerializer(),
156        responses={
157            204: OpenApiResponse(description="Successfully unassigned"),
158        },
159    )
160    @action(methods=["PATCH"], detail=True, pagination_class=None, filter_backends=[])
161    def unassign(self, request: Request, *args, **kwargs) -> Response:
162        """Unassign permission(s) to role. When `object_pk` is set, the permissions
163        are only assigned to the specific object, otherwise they are assigned globally."""
164        role: Role = self.get_object()
165        data = PermissionAssignSerializer(data=request.data)
166        data.is_valid(raise_exception=True)
167        with atomic():
168            for perm in data.validated_data["permissions"]:
169                remove_perm(perm, role, data.validated_data["model_instance"])
170        return Response(status=204)

Get assigned object permissions for a single object

serializer_class = <class 'RoleAssignedObjectPermissionSerializer'>
ordering = ['name']
queryset = <QuerySet []>
filterset_class = <class 'RoleAssignedPermissionFilter'>
search_fields = ['name']
@permission_required('authentik_rbac.assign_role_permissions')
@extend_schema(request=PermissionAssignSerializer(), responses={200: PermissionAssignResultSerializer(many=True)}, operation_id='rbac_permissions_assigned_by_roles_assign')
@action(methods=['POST'], detail=True, pagination_class=None, filter_backends=[])
def assign( self, request: rest_framework.request.Request, *args, **kwargs) -> rest_framework.response.Response:
131    @permission_required("authentik_rbac.assign_role_permissions")
132    @extend_schema(
133        request=PermissionAssignSerializer(),
134        responses={
135            200: PermissionAssignResultSerializer(many=True),
136        },
137        operation_id="rbac_permissions_assigned_by_roles_assign",
138    )
139    @action(methods=["POST"], detail=True, pagination_class=None, filter_backends=[])
140    def assign(self, request: Request, *args, **kwargs) -> Response:
141        """Assign permission(s) to role. When `object_pk` is set, the permissions
142        are only assigned to the specific object, otherwise they are assigned globally."""
143        role: Role = self.get_object()
144        data = PermissionAssignSerializer(data=request.data)
145        data.is_valid(raise_exception=True)
146        ids = []
147        with atomic():
148            for perm in data.validated_data["permissions"]:
149                assigned_perm = assign_perm(perm, role, data.validated_data["model_instance"])
150                ids.append(PermissionAssignResultSerializer(instance={"id": assigned_perm.pk}).data)
151        return Response(ids, status=200)

Assign permission(s) to role. When object_pk is set, the permissions are only assigned to the specific object, otherwise they are assigned globally.

@permission_required('authentik_rbac.unassign_role_permissions')
@extend_schema(request=PermissionAssignSerializer(), responses={204: OpenApiResponse(description='Successfully unassigned')})
@action(methods=['PATCH'], detail=True, pagination_class=None, filter_backends=[])
def unassign( self, request: rest_framework.request.Request, *args, **kwargs) -> rest_framework.response.Response:
153    @permission_required("authentik_rbac.unassign_role_permissions")
154    @extend_schema(
155        request=PermissionAssignSerializer(),
156        responses={
157            204: OpenApiResponse(description="Successfully unassigned"),
158        },
159    )
160    @action(methods=["PATCH"], detail=True, pagination_class=None, filter_backends=[])
161    def unassign(self, request: Request, *args, **kwargs) -> Response:
162        """Unassign permission(s) to role. When `object_pk` is set, the permissions
163        are only assigned to the specific object, otherwise they are assigned globally."""
164        role: Role = self.get_object()
165        data = PermissionAssignSerializer(data=request.data)
166        data.is_valid(raise_exception=True)
167        with atomic():
168            for perm in data.validated_data["permissions"]:
169                remove_perm(perm, role, data.validated_data["model_instance"])
170        return Response(status=204)

Unassign permission(s) to role. When object_pk is set, the permissions are only assigned to the specific object, otherwise they are assigned globally.

name = None
description = None
suffix = None
detail = None
basename = None