@ -1,6 +1,7 @@
|
||||
"""authentik administration overview"""
|
||||
|
||||
from django.core.cache import cache
|
||||
from django_tenants.utils import get_public_schema_name
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from packaging.version import parse
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
@ -13,6 +14,7 @@ from authentik import __version__, get_build_hash
|
||||
from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.outposts.models import Outpost
|
||||
from authentik.tenants.utils import get_current_tenant
|
||||
|
||||
|
||||
class VersionSerializer(PassiveSerializer):
|
||||
@ -35,6 +37,8 @@ class VersionSerializer(PassiveSerializer):
|
||||
|
||||
def get_version_latest(self, _) -> str:
|
||||
"""Get latest version from cache"""
|
||||
if get_current_tenant().schema_name == get_public_schema_name():
|
||||
return __version__
|
||||
version_in_cache = cache.get(VERSION_CACHE_KEY)
|
||||
if not version_in_cache: # pragma: no cover
|
||||
update_latest_version.send()
|
||||
|
@ -17,17 +17,29 @@ class AuthentikAdminConfig(ManagedAppConfig):
|
||||
verbose_name = "authentik Admin"
|
||||
default = True
|
||||
|
||||
@ManagedAppConfig.reconcile_tenant
|
||||
@ManagedAppConfig.reconcile_global
|
||||
def clear_update_notifications(self):
|
||||
from authentik.admin.tasks import clear_update_notifications
|
||||
"""Clear update notifications on startup if the notification was for the version
|
||||
we're running now."""
|
||||
from packaging.version import parse
|
||||
|
||||
clear_update_notifications.send()
|
||||
from authentik.admin.tasks import LOCAL_VERSION
|
||||
from authentik.events.models import EventAction, Notification
|
||||
|
||||
for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):
|
||||
if "new_version" not in notification.event.context:
|
||||
continue
|
||||
notification_version = notification.event.context["new_version"]
|
||||
if LOCAL_VERSION >= parse(notification_version):
|
||||
notification.delete()
|
||||
|
||||
@property
|
||||
def tenant_schedule_specs(self) -> list[ScheduleSpec]:
|
||||
def global_schedule_specs(self) -> list[ScheduleSpec]:
|
||||
from authentik.admin.tasks import update_latest_version
|
||||
|
||||
return [
|
||||
ScheduleSpec(
|
||||
actor_name="authentik.admin.tasks.update_latest_version",
|
||||
actor_name=update_latest_version.actor_name,
|
||||
crontab=f"{fqdn_rand('admin_latest_version')} * * * *",
|
||||
),
|
||||
]
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""authentik admin tasks"""
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.db import DatabaseError, InternalError, ProgrammingError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from dramatiq import actor
|
||||
from packaging.version import parse
|
||||
@ -10,7 +9,7 @@ from structlog.stdlib import get_logger
|
||||
|
||||
from authentik import __version__, get_build_hash
|
||||
from authentik.admin.apps import PROM_INFO
|
||||
from authentik.events.models import Event, EventAction, Notification
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
from authentik.tasks.middleware import CurrentTask
|
||||
@ -33,18 +32,6 @@ def _set_prom_info():
|
||||
)
|
||||
|
||||
|
||||
@actor(queue_name="startup", throws=(DatabaseError, ProgrammingError, InternalError))
|
||||
def clear_update_notifications():
|
||||
"""Clear update notifications on startup if the notification was for the version
|
||||
we're running now."""
|
||||
for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):
|
||||
if "new_version" not in notification.event.context:
|
||||
continue
|
||||
notification_version = notification.event.context["new_version"]
|
||||
if LOCAL_VERSION >= parse(notification_version):
|
||||
notification.delete()
|
||||
|
||||
|
||||
@actor
|
||||
def update_latest_version():
|
||||
"""Update latest version info"""
|
||||
|
@ -6,6 +6,7 @@ from inspect import ismethod
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.db import DatabaseError, InternalError, ProgrammingError
|
||||
from dramatiq.actor import Actor
|
||||
from dramatiq.broker import get_broker
|
||||
from structlog.stdlib import BoundLogger, get_logger
|
||||
|
||||
@ -93,6 +94,18 @@ class ManagedAppConfig(AppConfig):
|
||||
"""Get a list of schedule specs that must exist in the default tenant"""
|
||||
return []
|
||||
|
||||
@property
|
||||
def tenant_startup_tasks(self) -> list[Actor]:
|
||||
"""Get a list of actors to dispatch on startup in each tenant.
|
||||
If an associated schedule is found and is paused, the actor is skipped."""
|
||||
return []
|
||||
|
||||
@property
|
||||
def global_startup_tasks(self) -> list[Actor]:
|
||||
"""Get a list of actors to dispatch on startup in the default tenant.
|
||||
If an associated schedule is found and is paused, the actor is skipped."""
|
||||
return []
|
||||
|
||||
def _reconcile_tenant(self) -> None:
|
||||
"""reconcile ourselves for tenanted methods"""
|
||||
from authentik.tenants.models import Tenant
|
||||
@ -125,40 +138,27 @@ class AuthentikBlueprintsConfig(ManagedAppConfig):
|
||||
verbose_name = "authentik Blueprints"
|
||||
default = True
|
||||
|
||||
def import_models(self):
|
||||
super().import_models()
|
||||
self.import_module("authentik.blueprints.v1.meta.apply_blueprint")
|
||||
|
||||
@ManagedAppConfig.reconcile_global
|
||||
def tasks_middlewares(self):
|
||||
from authentik.blueprints.v1.tasks import BlueprintWatcherMiddleware
|
||||
|
||||
get_broker().add_middleware(BlueprintWatcherMiddleware())
|
||||
|
||||
@ManagedAppConfig.reconcile_tenant
|
||||
def blueprints_discovery(self):
|
||||
"""Run blueprint discovery"""
|
||||
from authentik.tasks.schedules.models import Schedule
|
||||
from authentik.blueprints.v1.tasks import blueprints_discovery, clear_failed_blueprints
|
||||
|
||||
for schedule in Schedule.objects.filter(
|
||||
actor_name__in=(
|
||||
blueprints_discovery.actor_name,
|
||||
clear_failed_blueprints.actor_name,
|
||||
),
|
||||
paused=False,
|
||||
):
|
||||
schedule.send()
|
||||
|
||||
def import_models(self):
|
||||
super().import_models()
|
||||
self.import_module("authentik.blueprints.v1.meta.apply_blueprint")
|
||||
|
||||
@property
|
||||
def tenant_schedule_specs(self) -> list[ScheduleSpec]:
|
||||
return [
|
||||
ScheduleSpec(
|
||||
actor_name="authentik.blueprints.v1.tasks.blueprints_discovery",
|
||||
crontab=f"{fqdn_rand('blueprints_v1_discover')} * * * *",
|
||||
run_on_startup=True,
|
||||
),
|
||||
ScheduleSpec(
|
||||
actor_name="authentik.blueprints.v1.tasks.clear_failed_blueprints",
|
||||
crontab=f"{fqdn_rand('blueprints_v1_cleanup')} * * * *",
|
||||
run_on_startup=True,
|
||||
),
|
||||
]
|
||||
|
@ -55,6 +55,7 @@ class AuthentikOutpostConfig(ManagedAppConfig):
|
||||
managed=MANAGED_OUTPOST,
|
||||
)
|
||||
if created:
|
||||
outpost.set_oauth_defaults()
|
||||
if KubernetesServiceConnection.objects.exists():
|
||||
outpost.service_connection = KubernetesServiceConnection.objects.first()
|
||||
elif DockerServiceConnection.objects.exists():
|
||||
|
@ -13,6 +13,8 @@ class AuthentikProviderProxyConfig(ManagedAppConfig):
|
||||
|
||||
@ManagedAppConfig.reconcile_tenant
|
||||
def proxy_set_defaults(self):
|
||||
from authentik.providers.proxy.tasks import proxy_set_defaults
|
||||
from authentik.providers.proxy.models import ProxyProvider
|
||||
|
||||
proxy_set_defaults.send()
|
||||
for provider in ProxyProvider.objects.all():
|
||||
provider.set_oauth_defaults()
|
||||
provider.save()
|
||||
|
@ -2,23 +2,11 @@
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from channels.layers import get_channel_layer
|
||||
from django.db import DatabaseError, InternalError, ProgrammingError
|
||||
from dramatiq.actor import actor
|
||||
|
||||
from authentik.outposts.consumer import OUTPOST_GROUP
|
||||
from authentik.outposts.models import Outpost, OutpostType
|
||||
from authentik.providers.oauth2.id_token import hash_session_key
|
||||
from authentik.providers.proxy.models import ProxyProvider
|
||||
|
||||
|
||||
@actor(
|
||||
throws=(DatabaseError, ProgrammingError, InternalError),
|
||||
)
|
||||
def proxy_set_defaults():
|
||||
"""Ensure correct defaults are set for all providers"""
|
||||
for provider in ProxyProvider.objects.all():
|
||||
provider.set_oauth_defaults()
|
||||
provider.save()
|
||||
|
||||
|
||||
@actor
|
||||
|
@ -23,6 +23,8 @@ class ScheduleSpec:
|
||||
|
||||
send_on_save: bool = False
|
||||
|
||||
run_on_startup: bool = False
|
||||
|
||||
def get_uid(self) -> str:
|
||||
if self.uid is not None:
|
||||
return f"{self.actor_name}:{self.uid}"
|
||||
|
Reference in New Issue
Block a user