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
	 Marc 'risson' Schmitt
					Marc 'risson' Schmitt