Files
authentik/authentik/admin/api/tasks.py
Jens L e28babb0b8 core: Initial RBAC (#6806)
* rename consent permission

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* the user version

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

t

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* initial role

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* some minor table refactoring

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix user, add assign

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add roles ui

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix backend

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add assign API for roles

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start adding toggle buttons

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start view page

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* exclude add_ permission for per-object perms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* small cleanup

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add permission list for roles

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make sidebar update

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix page header not re-rendering?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fixup

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add search

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* show first category in table groupBy except when its empty

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make model and object PK optional but required together

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* allow for setting global perms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* exclude non-authentik permissions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* exclude models which aren't allowed (base models etc)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* ensure all models have verbose_name set, exclude some more internal objects

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* lint fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix role perm assign

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add unasign for global perms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add meta changes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* clear modal state after submit

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add roles to our group

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix duplicate url names

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make recursive group query more usable

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add name field to role itself and move group creation to signal

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start sync

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* move rbac stuff to separate django app

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix lint and such

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix go

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start API changes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add more API tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make admin interface not require superuser for now, improve error handling

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* replace some IsAdminUser where applicable

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* migrate flow inspector perms to actual permission

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix license not being a serializermodel

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add permission modal to models without view page

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add additional permissions to assign/unassign permissions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add action to unassign user permissions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add permissions tab to remaining view pages

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix flow inspector permission check

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix codecov config?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add more API tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* ensure viewsets have an order set

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* hopefully the last api name change

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make perm modal less confusing

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start user view permission page

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* only make delete bulk form expandable if usedBy is set

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* expand permission tables

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add more things

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add user global permission table

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix lint

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests' url names

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add tests for assign perms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add unassign tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* rebuild permissions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* prevent assigning/unassigning permissions to internal service accounts

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* only enable default api browser in debug

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix role object permissions showing duplicate

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix role link on role object permissions table

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix object permission modal having duplicate close buttons

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* return error if user has no global perm and no object perms

also improve error display on table

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* small optimisation

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* optimise even more

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update locale

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add system permission for non-object permissions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* allow access to admin interface based on perm

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* clean

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* don't exclude base models

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-10-16 17:31:50 +02:00

135 lines
4.7 KiB
Python

"""Tasks API"""
from importlib import import_module
from django.contrib import messages
from django.http.response import Http404
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import (
CharField,
ChoiceField,
DateTimeField,
ListField,
SerializerMethodField,
)
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from structlog.stdlib import get_logger
from authentik.api.decorators import permission_required
from authentik.core.api.utils import PassiveSerializer
from authentik.events.monitored_tasks import TaskInfo, TaskResultStatus
from authentik.rbac.permissions import HasPermission
LOGGER = get_logger()
class TaskSerializer(PassiveSerializer):
"""Serialize TaskInfo and TaskResult"""
task_name = CharField()
task_description = CharField()
task_finish_timestamp = DateTimeField(source="finish_time")
task_duration = SerializerMethodField()
status = ChoiceField(
source="result.status.name",
choices=[(x.name, x.name) for x in TaskResultStatus],
)
messages = ListField(source="result.messages")
def get_task_duration(self, instance: TaskInfo) -> int:
"""Get the duration a task took to run"""
return max(instance.finish_timestamp - instance.start_timestamp, 0)
def to_representation(self, instance: TaskInfo):
"""When a new version of authentik adds fields to TaskInfo,
the API will fail with an AttributeError, as the classes
are pickled in cache. In that case, just delete the info"""
try:
return super().to_representation(instance)
# pylint: disable=broad-except
except Exception: # pragma: no cover
if isinstance(self.instance, list):
for inst in self.instance:
inst.delete()
else:
self.instance.delete()
return {}
class TaskViewSet(ViewSet):
"""Read-only view set that returns all background tasks"""
permission_classes = [HasPermission("authentik_rbac.view_system_tasks")]
serializer_class = TaskSerializer
@extend_schema(
responses={
200: TaskSerializer(many=False),
404: OpenApiResponse(description="Task not found"),
},
parameters=[
OpenApiParameter(
"id",
type=OpenApiTypes.STR,
location=OpenApiParameter.PATH,
required=True,
),
],
)
def retrieve(self, request: Request, pk=None) -> Response:
"""Get a single system task"""
task = TaskInfo.by_name(pk)
if not task:
raise Http404
return Response(TaskSerializer(task, many=False).data)
@extend_schema(responses={200: TaskSerializer(many=True)})
def list(self, request: Request) -> Response:
"""List system tasks"""
tasks = sorted(TaskInfo.all().values(), key=lambda task: task.task_name)
return Response(TaskSerializer(tasks, many=True).data)
@permission_required(None, ["authentik_rbac.run_system_tasks"])
@extend_schema(
request=OpenApiTypes.NONE,
responses={
204: OpenApiResponse(description="Task retried successfully"),
404: OpenApiResponse(description="Task not found"),
500: OpenApiResponse(description="Failed to retry task"),
},
parameters=[
OpenApiParameter(
"id",
type=OpenApiTypes.STR,
location=OpenApiParameter.PATH,
required=True,
),
],
)
@action(detail=True, methods=["post"])
def retry(self, request: Request, pk=None) -> Response:
"""Retry task"""
task = TaskInfo.by_name(pk)
if not task:
raise Http404
try:
task_module = import_module(task.task_call_module)
task_func = getattr(task_module, task.task_call_func)
LOGGER.debug("Running task", task=task_func)
task_func.delay(*task.task_call_args, **task.task_call_kwargs)
messages.success(
self.request,
_("Successfully re-scheduled Task %(name)s!" % {"name": task.task_name}),
)
return Response(status=204)
except (ImportError, AttributeError): # pragma: no cover
LOGGER.warning("Failed to run task, remove state", task=task)
# if we get an import error, the module path has probably changed
task.delete()
return Response(status=500)