core: update application list API to show applications accessible by policy
This commit is contained in:
parent
bfc1bae0bb
commit
63041d788b
|
@ -1,30 +0,0 @@
|
||||||
"""permission classes for django restframework"""
|
|
||||||
from rest_framework.permissions import BasePermission, DjangoObjectPermissions
|
|
||||||
|
|
||||||
from passbook.policies.engine import PolicyEngine
|
|
||||||
from passbook.policies.models import PolicyBindingModel
|
|
||||||
|
|
||||||
|
|
||||||
class CustomObjectPermissions(DjangoObjectPermissions):
|
|
||||||
"""Similar to `DjangoObjectPermissions`, but adding 'view' permissions."""
|
|
||||||
|
|
||||||
perms_map = {
|
|
||||||
"GET": ["%(app_label)s.view_%(model_name)s"],
|
|
||||||
"OPTIONS": ["%(app_label)s.view_%(model_name)s"],
|
|
||||||
"HEAD": ["%(app_label)s.view_%(model_name)s"],
|
|
||||||
"POST": ["%(app_label)s.add_%(model_name)s"],
|
|
||||||
"PUT": ["%(app_label)s.change_%(model_name)s"],
|
|
||||||
"PATCH": ["%(app_label)s.change_%(model_name)s"],
|
|
||||||
"DELETE": ["%(app_label)s.delete_%(model_name)s"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyPermissions(BasePermission):
|
|
||||||
"""Permission checker based on PolicyEngine"""
|
|
||||||
|
|
||||||
policy_engine: PolicyEngine
|
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj: PolicyBindingModel) -> bool:
|
|
||||||
self.policy_engine = PolicyEngine(obj.policies, request.user, request)
|
|
||||||
self.policy_engine.request.obj = obj
|
|
||||||
return self.policy_engine.build().passing
|
|
|
@ -3,10 +3,10 @@ from django.urls import path, re_path
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
from drf_yasg.views import get_schema_view
|
from drf_yasg.views import get_schema_view
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
|
from rest_framework.permissions import AllowAny
|
||||||
|
|
||||||
from passbook.admin.api.overview import AdministrationOverviewViewSet
|
from passbook.admin.api.overview import AdministrationOverviewViewSet
|
||||||
from passbook.admin.api.overview_metrics import AdministrationMetricsViewSet
|
from passbook.admin.api.overview_metrics import AdministrationMetricsViewSet
|
||||||
from passbook.api.permissions import CustomObjectPermissions
|
|
||||||
from passbook.api.v2.messages import MessagesViewSet
|
from passbook.api.v2.messages import MessagesViewSet
|
||||||
from passbook.audit.api import EventViewSet
|
from passbook.audit.api import EventViewSet
|
||||||
from passbook.core.api.applications import ApplicationViewSet
|
from passbook.core.api.applications import ApplicationViewSet
|
||||||
|
@ -127,7 +127,7 @@ info = openapi.Info(
|
||||||
SchemaView = get_schema_view(
|
SchemaView = get_schema_view(
|
||||||
info,
|
info,
|
||||||
public=True,
|
public=True,
|
||||||
permission_classes=(CustomObjectPermissions,),
|
permission_classes=(AllowAny,),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
"""Application API Views"""
|
"""Application API Views"""
|
||||||
|
from django.db.models import QuerySet
|
||||||
|
from rest_framework.request import Request
|
||||||
|
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 rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||||
|
|
||||||
from passbook.core.models import Application
|
from passbook.core.models import Application
|
||||||
|
from passbook.policies.engine import PolicyEngine
|
||||||
|
|
||||||
|
|
||||||
class ApplicationSerializer(ModelSerializer):
|
class ApplicationSerializer(ModelSerializer):
|
||||||
|
@ -29,3 +34,24 @@ class ApplicationViewSet(ModelViewSet):
|
||||||
|
|
||||||
queryset = Application.objects.all()
|
queryset = Application.objects.all()
|
||||||
serializer_class = ApplicationSerializer
|
serializer_class = ApplicationSerializer
|
||||||
|
lookup_field = "slug"
|
||||||
|
|
||||||
|
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 list(self, request: Request, *_, **__) -> Response:
|
||||||
|
"""Custom list method that checks Policy based access instead of guardian"""
|
||||||
|
queryset = self._filter_queryset_for_list(self.get_queryset())
|
||||||
|
allowed_applications = []
|
||||||
|
for application in queryset.order_by("name"):
|
||||||
|
engine = PolicyEngine(application, self.request.user, self.request)
|
||||||
|
engine.build()
|
||||||
|
if engine.passing:
|
||||||
|
allowed_applications.append(application)
|
||||||
|
serializer = self.get_serializer(allowed_applications, many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
Reference in a new issue