wip: description, fix total_seconds
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
@ -33,10 +33,10 @@ def _set_prom_info():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Update latest version info"))
|
||||||
def update_latest_version():
|
def update_latest_version():
|
||||||
"""Update latest version info"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
|
raise RuntimeError("whatever")
|
||||||
if CONFIG.get_bool("disable_update_check"):
|
if CONFIG.get_bool("disable_update_check"):
|
||||||
cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
|
cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
|
||||||
self.info("Version check disabled.")
|
self.info("Version check disabled.")
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
"""v1 blueprints tasks"""
|
"""v1 blueprints tasks"""
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, field
|
from dataclasses import asdict, dataclass, field
|
||||||
from hashlib import sha512
|
from hashlib import sha512
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -106,10 +108,10 @@ class BlueprintEventHandler(FileSystemEventHandler):
|
|||||||
|
|
||||||
|
|
||||||
@actor(
|
@actor(
|
||||||
|
description=_("Find blueprints as `blueprints_find` does, but return a safe dict"),
|
||||||
throws=(DatabaseError, ProgrammingError, InternalError),
|
throws=(DatabaseError, ProgrammingError, InternalError),
|
||||||
)
|
)
|
||||||
def blueprints_find_dict():
|
def blueprints_find_dict():
|
||||||
"""Find blueprints as `blueprints_find` does, but return a safe dict"""
|
|
||||||
blueprints = []
|
blueprints = []
|
||||||
for blueprint in blueprints_find():
|
for blueprint in blueprints_find():
|
||||||
blueprints.append(sanitize_dict(asdict(blueprint)))
|
blueprints.append(sanitize_dict(asdict(blueprint)))
|
||||||
@ -145,9 +147,11 @@ def blueprints_find() -> list[BlueprintFile]:
|
|||||||
return blueprints
|
return blueprints
|
||||||
|
|
||||||
|
|
||||||
@actor(throws=(DatabaseError, ProgrammingError, InternalError))
|
@actor(
|
||||||
|
description=_("Find blueprints and check if they need to be created in the database"),
|
||||||
|
throws=(DatabaseError, ProgrammingError, InternalError),
|
||||||
|
)
|
||||||
def blueprints_discovery(path: str | None = None):
|
def blueprints_discovery(path: str | None = None):
|
||||||
"""Find blueprints and check if they need to be created in the database"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
count = 0
|
count = 0
|
||||||
for blueprint in blueprints_find():
|
for blueprint in blueprints_find():
|
||||||
@ -185,9 +189,8 @@ def check_blueprint_v1_file(blueprint: BlueprintFile):
|
|||||||
apply_blueprint.send_with_options(args=(instance.pk,), rel_obj=instance)
|
apply_blueprint.send_with_options(args=(instance.pk,), rel_obj=instance)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Apply single blueprint"))
|
||||||
def apply_blueprint(instance_pk: UUID):
|
def apply_blueprint(instance_pk: UUID):
|
||||||
"""Apply single blueprint"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
self.set_uid(str(instance_pk))
|
self.set_uid(str(instance_pk))
|
||||||
instance: BlueprintInstance | None = None
|
instance: BlueprintInstance | None = None
|
||||||
@ -237,9 +240,8 @@ def apply_blueprint(instance_pk: UUID):
|
|||||||
instance.save()
|
instance.save()
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Remove blueprints which couldn't be fetched"))
|
||||||
def clear_failed_blueprints():
|
def clear_failed_blueprints():
|
||||||
"""Remove blueprints which couldn't be fetched"""
|
|
||||||
# Exclude OCI blueprints as those might be temporarily unavailable
|
# Exclude OCI blueprints as those might be temporarily unavailable
|
||||||
for blueprint in BlueprintInstance.objects.exclude(path__startswith=OCI_PREFIX):
|
for blueprint in BlueprintInstance.objects.exclude(path__startswith=OCI_PREFIX):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
"""authentik core tasks"""
|
"""authentik core tasks"""
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
@ -18,9 +20,8 @@ from authentik.tasks.models import Task
|
|||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Remove expired objects"))
|
||||||
def clean_expired_models():
|
def clean_expired_models():
|
||||||
"""Remove expired objects"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
for cls in ExpiringModel.__subclasses__():
|
for cls in ExpiringModel.__subclasses__():
|
||||||
cls: ExpiringModel
|
cls: ExpiringModel
|
||||||
@ -34,9 +35,8 @@ def clean_expired_models():
|
|||||||
self.info(f"Expired {amount} {cls._meta.verbose_name_plural}")
|
self.info(f"Expired {amount} {cls._meta.verbose_name_plural}")
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Remove temporary users created by SAML Sources"))
|
||||||
def clean_temporary_users():
|
def clean_temporary_users():
|
||||||
"""Remove temporary users created by SAML Sources"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
_now = datetime.now()
|
_now = datetime.now()
|
||||||
deleted_users = 0
|
deleted_users = 0
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
"""Crypto tasks"""
|
"""Crypto tasks"""
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -35,9 +37,8 @@ def ensure_certificate_valid(body: str):
|
|||||||
return body
|
return body
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Discover, import and update certificates from the filesystem"))
|
||||||
def certificate_discovery():
|
def certificate_discovery():
|
||||||
"""Discover, import and update certificates from the filesystem"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
certs = {}
|
certs = {}
|
||||||
private_keys = {}
|
private_keys = {}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ from django.db.models.aggregates import Count
|
|||||||
from django_dramatiq_postgres.middleware import CurrentTask
|
from django_dramatiq_postgres.middleware import CurrentTask
|
||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik.enterprise.policies.unique_password.models import (
|
from authentik.enterprise.policies.unique_password.models import (
|
||||||
UniquePasswordPolicy,
|
UniquePasswordPolicy,
|
||||||
@ -12,11 +13,12 @@ from authentik.tasks.models import Task
|
|||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(
|
||||||
|
description=_(
|
||||||
|
"Check if any UniquePasswordPolicy exists, and if not, purge the password history table."
|
||||||
|
)
|
||||||
|
)
|
||||||
def check_and_purge_password_history():
|
def check_and_purge_password_history():
|
||||||
"""Check if any UniquePasswordPolicy exists, and if not, purge the password history table.
|
|
||||||
This is run on a schedule instead of being triggered by policy binding deletion.
|
|
||||||
"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
|
|
||||||
if not UniquePasswordPolicy.objects.exists():
|
if not UniquePasswordPolicy.objects.exists():
|
||||||
@ -28,10 +30,8 @@ def check_and_purge_password_history():
|
|||||||
self.info("Not purging password histories, a unique password policy exists")
|
self.info("Not purging password histories, a unique password policy exists")
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Remove user password history that are too old."))
|
||||||
def trim_password_histories():
|
def trim_password_histories():
|
||||||
self: Task = CurrentTask.get_task()
|
|
||||||
|
|
||||||
"""Removes rows from UserPasswordHistory older than
|
"""Removes rows from UserPasswordHistory older than
|
||||||
the `n` most recent entries.
|
the `n` most recent entries.
|
||||||
|
|
||||||
@ -39,6 +39,8 @@ def trim_password_histories():
|
|||||||
UniquePasswordPolicy policies.
|
UniquePasswordPolicy policies.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self: Task = CurrentTask.get_task()
|
||||||
|
|
||||||
# No policy, we'll let the cleanup above do its thing
|
# No policy, we'll let the cleanup above do its thing
|
||||||
if not UniquePasswordPolicy.objects.exists():
|
if not UniquePasswordPolicy.objects.exists():
|
||||||
return
|
return
|
||||||
|
|||||||
@ -4,26 +4,27 @@ from dramatiq.actor import actor
|
|||||||
|
|
||||||
from authentik.enterprise.providers.google_workspace.models import GoogleWorkspaceProvider
|
from authentik.enterprise.providers.google_workspace.models import GoogleWorkspaceProvider
|
||||||
from authentik.lib.sync.outgoing.tasks import SyncTasks
|
from authentik.lib.sync.outgoing.tasks import SyncTasks
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
sync_tasks = SyncTasks(GoogleWorkspaceProvider)
|
sync_tasks = SyncTasks(GoogleWorkspaceProvider)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync Google Workspace provider objects."))
|
||||||
def google_workspace_sync_objects(*args, **kwargs):
|
def google_workspace_sync_objects(*args, **kwargs):
|
||||||
return sync_tasks.sync_objects(*args, **kwargs)
|
return sync_tasks.sync_objects(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Full sync for Google Workspace provider."))
|
||||||
def google_workspace_sync(provider_pk: int, *args, **kwargs):
|
def google_workspace_sync(provider_pk: int, *args, **kwargs):
|
||||||
"""Run full sync for Google Workspace provider"""
|
"""Run full sync for Google Workspace provider"""
|
||||||
return sync_tasks.sync(provider_pk, google_workspace_sync_objects)
|
return sync_tasks.sync(provider_pk, google_workspace_sync_objects)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync a direct object (user, group) for Google Workspace provider."))
|
||||||
def google_workspace_sync_direct(*args, **kwargs):
|
def google_workspace_sync_direct(*args, **kwargs):
|
||||||
return sync_tasks.sync_signal_direct(*args, **kwargs)
|
return sync_tasks.sync_signal_direct(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync a related object (memberships) for Google Workspace provider."))
|
||||||
def google_workspace_sync_m2m(*args, **kwargs):
|
def google_workspace_sync_m2m(*args, **kwargs):
|
||||||
return sync_tasks.sync_signal_m2m(*args, **kwargs)
|
return sync_tasks.sync_signal_m2m(*args, **kwargs)
|
||||||
|
|||||||
@ -4,26 +4,27 @@ from dramatiq.actor import actor
|
|||||||
|
|
||||||
from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProvider
|
from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProvider
|
||||||
from authentik.lib.sync.outgoing.tasks import SyncTasks
|
from authentik.lib.sync.outgoing.tasks import SyncTasks
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
sync_tasks = SyncTasks(MicrosoftEntraProvider)
|
sync_tasks = SyncTasks(MicrosoftEntraProvider)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync Microsoft Entra provider objects."))
|
||||||
def microsoft_entra_sync_objects(*args, **kwargs):
|
def microsoft_entra_sync_objects(*args, **kwargs):
|
||||||
return sync_tasks.sync_objects(*args, **kwargs)
|
return sync_tasks.sync_objects(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Full sync for Microsoft Entra provider."))
|
||||||
def microsoft_entra_sync(provider_pk: int, *args, **kwargs):
|
def microsoft_entra_sync(provider_pk: int, *args, **kwargs):
|
||||||
"""Run full sync for Microsoft Entra provider"""
|
"""Run full sync for Microsoft Entra provider"""
|
||||||
return sync_tasks.sync(provider_pk, microsoft_entra_sync_objects)
|
return sync_tasks.sync(provider_pk, microsoft_entra_sync_objects)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync a direct object (user, group) for Microsoft Entra provider."))
|
||||||
def microsoft_entra_sync_direct(*args, **kwargs):
|
def microsoft_entra_sync_direct(*args, **kwargs):
|
||||||
return sync_tasks.sync_signal_direct(*args, **kwargs)
|
return sync_tasks.sync_signal_direct(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync a related object (memberships) for Microsoft Entra provider."))
|
||||||
def microsoft_entra_sync_m2m(*args, **kwargs):
|
def microsoft_entra_sync_m2m(*args, **kwargs):
|
||||||
return sync_tasks.sync_signal_m2m(*args, **kwargs)
|
return sync_tasks.sync_signal_m2m(*args, **kwargs)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
@ -61,7 +62,7 @@ def _check_app_access(stream: Stream, event_data: dict) -> bool:
|
|||||||
return engine.passing
|
return engine.passing
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Send an SSF event"))
|
||||||
def _send_ssf_event(stream_uuid: UUID, event_data: dict[str, Any]):
|
def _send_ssf_event(stream_uuid: UUID, event_data: dict[str, Any]):
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
"""Enterprise tasks"""
|
"""Enterprise tasks"""
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
|
|
||||||
from authentik.enterprise.license import LicenseKey
|
from authentik.enterprise.license import LicenseKey
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Update enterprise license status."))
|
||||||
def enterprise_update_usage():
|
def enterprise_update_usage():
|
||||||
"""Update enterprise license status"""
|
|
||||||
LicenseKey.get_total().record_usage()
|
LicenseKey.get_total().record_usage()
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.db.models.query_utils import Q
|
from django.db.models.query_utils import Q
|
||||||
from django_dramatiq_postgres.middleware import CurrentTask
|
from django_dramatiq_postgres.middleware import CurrentTask
|
||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
@ -22,7 +23,7 @@ from authentik.tasks.models import Task
|
|||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Check if policies attached to NotificationRule match event"))
|
||||||
def event_trigger_handler(event_uuid: UUID, trigger_name: str):
|
def event_trigger_handler(event_uuid: UUID, 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()
|
||||||
@ -79,7 +80,7 @@ def event_trigger_handler(event_uuid: UUID, trigger_name: str):
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Send notification"))
|
||||||
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"""
|
||||||
event = Event.objects.filter(pk=event_pk).first()
|
event = Event.objects.filter(pk=event_pk).first()
|
||||||
@ -100,7 +101,7 @@ def notification_transport(transport_pk: int, event_pk: str, user_pk: int, trigg
|
|||||||
transport.send(notification)
|
transport.send(notification)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Cleanup events for GDPR compliance"))
|
||||||
def gdpr_cleanup(user_pk: int):
|
def gdpr_cleanup(user_pk: int):
|
||||||
"""cleanup events from gdpr_compliance"""
|
"""cleanup events from gdpr_compliance"""
|
||||||
events = Event.objects.filter(user__pk=user_pk)
|
events = Event.objects.filter(user__pk=user_pk)
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
"""outpost tasks"""
|
"""outpost tasks"""
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from os import R_OK, access
|
from os import R_OK, access
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -82,7 +84,7 @@ def controller_for_outpost(outpost: Outpost) -> type[BaseController] | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Update cached state of a service connection"))
|
||||||
def outpost_service_connection_monitor(connection_pk: Any):
|
def outpost_service_connection_monitor(connection_pk: Any):
|
||||||
"""Update cached state of a service connection"""
|
"""Update cached state of a service connection"""
|
||||||
connection: OutpostServiceConnection = (
|
connection: OutpostServiceConnection = (
|
||||||
@ -107,7 +109,7 @@ def outpost_service_connection_monitor(connection_pk: Any):
|
|||||||
cache.set(connection.state_key, state, timeout=None)
|
cache.set(connection.state_key, state, timeout=None)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Create/update/monitor/delete the deployment of an Outpost"))
|
||||||
def outpost_controller(outpost_pk: str, action: str = "up", from_cache: bool = False):
|
def outpost_controller(outpost_pk: str, action: str = "up", from_cache: bool = False):
|
||||||
"""Create/update/monitor/delete the deployment of an Outpost"""
|
"""Create/update/monitor/delete the deployment of an Outpost"""
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
@ -140,7 +142,7 @@ def outpost_controller(outpost_pk: str, action: str = "up", from_cache: bool = F
|
|||||||
self.info(log)
|
self.info(log)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Ensure that all Outposts have valid Service Accounts and Tokens"))
|
||||||
def outpost_token_ensurer():
|
def outpost_token_ensurer():
|
||||||
"""
|
"""
|
||||||
Periodically ensure that all Outposts have valid Service Accounts and Tokens
|
Periodically ensure that all Outposts have valid Service Accounts and Tokens
|
||||||
@ -153,7 +155,7 @@ def outpost_token_ensurer():
|
|||||||
self.info(f"Successfully checked {len(all_outposts)} Outposts.")
|
self.info(f"Successfully checked {len(all_outposts)} Outposts.")
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("If an Outpost is saved, ensure that token is created/updated"))
|
||||||
def outpost_post_save(model_class: str, model_pk: Any):
|
def outpost_post_save(model_class: str, model_pk: Any):
|
||||||
"""If an Outpost is saved, Ensure that token is created/updated
|
"""If an Outpost is saved, Ensure that token is created/updated
|
||||||
|
|
||||||
@ -225,7 +227,7 @@ def _outpost_single_update(outpost: Outpost, layer=None):
|
|||||||
async_to_sync(layer.group_send)(group, {"type": "event.update"})
|
async_to_sync(layer.group_send)(group, {"type": "event.update"})
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Checks the local environment and create Service connections."))
|
||||||
def outpost_connection_discovery():
|
def outpost_connection_discovery():
|
||||||
"""Checks the local environment and create Service connections."""
|
"""Checks the local environment and create Service connections."""
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
@ -266,9 +268,8 @@ def outpost_connection_discovery():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Terminate session on all outposts"))
|
||||||
def outpost_session_end(session_id: str):
|
def outpost_session_end(session_id: str):
|
||||||
"""Update outpost instances connected to a single outpost"""
|
|
||||||
layer = get_channel_layer()
|
layer = get_channel_layer()
|
||||||
hashed_session_id = hash_session_key(session_id)
|
hashed_session_id = hash_session_key(session_id)
|
||||||
for outpost in Outpost.objects.all():
|
for outpost in Outpost.objects.all():
|
||||||
|
|||||||
@ -7,11 +7,11 @@ from dramatiq.actor import actor
|
|||||||
from authentik.outposts.consumer import OUTPOST_GROUP
|
from authentik.outposts.consumer import OUTPOST_GROUP
|
||||||
from authentik.outposts.models import Outpost, OutpostType
|
from authentik.outposts.models import Outpost, OutpostType
|
||||||
from authentik.providers.oauth2.id_token import hash_session_key
|
from authentik.providers.oauth2.id_token import hash_session_key
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Terminate session on Proxy outpost"))
|
||||||
def proxy_on_logout(session_id: str):
|
def proxy_on_logout(session_id: str):
|
||||||
"""Update outpost instances connected to a single outpost"""
|
|
||||||
layer = get_channel_layer()
|
layer = get_channel_layer()
|
||||||
hashed_session_id = hash_session_key(session_id)
|
hashed_session_id = hash_session_key(session_id)
|
||||||
for outpost in Outpost.objects.filter(type=OutpostType.PROXY):
|
for outpost in Outpost.objects.filter(type=OutpostType.PROXY):
|
||||||
|
|||||||
@ -4,26 +4,27 @@ from dramatiq.actor import actor
|
|||||||
|
|
||||||
from authentik.lib.sync.outgoing.tasks import SyncTasks
|
from authentik.lib.sync.outgoing.tasks import SyncTasks
|
||||||
from authentik.providers.scim.models import SCIMProvider
|
from authentik.providers.scim.models import SCIMProvider
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
sync_tasks = SyncTasks(SCIMProvider)
|
sync_tasks = SyncTasks(SCIMProvider)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync SCIM provider objects."))
|
||||||
def scim_sync_objects(*args, **kwargs):
|
def scim_sync_objects(*args, **kwargs):
|
||||||
return sync_tasks.sync_objects(*args, **kwargs)
|
return sync_tasks.sync_objects(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Full sync for SCIM provider."))
|
||||||
def scim_sync(provider_pk: int, *args, **kwargs):
|
def scim_sync(provider_pk: int, *args, **kwargs):
|
||||||
"""Run full sync for SCIM provider"""
|
"""Run full sync for SCIM provider"""
|
||||||
return sync_tasks.sync(provider_pk, scim_sync_objects)
|
return sync_tasks.sync(provider_pk, scim_sync_objects)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync a direct object (user, group) for SCIM provider."))
|
||||||
def scim_sync_direct(*args, **kwargs):
|
def scim_sync_direct(*args, **kwargs):
|
||||||
return sync_tasks.sync_signal_direct(*args, **kwargs)
|
return sync_tasks.sync_signal_direct(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Sync a related object (memberships) for SCIM provider."))
|
||||||
def scim_sync_m2m(*args, **kwargs):
|
def scim_sync_m2m(*args, **kwargs):
|
||||||
return sync_tasks.sync_signal_m2m(*args, **kwargs)
|
return sync_tasks.sync_signal_m2m(*args, **kwargs)
|
||||||
|
|||||||
@ -360,8 +360,8 @@ DRAMATIQ = {
|
|||||||
"task_model": "authentik.tasks.models.Task",
|
"task_model": "authentik.tasks.models.Task",
|
||||||
"task_purge_interval": timedelta_from_string(
|
"task_purge_interval": timedelta_from_string(
|
||||||
CONFIG.get("worker.task_purge_interval")
|
CONFIG.get("worker.task_purge_interval")
|
||||||
).total_seconds,
|
).total_seconds(),
|
||||||
"task_expiration": timedelta_from_string(CONFIG.get("worker.task_expiration")).total_seconds,
|
"task_expiration": timedelta_from_string(CONFIG.get("worker.task_expiration")).total_seconds(),
|
||||||
"autodiscovery": {
|
"autodiscovery": {
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
"setup_module": "authentik.tasks.setup",
|
"setup_module": "authentik.tasks.setup",
|
||||||
@ -372,7 +372,7 @@ DRAMATIQ = {
|
|||||||
"threads": CONFIG.get_int("worker.threads", 1),
|
"threads": CONFIG.get_int("worker.threads", 1),
|
||||||
"consumer_listen_timeout": timedelta_from_string(
|
"consumer_listen_timeout": timedelta_from_string(
|
||||||
CONFIG.get("worker.consumer_listen_timeout")
|
CONFIG.get("worker.consumer_listen_timeout")
|
||||||
),
|
).total_seconds(),
|
||||||
},
|
},
|
||||||
"scheduler_class": "authentik.tasks.schedules.scheduler.Scheduler",
|
"scheduler_class": "authentik.tasks.schedules.scheduler.Scheduler",
|
||||||
"schedule_model": "authentik.tasks.schedules.models.Schedule",
|
"schedule_model": "authentik.tasks.schedules.models.Schedule",
|
||||||
@ -400,6 +400,7 @@ DRAMATIQ = {
|
|||||||
("authentik.tasks.middleware.TenantMiddleware", {}),
|
("authentik.tasks.middleware.TenantMiddleware", {}),
|
||||||
("authentik.tasks.middleware.RelObjMiddleware", {}),
|
("authentik.tasks.middleware.RelObjMiddleware", {}),
|
||||||
("authentik.tasks.middleware.LoggingMiddleware", {}),
|
("authentik.tasks.middleware.LoggingMiddleware", {}),
|
||||||
|
("authentik.tasks.middleware.DescriptionMiddleware", {}),
|
||||||
),
|
),
|
||||||
"test": TEST,
|
"test": TEST,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from django_dramatiq_postgres.middleware import CurrentTask
|
|||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.sync.outgoing.exceptions import StopSync
|
from authentik.lib.sync.outgoing.exceptions import StopSync
|
||||||
from authentik.lib.utils.errors import exception_to_string
|
from authentik.lib.utils.errors import exception_to_string
|
||||||
@ -16,7 +17,7 @@ LOGGER = get_logger()
|
|||||||
CACHE_KEY_STATUS = "goauthentik.io/sources/kerberos/status/"
|
CACHE_KEY_STATUS = "goauthentik.io/sources/kerberos/status/"
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Check connectivity for Kerberos sources"))
|
||||||
def kerberos_connectivity_check(pk: str):
|
def kerberos_connectivity_check(pk: str):
|
||||||
"""Check connectivity for Kerberos Sources"""
|
"""Check connectivity for Kerberos Sources"""
|
||||||
# 2 hour timeout, this task should run every hour
|
# 2 hour timeout, this task should run every hour
|
||||||
@ -28,9 +29,11 @@ def kerberos_connectivity_check(pk: str):
|
|||||||
cache.set(CACHE_KEY_STATUS + source.slug, status, timeout=timeout)
|
cache.set(CACHE_KEY_STATUS + source.slug, status, timeout=timeout)
|
||||||
|
|
||||||
|
|
||||||
@actor(time_limit=(60 * 60 * CONFIG.get_int("sources.kerberos.task_timeout_hours")) * 2.5 * 1000)
|
@actor(
|
||||||
|
time_limit=(60 * 60 * CONFIG.get_int("sources.kerberos.task_timeout_hours")) * 2.5 * 1000,
|
||||||
|
description=_("Sync Kerberos source"),
|
||||||
|
)
|
||||||
def kerberos_sync(pk: str):
|
def kerberos_sync(pk: str):
|
||||||
"""Sync a single source"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
source: KerberosSource = KerberosSource.objects.filter(enabled=True, pk=pk).first()
|
source: KerberosSource = KerberosSource.objects.filter(enabled=True, pk=pk).first()
|
||||||
if not source:
|
if not source:
|
||||||
|
|||||||
@ -9,6 +9,7 @@ from dramatiq.composition import group
|
|||||||
from dramatiq.message import Message
|
from dramatiq.message import Message
|
||||||
from ldap3.core.exceptions import LDAPException
|
from ldap3.core.exceptions import LDAPException
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.sync.outgoing.exceptions import StopSync
|
from authentik.lib.sync.outgoing.exceptions import StopSync
|
||||||
@ -33,7 +34,7 @@ CACHE_KEY_PREFIX = "goauthentik.io/sources/ldap/page/"
|
|||||||
CACHE_KEY_STATUS = "goauthentik.io/sources/ldap/status/"
|
CACHE_KEY_STATUS = "goauthentik.io/sources/ldap/status/"
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Check connectivity for LDAP sources"))
|
||||||
def ldap_connectivity_check(pk: str | None = None):
|
def ldap_connectivity_check(pk: str | None = None):
|
||||||
"""Check connectivity for LDAP Sources"""
|
"""Check connectivity for LDAP Sources"""
|
||||||
timeout = 60 * 60 * 2
|
timeout = 60 * 60 * 2
|
||||||
@ -48,8 +49,8 @@ def ldap_connectivity_check(pk: str | None = None):
|
|||||||
# We take the configured hours timeout time by 3.5 as we run user and
|
# We take the configured hours timeout time by 3.5 as we run user and
|
||||||
# group in parallel and then membership, then deletions, so 3x is to cover the serial tasks,
|
# group in parallel and then membership, then deletions, so 3x is to cover the serial tasks,
|
||||||
# and 0.5x on top of that to give some more leeway
|
# and 0.5x on top of that to give some more leeway
|
||||||
time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours") * 1000)
|
time_limit=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours") * 1000) * 3.5,
|
||||||
* 3.5,
|
description=_("Sync LDAP source"),
|
||||||
)
|
)
|
||||||
def ldap_sync(source_pk: str):
|
def ldap_sync(source_pk: str):
|
||||||
"""Sync a single source"""
|
"""Sync a single source"""
|
||||||
@ -116,7 +117,10 @@ def ldap_sync_paginator(source: LDAPSource, sync: type[BaseLDAPSynchronizer]) ->
|
|||||||
return messages
|
return messages
|
||||||
|
|
||||||
|
|
||||||
@actor(time_limit=60 * 60 * CONFIG.get_int("ldap.task_timeout_hours") * 1000)
|
@actor(
|
||||||
|
time_limit=60 * 60 * CONFIG.get_int("ldap.task_timeout_hours") * 1000,
|
||||||
|
description=_("Sync page for LDAP source"),
|
||||||
|
)
|
||||||
def ldap_sync_page(source_pk: str, sync_class: str, page_cache_key: str):
|
def ldap_sync_page(source_pk: str, sync_class: str, page_cache_key: str):
|
||||||
"""Synchronization of an LDAP Source"""
|
"""Synchronization of an LDAP Source"""
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from django_dramatiq_postgres.middleware import CurrentTask
|
|||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
from requests import RequestException
|
from requests import RequestException
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik.lib.utils.http import get_http_session
|
from authentik.lib.utils.http import get_http_session
|
||||||
from authentik.sources.oauth.models import OAuthSource
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
@ -14,9 +15,12 @@ from authentik.tasks.models import Task
|
|||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(
|
||||||
|
description=_(
|
||||||
|
"Update OAuth sources' config from well_known, and JWKS info from the configured URL"
|
||||||
|
)
|
||||||
|
)
|
||||||
def update_well_known_jwks():
|
def update_well_known_jwks():
|
||||||
"""Update OAuth sources' config from well_known, and JWKS info from the configured URL"""
|
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
session = get_http_session()
|
session = get_http_session()
|
||||||
for source in OAuthSource.objects.all().exclude(oidc_well_known_url=""):
|
for source in OAuthSource.objects.all().exclude(oidc_well_known_url=""):
|
||||||
|
|||||||
@ -9,9 +9,10 @@ from authentik.lib.utils.errors import exception_to_string
|
|||||||
from authentik.sources.plex.models import PlexSource
|
from authentik.sources.plex.models import PlexSource
|
||||||
from authentik.sources.plex.plex import PlexAuth
|
from authentik.sources.plex.plex import PlexAuth
|
||||||
from authentik.tasks.models import Task
|
from authentik.tasks.models import Task
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Check the validity of a Plex source"))
|
||||||
def check_plex_token(source_pk: str):
|
def check_plex_token(source_pk: str):
|
||||||
"""Check the validity of a Plex source."""
|
"""Check the validity of a Plex source."""
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
|
|||||||
@ -9,6 +9,7 @@ from django.db.transaction import atomic
|
|||||||
from django_dramatiq_postgres.middleware import CurrentTask
|
from django_dramatiq_postgres.middleware import CurrentTask
|
||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
from fido2.mds3 import filter_revoked, parse_blob
|
from fido2.mds3 import filter_revoked, parse_blob
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik.stages.authenticator_webauthn.models import (
|
from authentik.stages.authenticator_webauthn.models import (
|
||||||
UNKNOWN_DEVICE_TYPE_AAGUID,
|
UNKNOWN_DEVICE_TYPE_AAGUID,
|
||||||
@ -29,7 +30,7 @@ def mds_ca() -> bytes:
|
|||||||
return _raw_root.read()
|
return _raw_root.read()
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Background task to import FIDO Alliance MDS blob and AAGUIDs into database"))
|
||||||
def webauthn_mds_import(force=False):
|
def webauthn_mds_import(force=False):
|
||||||
"""Background task to import FIDO Alliance MDS blob and AAGUIDs into database"""
|
"""Background task to import FIDO Alliance MDS blob and AAGUIDs into database"""
|
||||||
self: Task = CurrentTask.get_task()
|
self: Task = CurrentTask.get_task()
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from typing import Any
|
|||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
from django.core.mail.utils import DNS_NAME
|
from django.core.mail.utils import DNS_NAME
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_dramatiq_postgres.middleware import CurrentTask
|
from django_dramatiq_postgres.middleware import CurrentTask
|
||||||
from dramatiq.actor import actor
|
from dramatiq.actor import actor
|
||||||
from dramatiq.composition import group
|
from dramatiq.composition import group
|
||||||
@ -48,7 +49,7 @@ def get_email_body(email: EmailMultiAlternatives) -> str:
|
|||||||
return email.body
|
return email.body
|
||||||
|
|
||||||
|
|
||||||
@actor
|
@actor(description=_("Send email"))
|
||||||
def send_mail(
|
def send_mail(
|
||||||
message: dict[Any, Any],
|
message: dict[Any, Any],
|
||||||
stage_class_path: str | None = None,
|
stage_class_path: str | None = None,
|
||||||
|
|||||||
@ -72,3 +72,9 @@ class LoggingMiddleware(Middleware):
|
|||||||
message=f"Task {task.actor_name} encountered an error: "
|
message=f"Task {task.actor_name} encountered an error: "
|
||||||
"{exception_to_string(exception)}",
|
"{exception_to_string(exception)}",
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
|
|
||||||
|
class DescriptionMiddleware(Middleware):
|
||||||
|
@property
|
||||||
|
def actor_options(self):
|
||||||
|
return {"description"}
|
||||||
|
|||||||
@ -52,9 +52,9 @@ class ScheduleSerializer(ModelSerializer):
|
|||||||
actor: Actor = get_broker().get_actor(instance.actor_name)
|
actor: Actor = get_broker().get_actor(instance.actor_name)
|
||||||
except ActorNotFound:
|
except ActorNotFound:
|
||||||
return "FIXME this shouldn't happen"
|
return "FIXME this shouldn't happen"
|
||||||
if not actor.fn.__doc__:
|
if "description" not in actor.options:
|
||||||
return "no doc"
|
return "no doc"
|
||||||
return actor.fn.__doc__.strip()
|
return actor.options["description"]
|
||||||
|
|
||||||
|
|
||||||
class ScheduleFilter(FilterSet):
|
class ScheduleFilter(FilterSet):
|
||||||
|
|||||||
Reference in New Issue
Block a user