Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt
2025-06-04 18:05:40 +02:00
parent 107b96e65c
commit e65fabf040
2 changed files with 32 additions and 45 deletions

View File

@ -13,8 +13,8 @@ from rest_framework.request import Request
from authentik.core.models import AuthenticatedSession, User from authentik.core.models import AuthenticatedSession, User
from authentik.core.signals import login_failed, password_changed from authentik.core.signals import login_failed, password_changed
from authentik.events.apps import SYSTEM_TASK_STATUS from authentik.events.apps import SYSTEM_TASK_STATUS
from authentik.events.models import Event, EventAction, SystemTask from authentik.events.models import Event, EventAction, NotificationRule, SystemTask
from authentik.events.tasks import event_notification_handler, gdpr_cleanup from authentik.events.tasks import event_trigger_handler, gdpr_cleanup
from authentik.flows.models import Stage from authentik.flows.models import Stage
from authentik.flows.planner import PLAN_CONTEXT_OUTPOST, PLAN_CONTEXT_SOURCE, FlowPlan from authentik.flows.planner import PLAN_CONTEXT_OUTPOST, PLAN_CONTEXT_SOURCE, FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import SESSION_KEY_PLAN
@ -114,7 +114,8 @@ def on_password_changed(sender, user: User, password: str, request: HttpRequest
@receiver(post_save, sender=Event) @receiver(post_save, sender=Event)
def event_post_save_notification(sender, instance: Event, **_): def event_post_save_notification(sender, instance: Event, **_):
"""Start task to check if any policies trigger an notification on this event""" """Start task to check if any policies trigger an notification on this event"""
event_notification_handler.send(instance.event_uuid.hex) for trigger in NotificationRule.objects.all():
event_trigger_handler.send(instance.event_uuid, trigger.name)
@receiver(pre_delete, sender=User) @receiver(pre_delete, sender=User)

View File

@ -1,36 +1,27 @@
"""Event notification tasks""" """Event notification tasks"""
from uuid import UUID
from django.db.models.query_utils import Q from django.db.models.query_utils import Q
from dramatiq.actor import actor from dramatiq.actor import actor
from guardian.shortcuts import get_anonymous_user from guardian.shortcuts import get_anonymous_user
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.expression.exceptions import PropertyMappingExpressionException
from authentik.core.models import User from authentik.core.models import User
from authentik.events.models import ( from authentik.events.models import (
Event, Event,
Notification, Notification,
NotificationRule, NotificationRule,
NotificationTransport, NotificationTransport,
NotificationTransportError,
) )
from authentik.policies.engine import PolicyEngine from authentik.policies.engine import PolicyEngine
from authentik.policies.models import PolicyBinding, PolicyEngineMode from authentik.policies.models import PolicyBinding, PolicyEngineMode
from authentik.tasks.middleware import CurrentTask from authentik.tasks.middleware import CurrentTask
from authentik.tasks.models import Task, TaskStatus
LOGGER = get_logger() LOGGER = get_logger()
@actor @actor
def event_notification_handler(event_uuid: str): def event_trigger_handler(event_uuid: UUID, trigger_name: str):
"""Start task for each trigger definition"""
for trigger in NotificationRule.objects.all():
event_trigger_handler.send(event_uuid, trigger.name)
@actor
def event_trigger_handler(event_uuid: str, trigger_name: str):
"""Check if policies attached to NotificationRule match event""" """Check if policies attached to NotificationRule match event"""
event: Event = Event.objects.filter(event_uuid=event_uuid).first() event: Event = Event.objects.filter(event_uuid=event_uuid).first()
if not event: if not event:
@ -77,11 +68,14 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
for transport in trigger.transports.all(): for transport in trigger.transports.all():
for user in trigger.group.users.all(): for user in trigger.group.users.all():
LOGGER.debug("created notification") LOGGER.debug("created notification")
notification_transport.send( notification_transport.send_with_options(
transport.pk, args=(
event.pk, transport.pk,
user.pk, event.pk,
trigger.pk, user.pk,
trigger.pk,
),
rel_obj=transport,
) )
if transport.send_once: if transport.send_once:
break break
@ -90,30 +84,22 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
@actor @actor
def notification_transport(transport_pk: int, event_pk: str, user_pk: int, trigger_pk: str): def notification_transport(transport_pk: int, event_pk: str, user_pk: int, trigger_pk: str):
"""Send notification over specified transport""" """Send notification over specified transport"""
self: Task = CurrentTask.get_task() event = Event.objects.filter(pk=event_pk).first()
# TODO: fixme if not event:
# self.save_on_success = False return
try: user = User.objects.filter(pk=user_pk).first()
event = Event.objects.filter(pk=event_pk).first() if not user:
if not event: return
return trigger = NotificationRule.objects.filter(pk=trigger_pk).first()
user = User.objects.filter(pk=user_pk).first() if not trigger:
if not user: return
return notification = Notification(
trigger = NotificationRule.objects.filter(pk=trigger_pk).first() severity=trigger.severity, body=event.summary, event=event, user=user
if not trigger: )
return transport = NotificationTransport.objects.filter(pk=transport_pk).first()
notification = Notification( if not transport:
severity=trigger.severity, body=event.summary, event=event, user=user return
) transport.send(notification)
transport = NotificationTransport.objects.filter(pk=transport_pk).first()
if not transport:
return
transport.send(notification)
self.set_status(TaskStatus.SUCCESSFUL)
except (NotificationTransportError, PropertyMappingExpressionException) as exc:
self.set_error(exc)
raise exc
@actor @actor
@ -127,9 +113,9 @@ def gdpr_cleanup(user_pk: int):
@actor @actor
def notification_cleanup(): def notification_cleanup():
"""Cleanup seen notifications and notifications whose event expired.""" """Cleanup seen notifications and notifications whose event expired."""
self: Task = CurrentTask.get_task() self = CurrentTask.get_task()
notifications = Notification.objects.filter(Q(event=None) | Q(seen=True)) notifications = Notification.objects.filter(Q(event=None) | Q(seen=True))
amount = notifications.count() amount = notifications.count()
notifications.delete() notifications.delete()
LOGGER.debug("Expired notifications", amount=amount) LOGGER.debug("Expired notifications", amount=amount)
self.set_status(TaskStatus.SUCCESSFUL, f"Expired {amount} Notifications") self.info(f"Expired {amount} Notifications")