Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt
2025-06-11 17:45:05 +02:00
parent 5e2af4a740
commit f2926fa1eb
12 changed files with 22 additions and 55 deletions

View File

@ -21,7 +21,6 @@ from authentik.core.models import (
from authentik.lib.models import SerializerModel from authentik.lib.models import SerializerModel
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction, OutgoingSyncProvider from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction, OutgoingSyncProvider
from authentik.tasks.schedules.models import ScheduledModel
def default_scopes() -> list[str]: def default_scopes() -> list[str]:

View File

@ -21,7 +21,6 @@ from authentik.core.models import (
from authentik.lib.models import SerializerModel from authentik.lib.models import SerializerModel
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction, OutgoingSyncProvider from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction, OutgoingSyncProvider
from authentik.tasks.schedules.models import ScheduledModel
class MicrosoftEntraProviderUser(SerializerModel): class MicrosoftEntraProviderUser(SerializerModel):

View File

@ -9,11 +9,6 @@ from uuid import uuid4
from django.apps import apps from django.apps import apps
from django.db import models from django.db import models
from django.db.models import Count, ExpressionWrapper, F
from django.db.models.fields import DurationField
from django.db.models.functions import Extract
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.http import HttpRequest from django.http import HttpRequest
from django.http.request import QueryDict from django.http.request import QueryDict
from django.utils.timezone import now from django.utils.timezone import now
@ -197,21 +192,15 @@ class Event(SerializerModel, ExpiringModel):
if hasattr(request, "user"): if hasattr(request, "user"):
original_user = None original_user = None
if hasattr(request, "session"): if hasattr(request, "session"):
original_user = request.session.get( original_user = request.session.get(SESSION_KEY_IMPERSONATE_ORIGINAL_USER, None)
SESSION_KEY_IMPERSONATE_ORIGINAL_USER, None
)
self.user = get_user(request.user, original_user) self.user = get_user(request.user, original_user)
if user: if user:
self.user = get_user(user) self.user = get_user(user)
# Check if we're currently impersonating, and add that user # Check if we're currently impersonating, and add that user
if hasattr(request, "session"): if hasattr(request, "session"):
if SESSION_KEY_IMPERSONATE_ORIGINAL_USER in request.session: if SESSION_KEY_IMPERSONATE_ORIGINAL_USER in request.session:
self.user = get_user( self.user = get_user(request.session[SESSION_KEY_IMPERSONATE_ORIGINAL_USER])
request.session[SESSION_KEY_IMPERSONATE_ORIGINAL_USER] self.user["on_behalf_of"] = get_user(request.session[SESSION_KEY_IMPERSONATE_USER])
)
self.user["on_behalf_of"] = get_user(
request.session[SESSION_KEY_IMPERSONATE_USER]
)
# User 255.255.255.255 as fallback if IP cannot be determined # User 255.255.255.255 as fallback if IP cannot be determined
self.client_ip = ClientIPMiddleware.get_client_ip(request) self.client_ip = ClientIPMiddleware.get_client_ip(request)
# Enrich event data # Enrich event data
@ -345,12 +334,8 @@ class NotificationTransport(SerializerModel):
"user_username": notification.user.username, "user_username": notification.user.username,
} }
if notification.event and notification.event.user: if notification.event and notification.event.user:
default_body["event_user_email"] = notification.event.user.get( default_body["event_user_email"] = notification.event.user.get("email", None)
"email", None default_body["event_user_username"] = notification.event.user.get("username", None)
)
default_body["event_user_username"] = notification.event.user.get(
"username", None
)
headers = {} headers = {}
if self.webhook_mapping_body: if self.webhook_mapping_body:
default_body = sanitize_item( default_body = sanitize_item(
@ -461,9 +446,7 @@ class NotificationTransport(SerializerModel):
"title": "", "title": "",
} }
if notification.event and notification.event.user: if notification.event and notification.event.user:
context["key_value"]["event_user_email"] = notification.event.user.get( context["key_value"]["event_user_email"] = notification.event.user.get("email", None)
"email", None
)
context["key_value"]["event_user_username"] = notification.event.user.get( context["key_value"]["event_user_username"] = notification.event.user.get(
"username", None "username", None
) )
@ -564,9 +547,7 @@ class NotificationRule(SerializerModel, PolicyBindingModel):
severity = models.TextField( severity = models.TextField(
choices=NotificationSeverity.choices, choices=NotificationSeverity.choices,
default=NotificationSeverity.NOTICE, default=NotificationSeverity.NOTICE,
help_text=_( help_text=_("Controls which severity level the created notifications will have."),
"Controls which severity level the created notifications will have."
),
) )
group = models.ForeignKey( group = models.ForeignKey(
Group, Group,

View File

@ -1,7 +1,5 @@
from django.utils.text import slugify
from dramatiq.actor import Actor from dramatiq.actor import Actor
from drf_spectacular.utils import OpenApiResponse, extend_schema from drf_spectacular.utils import extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import BooleanField, CharField, ChoiceField from rest_framework.fields import BooleanField, CharField, ChoiceField
from rest_framework.request import Request from rest_framework.request import Request

View File

@ -2,7 +2,6 @@ from django.db.models import Model
from django.db.models.query import Q from django.db.models.query import Q
from django.db.models.signals import m2m_changed, post_save, pre_delete from django.db.models.signals import m2m_changed, post_save, pre_delete
from dramatiq.actor import Actor from dramatiq.actor import Actor
from dramatiq.results.errors import ResultFailure
from authentik.core.models import Group, User from authentik.core.models import Group, User
from authentik.lib.sync.outgoing.base import Direction from authentik.lib.sync.outgoing.base import Direction

View File

@ -42,9 +42,7 @@ def pre_save_outpost(sender, instance: Outpost, **_):
# Name changes the deployment name, need to recreate # Name changes the deployment name, need to recreate
dirty += old_instance.name != instance.name dirty += old_instance.name != instance.name
# namespace requires re-create # namespace requires re-create
dirty += ( dirty += old_instance.config.kubernetes_namespace != instance.config.kubernetes_namespace
old_instance.config.kubernetes_namespace != instance.config.kubernetes_namespace
)
if bool(dirty): if bool(dirty):
LOGGER.info("Outpost needs re-deployment due to changes", instance=instance) LOGGER.info("Outpost needs re-deployment due to changes", instance=instance)
cache.set(CACHE_KEY_OUTPOST_DOWN % instance.pk.hex, old_instance) cache.set(CACHE_KEY_OUTPOST_DOWN % instance.pk.hex, old_instance)
@ -105,8 +103,6 @@ def logout_revoke_direct(sender: type[User], request: HttpRequest, **_):
@receiver(pre_delete, sender=AuthenticatedSession) @receiver(pre_delete, sender=AuthenticatedSession)
def logout_revoke( def logout_revoke(sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_):
sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_
):
"""Catch logout by expiring sessions being deleted""" """Catch logout by expiring sessions being deleted"""
outpost_session_end.send(instance.session.session_key) outpost_session_end.send(instance.session.session_key)

View File

@ -14,7 +14,6 @@ from authentik.core.models import BackchannelProvider, Group, PropertyMapping, U
from authentik.lib.models import SerializerModel from authentik.lib.models import SerializerModel
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.models import OutgoingSyncProvider from authentik.lib.sync.outgoing.models import OutgoingSyncProvider
from authentik.tasks.schedules.models import ScheduledModel
class SCIMProviderUser(SerializerModel): class SCIMProviderUser(SerializerModel):

View File

@ -2,7 +2,6 @@
from django.core.cache import cache from django.core.cache import cache
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import BooleanField, SerializerMethodField from rest_framework.fields import BooleanField, SerializerMethodField
from rest_framework.request import Request from rest_framework.request import Request

View File

@ -35,9 +35,7 @@ def send_mails(
# Use the class path instead of the class itself for serialization # Use the class path instead of the class itself for serialization
stage_class_path = class_to_path(stage.__class__) stage_class_path = class_to_path(stage.__class__)
for message in messages: for message in messages:
tasks.append( tasks.append(send_mail.message(message.__dict__, stage_class_path, str(stage.pk)))
send_mail.message(message.__dict__, stage_class_path, str(stage.pk))
)
return group(tasks).run() return group(tasks).run()

View File

@ -1,5 +1,4 @@
import dramatiq import dramatiq
from django.conf import settings
from dramatiq.broker import Broker, get_broker from dramatiq.broker import Broker, get_broker
from dramatiq.encoder import PickleEncoder from dramatiq.encoder import PickleEncoder
from dramatiq.middleware import ( from dramatiq.middleware import (

View File

@ -1,4 +1,3 @@
from django.apps import apps
from authentik.blueprints.apps import ManagedAppConfig from authentik.blueprints.apps import ManagedAppConfig
from authentik.lib.utils.reflection import get_apps from authentik.lib.utils.reflection import get_apps
@ -15,21 +14,12 @@ class AuthentikTasksSchedulesConfig(ManagedAppConfig):
def tenant_schedule_specs(self) -> list[ScheduleSpec]: def tenant_schedule_specs(self) -> list[ScheduleSpec]:
from authentik.tasks.schedules.models import ScheduledModel from authentik.tasks.schedules.models import ScheduledModel
def is_scheduled_model(klass) -> bool:
if ScheduledModel in klass.__bases__:
return True
return any(is_scheduled_model(klass) for klass in klass.__bases__)
schedules = [] schedules = []
for Model in ScheduledModel.models():
for Model in apps.get_models():
if not is_scheduled_model(Model):
continue
for obj in Model.objects.all(): for obj in Model.objects.all():
for spec in obj.schedule_specs: for spec in obj.schedule_specs:
spec.rel_obj = obj spec.rel_obj = obj
schedules.append(spec) schedules.append(spec)
return schedules return schedules
def _reconcile_schedules(self, specs: list[ScheduleSpec]): def _reconcile_schedules(self, specs: list[ScheduleSpec]):

View File

@ -3,6 +3,7 @@ from uuid import uuid4
import pgtrigger import pgtrigger
from cron_converter import Cron from cron_converter import Cron
from django.apps import apps
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@ -109,6 +110,15 @@ class ScheduledModel(models.Model):
class Meta: class Meta:
abstract = True abstract = True
@classmethod
def models(cls) -> list[models.Model]:
def is_scheduled_model(klass) -> bool:
if ScheduledModel in klass.__bases__:
return True
return any(is_scheduled_model(klass) for klass in klass.__bases__)
return [model for model in apps.get_models() if is_scheduled_model(model)]
@property @property
def schedule_specs(self) -> list[ScheduleSpec]: def schedule_specs(self) -> list[ScheduleSpec]:
raise NotImplementedError raise NotImplementedError