mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
@@ -1,5 +1,5 @@
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.fields import ListField
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.mixins import (
|
||||
DestroyModelMixin,
|
||||
ListModelMixin,
|
||||
@@ -32,7 +32,7 @@ class GrantRequestViewSet(RetrieveModelMixin, DestroyModelMixin, ListModelMixin,
|
||||
serializer_class = GrantRequestSerializer
|
||||
|
||||
class GrantRequestCreateSerializer(PassiveSerializer):
|
||||
pbms = ListField(child=PrimaryKeyRelatedField(queryset=PolicyBindingModel.objects.all()))
|
||||
pbms = PrimaryKeyRelatedField(queryset=PolicyBindingModel.objects.all(), many=True)
|
||||
|
||||
@extend_schema(request=GrantRequestCreateSerializer, responses={200: LinkSerializer})
|
||||
@validate(GrantRequestCreateSerializer)
|
||||
@@ -49,4 +49,11 @@ class GrantRequestViewSet(RetrieveModelMixin, DestroyModelMixin, ListModelMixin,
|
||||
},
|
||||
)
|
||||
plan.append_stage(in_memory_stage(GrantRequestFinalStageView))
|
||||
return Response({"link": plan.to_redirect(request, flow)})
|
||||
return Response({"link": plan.to_redirect(request, flow).url})
|
||||
|
||||
@action(["POST"], detail=True)
|
||||
def fulfill(self, request: Request, *args, **kwargs):
|
||||
grant: GrantRequest = self.get_object()
|
||||
# TODO: Check if this user can fulfill this grant
|
||||
grant.fulfill(request.user)
|
||||
return Response(status=204)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.2.14 on 2026-06-05 09:52
|
||||
# Generated by Django 5.2.14 on 2026-06-05 13:35
|
||||
|
||||
import authentik.core.models
|
||||
import django.db.models.deletion
|
||||
@@ -41,7 +41,19 @@ class Migration(migrations.Migration):
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="grant_requests_created",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"fulfilled_by",
|
||||
models.ForeignKey(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||
related_name="grant_requests_fulfilled",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
+13
-2
@@ -39,7 +39,16 @@ class GrantRequest(SerializerModel, ExpiringModel, CreatedUpdatedModel):
|
||||
|
||||
uuid = models.UUIDField(default=uuid4, primary_key=True)
|
||||
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_by = models.ForeignKey(
|
||||
User, on_delete=models.CASCADE, related_name="grant_requests_created"
|
||||
)
|
||||
fulfilled_by = models.ForeignKey(
|
||||
User,
|
||||
on_delete=models.SET_DEFAULT,
|
||||
related_name="grant_requests_fulfilled",
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
# Targets access was requested to
|
||||
targets = models.ManyToManyField(PolicyBindingModel, through="GrantRequestTarget")
|
||||
@@ -55,7 +64,9 @@ class GrantRequest(SerializerModel, ExpiringModel, CreatedUpdatedModel):
|
||||
return GrantRequestSerializer
|
||||
|
||||
@transaction.atomic
|
||||
def fulfill(self):
|
||||
def fulfill(self, user: User):
|
||||
self.fulfilled_by = user
|
||||
self.save()
|
||||
if self.status != RequestState.APPROVED:
|
||||
return
|
||||
for target in GrantRequestTarget.objects.filter(request=self).all():
|
||||
|
||||
+12
-2
@@ -2,8 +2,11 @@ from datetime import timedelta
|
||||
|
||||
from django.db import transaction
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
|
||||
from authentik.events.middleware import audit_ignore
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.stage import StageView
|
||||
from authentik.pam.models import GrantRequest, GrantRequestTarget, RequestState
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
@@ -17,8 +20,8 @@ class GrantRequestFinalStageView(StageView):
|
||||
user = self.get_pending_user()
|
||||
pbms = self.executor.plan.context.get(PLAN_CONTEXT_GRANT_REQUESTED_PBMS)
|
||||
expires = now() + timedelta(hours=1)
|
||||
with transaction.atomic():
|
||||
req = GrantRequest(
|
||||
with transaction.atomic(), audit_ignore():
|
||||
req = GrantRequest.objects.create(
|
||||
created_by=user,
|
||||
data=self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}),
|
||||
expiring=True,
|
||||
@@ -31,6 +34,13 @@ class GrantRequestFinalStageView(StageView):
|
||||
target=pbm,
|
||||
binding=None,
|
||||
)
|
||||
Event.new(
|
||||
EventAction.MODEL_CREATED,
|
||||
model=req,
|
||||
hyperlink=request.build_absolute_uri(reverse("authentik_core:if-admin"))
|
||||
+ "#/pam/requests/respond",
|
||||
hyperlink_label="Respond",
|
||||
).from_http(request, user)
|
||||
return self.executor.stage_ok()
|
||||
|
||||
def post(self, request: HttpRequest) -> HttpResponse:
|
||||
|
||||
Reference in New Issue
Block a user