From eaa3d11df8311b92f9b5b58b988445c32e80dd21 Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 9 May 2023 14:46:47 +0200 Subject: [PATCH] api: modular urls (#5551) * api: make API urls modular load API urls from app module's urls file instead of a single static file Signed-off-by: Jens Langhammer * refactor websocket url mounting Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/admin/urls.py | 22 ++ authentik/api/v3/urls.py | 271 ++---------------- authentik/blueprints/urls.py | 6 + authentik/core/apps.py | 1 - authentik/core/urls.py | 27 ++ authentik/crypto/urls.py | 6 + authentik/events/urls.py | 14 + authentik/flows/urls.py | 27 +- authentik/outposts/apps.py | 1 - authentik/outposts/urls.py | 13 + authentik/policies/dummy/urls.py | 4 + authentik/policies/event_matcher/urls.py | 4 + authentik/policies/expiry/urls.py | 4 + authentik/policies/expression/urls.py | 4 + authentik/policies/password/urls.py | 4 + authentik/policies/reputation/urls.py | 7 + authentik/policies/urls.py | 8 + authentik/providers/ldap/urls.py | 7 + authentik/providers/oauth2/urls.py | 15 + authentik/providers/proxy/urls.py | 7 + authentik/providers/radius/urls.py | 7 + authentik/providers/saml/urls.py | 7 + authentik/providers/scim/urls.py | 8 + authentik/root/websocket.py | 14 +- authentik/sources/ldap/urls.py | 7 + authentik/sources/oauth/urls.py | 7 + authentik/sources/plex/urls.py | 8 + authentik/sources/saml/urls.py | 7 + authentik/stages/authenticator_duo/urls.py | 16 ++ authentik/stages/authenticator_sms/urls.py | 16 ++ authentik/stages/authenticator_static/urls.py | 16 ++ authentik/stages/authenticator_totp/urls.py | 12 + .../stages/authenticator_validate/urls.py | 4 + .../stages/authenticator_webauthn/urls.py | 16 ++ authentik/stages/captcha/urls.py | 4 + authentik/stages/consent/urls.py | 7 + authentik/stages/deny/urls.py | 4 + authentik/stages/dummy/urls.py | 4 + authentik/stages/email/urls.py | 4 + authentik/stages/identification/urls.py | 4 + authentik/stages/invitation/urls.py | 7 + authentik/stages/password/urls.py | 4 + authentik/stages/prompt/urls.py | 7 + authentik/stages/user_delete/urls.py | 4 + authentik/stages/user_login/urls.py | 6 + authentik/stages/user_logout/urls.py | 4 + authentik/stages/user_write/urls.py | 4 + authentik/tenants/urls.py | 6 + 48 files changed, 412 insertions(+), 254 deletions(-) create mode 100644 authentik/admin/urls.py create mode 100644 authentik/blueprints/urls.py create mode 100644 authentik/crypto/urls.py create mode 100644 authentik/events/urls.py create mode 100644 authentik/policies/dummy/urls.py create mode 100644 authentik/policies/event_matcher/urls.py create mode 100644 authentik/policies/expiry/urls.py create mode 100644 authentik/policies/expression/urls.py create mode 100644 authentik/policies/password/urls.py create mode 100644 authentik/policies/reputation/urls.py create mode 100644 authentik/policies/urls.py create mode 100644 authentik/providers/ldap/urls.py create mode 100644 authentik/providers/proxy/urls.py create mode 100644 authentik/providers/radius/urls.py create mode 100644 authentik/providers/scim/urls.py create mode 100644 authentik/sources/ldap/urls.py create mode 100644 authentik/sources/plex/urls.py create mode 100644 authentik/stages/authenticator_duo/urls.py create mode 100644 authentik/stages/authenticator_sms/urls.py create mode 100644 authentik/stages/authenticator_static/urls.py create mode 100644 authentik/stages/authenticator_totp/urls.py create mode 100644 authentik/stages/authenticator_validate/urls.py create mode 100644 authentik/stages/authenticator_webauthn/urls.py create mode 100644 authentik/stages/captcha/urls.py create mode 100644 authentik/stages/consent/urls.py create mode 100644 authentik/stages/deny/urls.py create mode 100644 authentik/stages/dummy/urls.py create mode 100644 authentik/stages/email/urls.py create mode 100644 authentik/stages/identification/urls.py create mode 100644 authentik/stages/invitation/urls.py create mode 100644 authentik/stages/password/urls.py create mode 100644 authentik/stages/prompt/urls.py create mode 100644 authentik/stages/user_delete/urls.py create mode 100644 authentik/stages/user_login/urls.py create mode 100644 authentik/stages/user_logout/urls.py create mode 100644 authentik/stages/user_write/urls.py create mode 100644 authentik/tenants/urls.py diff --git a/authentik/admin/urls.py b/authentik/admin/urls.py new file mode 100644 index 000000000..25ad5885b --- /dev/null +++ b/authentik/admin/urls.py @@ -0,0 +1,22 @@ +"""API URLs""" +from django.urls import path + +from authentik.admin.api.meta import AppsViewSet +from authentik.admin.api.metrics import AdministrationMetricsViewSet +from authentik.admin.api.system import SystemView +from authentik.admin.api.tasks import TaskViewSet +from authentik.admin.api.version import VersionView +from authentik.admin.api.workers import WorkerView + +api_urlpatterns = [ + ("admin/system_tasks", TaskViewSet, "admin_system_tasks"), + ("admin/apps", AppsViewSet, "apps"), + path( + "admin/metrics/", + AdministrationMetricsViewSet.as_view(), + name="admin_metrics", + ), + path("admin/version/", VersionView.as_view(), name="admin_version"), + path("admin/workers/", WorkerView.as_view(), name="admin_workers"), + path("admin/system/", SystemView.as_view(), name="admin_system"), +] diff --git a/authentik/api/v3/urls.py b/authentik/api/v3/urls.py index 591f1adee..f6b2f45f8 100644 --- a/authentik/api/v3/urls.py +++ b/authentik/api/v3/urls.py @@ -1,269 +1,50 @@ """api v3 urls""" +from importlib import import_module + from django.urls import path +from django.urls.resolvers import URLPattern from django.views.decorators.cache import cache_page from drf_spectacular.views import SpectacularAPIView from rest_framework import routers +from structlog.stdlib import get_logger -from authentik.admin.api.meta import AppsViewSet -from authentik.admin.api.metrics import AdministrationMetricsViewSet -from authentik.admin.api.system import SystemView -from authentik.admin.api.tasks import TaskViewSet -from authentik.admin.api.version import VersionView -from authentik.admin.api.workers import WorkerView from authentik.api.v3.config import ConfigView from authentik.api.views import APIBrowserView -from authentik.blueprints.api import BlueprintInstanceViewSet -from authentik.core.api.applications import ApplicationViewSet -from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet -from authentik.core.api.devices import AdminDeviceViewSet, DeviceViewSet -from authentik.core.api.groups import GroupViewSet -from authentik.core.api.propertymappings import PropertyMappingViewSet -from authentik.core.api.providers import ProviderViewSet -from authentik.core.api.sources import SourceViewSet, UserSourceConnectionViewSet -from authentik.core.api.tokens import TokenViewSet -from authentik.core.api.users import UserViewSet -from authentik.crypto.api import CertificateKeyPairViewSet -from authentik.events.api.events import EventViewSet -from authentik.events.api.notification_mappings import NotificationWebhookMappingViewSet -from authentik.events.api.notification_rules import NotificationRuleViewSet -from authentik.events.api.notification_transports import NotificationTransportViewSet -from authentik.events.api.notifications import NotificationViewSet -from authentik.flows.api.bindings import FlowStageBindingViewSet -from authentik.flows.api.flows import FlowViewSet -from authentik.flows.api.stages import StageViewSet -from authentik.flows.views.executor import FlowExecutorView -from authentik.flows.views.inspector import FlowInspectorView -from authentik.outposts.api.outposts import OutpostViewSet -from authentik.outposts.api.service_connections import ( - DockerServiceConnectionViewSet, - KubernetesServiceConnectionViewSet, - ServiceConnectionViewSet, -) -from authentik.policies.api.bindings import PolicyBindingViewSet -from authentik.policies.api.policies import PolicyViewSet -from authentik.policies.dummy.api import DummyPolicyViewSet -from authentik.policies.event_matcher.api import EventMatcherPolicyViewSet -from authentik.policies.expiry.api import PasswordExpiryPolicyViewSet -from authentik.policies.expression.api import ExpressionPolicyViewSet -from authentik.policies.password.api import PasswordPolicyViewSet -from authentik.policies.reputation.api import ReputationPolicyViewSet, ReputationViewSet -from authentik.providers.ldap.api import LDAPOutpostConfigViewSet, LDAPProviderViewSet -from authentik.providers.oauth2.api.providers import OAuth2ProviderViewSet -from authentik.providers.oauth2.api.scopes import ScopeMappingViewSet -from authentik.providers.oauth2.api.tokens import ( - AccessTokenViewSet, - AuthorizationCodeViewSet, - RefreshTokenViewSet, -) -from authentik.providers.proxy.api import ProxyOutpostConfigViewSet, ProxyProviderViewSet -from authentik.providers.radius.api import RadiusOutpostConfigViewSet, RadiusProviderViewSet -from authentik.providers.saml.api.property_mapping import SAMLPropertyMappingViewSet -from authentik.providers.saml.api.providers import SAMLProviderViewSet -from authentik.providers.scim.api.property_mapping import SCIMMappingViewSet -from authentik.providers.scim.api.providers import SCIMProviderViewSet -from authentik.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet -from authentik.sources.oauth.api.source import OAuthSourceViewSet -from authentik.sources.oauth.api.source_connection import UserOAuthSourceConnectionViewSet -from authentik.sources.plex.api.source import PlexSourceViewSet -from authentik.sources.plex.api.source_connection import PlexSourceConnectionViewSet -from authentik.sources.saml.api.source import SAMLSourceViewSet -from authentik.sources.saml.api.source_connection import UserSAMLSourceConnectionViewSet -from authentik.stages.authenticator_duo.api import ( - AuthenticatorDuoStageViewSet, - DuoAdminDeviceViewSet, - DuoDeviceViewSet, -) -from authentik.stages.authenticator_sms.api import ( - AuthenticatorSMSStageViewSet, - SMSAdminDeviceViewSet, - SMSDeviceViewSet, -) -from authentik.stages.authenticator_static.api import ( - AuthenticatorStaticStageViewSet, - StaticAdminDeviceViewSet, - StaticDeviceViewSet, -) -from authentik.stages.authenticator_totp.api import ( - AuthenticatorTOTPStageViewSet, - TOTPAdminDeviceViewSet, - TOTPDeviceViewSet, -) -from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageViewSet -from authentik.stages.authenticator_webauthn.api import ( - AuthenticateWebAuthnStageViewSet, - WebAuthnAdminDeviceViewSet, - WebAuthnDeviceViewSet, -) -from authentik.stages.captcha.api import CaptchaStageViewSet -from authentik.stages.consent.api import ConsentStageViewSet, UserConsentViewSet -from authentik.stages.deny.api import DenyStageViewSet -from authentik.stages.dummy.api import DummyStageViewSet -from authentik.stages.email.api import EmailStageViewSet -from authentik.stages.identification.api import IdentificationStageViewSet -from authentik.stages.invitation.api import InvitationStageViewSet, InvitationViewSet -from authentik.stages.password.api import PasswordStageViewSet -from authentik.stages.prompt.api import PromptStageViewSet, PromptViewSet -from authentik.stages.user_delete.api import UserDeleteStageViewSet -from authentik.stages.user_login.api import UserLoginStageViewSet -from authentik.stages.user_logout.api import UserLogoutStageViewSet -from authentik.stages.user_write.api import UserWriteStageViewSet -from authentik.tenants.api import TenantViewSet +from authentik.lib.utils.reflection import get_apps + +LOGGER = get_logger() router = routers.DefaultRouter() router.include_format_suffixes = False -router.register("admin/system_tasks", TaskViewSet, basename="admin_system_tasks") -router.register("admin/apps", AppsViewSet, basename="apps") +_other_urls = [] +for _authentik_app in get_apps(): + try: + api_urls = import_module(f"{_authentik_app.name}.urls") + except (ModuleNotFoundError, ImportError): + continue + if not hasattr(api_urls, "api_urlpatterns"): + continue + urls: list = getattr(api_urls, "api_urlpatterns") + for url in urls: + if isinstance(url, URLPattern): + _other_urls.append(url) + else: + router.register(*url) + LOGGER.debug( + "Mounted API URLs", + app_name=_authentik_app.name, + ) -router.register("core/authenticated_sessions", AuthenticatedSessionViewSet) -router.register("core/applications", ApplicationViewSet) -router.register("core/groups", GroupViewSet) -router.register("core/users", UserViewSet) -router.register("core/user_consent", UserConsentViewSet) -router.register("core/tokens", TokenViewSet) -router.register("core/tenants", TenantViewSet) - -router.register("outposts/instances", OutpostViewSet) -router.register("outposts/service_connections/all", ServiceConnectionViewSet) -router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet) -router.register("outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet) -router.register("outposts/proxy", ProxyOutpostConfigViewSet) -router.register("outposts/ldap", LDAPOutpostConfigViewSet) -router.register("outposts/radius", RadiusOutpostConfigViewSet) - -router.register("flows/instances", FlowViewSet) -router.register("flows/bindings", FlowStageBindingViewSet) - -router.register("crypto/certificatekeypairs", CertificateKeyPairViewSet) - -router.register("events/events", EventViewSet) -router.register("events/notifications", NotificationViewSet) -router.register("events/transports", NotificationTransportViewSet) -router.register("events/rules", NotificationRuleViewSet) - -router.register("managed/blueprints", BlueprintInstanceViewSet) - -router.register("sources/all", SourceViewSet) -router.register("sources/user_connections/all", UserSourceConnectionViewSet) -router.register("sources/user_connections/oauth", UserOAuthSourceConnectionViewSet) -router.register("sources/user_connections/plex", PlexSourceConnectionViewSet) -router.register("sources/user_connections/saml", UserSAMLSourceConnectionViewSet) -router.register("sources/ldap", LDAPSourceViewSet) -router.register("sources/saml", SAMLSourceViewSet) -router.register("sources/oauth", OAuthSourceViewSet) -router.register("sources/plex", PlexSourceViewSet) - -router.register("policies/all", PolicyViewSet) -router.register("policies/bindings", PolicyBindingViewSet) -router.register("policies/expression", ExpressionPolicyViewSet) -router.register("policies/event_matcher", EventMatcherPolicyViewSet) -router.register("policies/password_expiry", PasswordExpiryPolicyViewSet) -router.register("policies/password", PasswordPolicyViewSet) -router.register("policies/reputation/scores", ReputationViewSet) -router.register("policies/reputation", ReputationPolicyViewSet) - -router.register("providers/all", ProviderViewSet) -router.register("providers/ldap", LDAPProviderViewSet) -router.register("providers/proxy", ProxyProviderViewSet) -router.register("providers/oauth2", OAuth2ProviderViewSet) -router.register("providers/saml", SAMLProviderViewSet) -router.register("providers/scim", SCIMProviderViewSet) -router.register("providers/radius", RadiusProviderViewSet) - -router.register("oauth2/authorization_codes", AuthorizationCodeViewSet) -router.register("oauth2/refresh_tokens", RefreshTokenViewSet) -router.register("oauth2/access_tokens", AccessTokenViewSet) - -router.register("propertymappings/all", PropertyMappingViewSet) -router.register("propertymappings/ldap", LDAPPropertyMappingViewSet) -router.register("propertymappings/saml", SAMLPropertyMappingViewSet) -router.register("propertymappings/scope", ScopeMappingViewSet) -router.register("propertymappings/notification", NotificationWebhookMappingViewSet) -router.register("propertymappings/scim", SCIMMappingViewSet) - -router.register("authenticators/all", DeviceViewSet, basename="device") -router.register("authenticators/duo", DuoDeviceViewSet) -router.register("authenticators/sms", SMSDeviceViewSet) -router.register("authenticators/static", StaticDeviceViewSet) -router.register("authenticators/totp", TOTPDeviceViewSet) -router.register("authenticators/webauthn", WebAuthnDeviceViewSet) -router.register( - "authenticators/admin/all", - AdminDeviceViewSet, - basename="admin-device", -) -router.register( - "authenticators/admin/duo", - DuoAdminDeviceViewSet, - basename="admin-duodevice", -) -router.register( - "authenticators/admin/sms", - SMSAdminDeviceViewSet, - basename="admin-smsdevice", -) -router.register( - "authenticators/admin/static", - StaticAdminDeviceViewSet, - basename="admin-staticdevice", -) -router.register("authenticators/admin/totp", TOTPAdminDeviceViewSet, basename="admin-totpdevice") -router.register( - "authenticators/admin/webauthn", - WebAuthnAdminDeviceViewSet, - basename="admin-webauthndevice", -) - -router.register("stages/all", StageViewSet) -router.register("stages/authenticator/duo", AuthenticatorDuoStageViewSet) -router.register("stages/authenticator/sms", AuthenticatorSMSStageViewSet) -router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet) -router.register("stages/authenticator/totp", AuthenticatorTOTPStageViewSet) -router.register("stages/authenticator/validate", AuthenticatorValidateStageViewSet) -router.register("stages/authenticator/webauthn", AuthenticateWebAuthnStageViewSet) -router.register("stages/captcha", CaptchaStageViewSet) -router.register("stages/consent", ConsentStageViewSet) -router.register("stages/deny", DenyStageViewSet) -router.register("stages/email", EmailStageViewSet) -router.register("stages/identification", IdentificationStageViewSet) -router.register("stages/invitation/invitations", InvitationViewSet) -router.register("stages/invitation/stages", InvitationStageViewSet) -router.register("stages/password", PasswordStageViewSet) -router.register("stages/prompt/prompts", PromptViewSet) -router.register("stages/prompt/stages", PromptStageViewSet) -router.register("stages/user_delete", UserDeleteStageViewSet) -router.register("stages/user_login", UserLoginStageViewSet) -router.register("stages/user_logout", UserLogoutStageViewSet) -router.register("stages/user_write", UserWriteStageViewSet) - -router.register("stages/dummy", DummyStageViewSet) -router.register("policies/dummy", DummyPolicyViewSet) urlpatterns = ( [ path("", APIBrowserView.as_view(), name="schema-browser"), ] + router.urls + + _other_urls + [ - path( - "admin/metrics/", - AdministrationMetricsViewSet.as_view(), - name="admin_metrics", - ), - path("admin/version/", VersionView.as_view(), name="admin_version"), - path("admin/workers/", WorkerView.as_view(), name="admin_workers"), - path("admin/system/", SystemView.as_view(), name="admin_system"), path("root/config/", ConfigView.as_view(), name="config"), - path( - "flows/executor//", - FlowExecutorView.as_view(), - name="flow-executor", - ), - path( - "flows/inspector//", - FlowInspectorView.as_view(), - name="flow-inspector", - ), path("schema/", cache_page(86400)(SpectacularAPIView.as_view()), name="schema"), ] ) diff --git a/authentik/blueprints/urls.py b/authentik/blueprints/urls.py new file mode 100644 index 000000000..7f18c0094 --- /dev/null +++ b/authentik/blueprints/urls.py @@ -0,0 +1,6 @@ +"""API URLs""" +from authentik.blueprints.api import BlueprintInstanceViewSet + +api_urlpatterns = [ + ("managed/blueprints", BlueprintInstanceViewSet), +] diff --git a/authentik/core/apps.py b/authentik/core/apps.py index 072e59a9e..719b2abb1 100644 --- a/authentik/core/apps.py +++ b/authentik/core/apps.py @@ -11,7 +11,6 @@ class AuthentikCoreConfig(ManagedAppConfig): label = "authentik_core" verbose_name = "authentik Core" mountpoint = "" - ws_mountpoint = "authentik.core.urls" default = True def reconcile_load_core_signals(self): diff --git a/authentik/core/urls.py b/authentik/core/urls.py index b45288bfe..0fc6aab0a 100644 --- a/authentik/core/urls.py +++ b/authentik/core/urls.py @@ -7,6 +7,15 @@ from django.urls import path from django.views.decorators.csrf import ensure_csrf_cookie from django.views.generic import RedirectView +from authentik.core.api.applications import ApplicationViewSet +from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet +from authentik.core.api.devices import AdminDeviceViewSet, DeviceViewSet +from authentik.core.api.groups import GroupViewSet +from authentik.core.api.propertymappings import PropertyMappingViewSet +from authentik.core.api.providers import ProviderViewSet +from authentik.core.api.sources import SourceViewSet, UserSourceConnectionViewSet +from authentik.core.api.tokens import TokenViewSet +from authentik.core.api.users import UserViewSet from authentik.core.views import apps, impersonate from authentik.core.views.debug import AccessDeniedView from authentik.core.views.interface import FlowInterfaceView, InterfaceView @@ -69,6 +78,24 @@ urlpatterns = [ ), ] +api_urlpatterns = [ + ("core/authenticated_sessions", AuthenticatedSessionViewSet), + ("core/applications", ApplicationViewSet), + ("core/groups", GroupViewSet), + ("core/users", UserViewSet), + ("core/tokens", TokenViewSet), + ("sources/all", SourceViewSet), + ("sources/user_connections/all", UserSourceConnectionViewSet), + ("providers/all", ProviderViewSet), + ("propertymappings/all", PropertyMappingViewSet), + ("authenticators/all", DeviceViewSet, "device"), + ( + "authenticators/admin/all", + AdminDeviceViewSet, + "admin-device", + ), +] + websocket_urlpatterns = [ path( "ws/client/", diff --git a/authentik/crypto/urls.py b/authentik/crypto/urls.py new file mode 100644 index 000000000..a71a89084 --- /dev/null +++ b/authentik/crypto/urls.py @@ -0,0 +1,6 @@ +"""API URLs""" +from authentik.crypto.api import CertificateKeyPairViewSet + +api_urlpatterns = [ + ("crypto/certificatekeypairs", CertificateKeyPairViewSet), +] diff --git a/authentik/events/urls.py b/authentik/events/urls.py new file mode 100644 index 000000000..5d7d40e5f --- /dev/null +++ b/authentik/events/urls.py @@ -0,0 +1,14 @@ +"""API URLs""" +from authentik.events.api.events import EventViewSet +from authentik.events.api.notification_mappings import NotificationWebhookMappingViewSet +from authentik.events.api.notification_rules import NotificationRuleViewSet +from authentik.events.api.notification_transports import NotificationTransportViewSet +from authentik.events.api.notifications import NotificationViewSet + +api_urlpatterns = [ + ("events/events", EventViewSet), + ("events/notifications", NotificationViewSet), + ("events/transports", NotificationTransportViewSet), + ("events/rules", NotificationRuleViewSet), + ("propertymappings/notification", NotificationWebhookMappingViewSet), +] diff --git a/authentik/flows/urls.py b/authentik/flows/urls.py index 3c5bed0bc..4642df07e 100644 --- a/authentik/flows/urls.py +++ b/authentik/flows/urls.py @@ -1,8 +1,17 @@ """flow urls""" from django.urls import path +from authentik.flows.api.bindings import FlowStageBindingViewSet +from authentik.flows.api.flows import FlowViewSet +from authentik.flows.api.stages import StageViewSet from authentik.flows.models import FlowDesignation -from authentik.flows.views.executor import CancelView, ConfigureFlowInitView, ToDefaultFlow +from authentik.flows.views.executor import ( + CancelView, + ConfigureFlowInitView, + FlowExecutorView, + ToDefaultFlow, +) +from authentik.flows.views.inspector import FlowInspectorView urlpatterns = [ path( @@ -22,3 +31,19 @@ urlpatterns = [ name="configure", ), ] + +api_urlpatterns = [ + ("flows/instances", FlowViewSet), + ("flows/bindings", FlowStageBindingViewSet), + ("stages/all", StageViewSet), + path( + "flows/executor//", + FlowExecutorView.as_view(), + name="flow-executor", + ), + path( + "flows/inspector//", + FlowInspectorView.as_view(), + name="flow-inspector", + ), +] diff --git a/authentik/outposts/apps.py b/authentik/outposts/apps.py index ea29ebdca..6898a170a 100644 --- a/authentik/outposts/apps.py +++ b/authentik/outposts/apps.py @@ -24,7 +24,6 @@ class AuthentikOutpostConfig(ManagedAppConfig): label = "authentik_outposts" verbose_name = "authentik Outpost" default = True - ws_mountpoint = "authentik.outposts.urls" def reconcile_load_outposts_signals(self): """Load outposts signals""" diff --git a/authentik/outposts/urls.py b/authentik/outposts/urls.py index 1e3982c09..353dfd13c 100644 --- a/authentik/outposts/urls.py +++ b/authentik/outposts/urls.py @@ -1,9 +1,22 @@ """Outpost Websocket URLS""" from django.urls import path +from authentik.outposts.api.outposts import OutpostViewSet +from authentik.outposts.api.service_connections import ( + DockerServiceConnectionViewSet, + KubernetesServiceConnectionViewSet, + ServiceConnectionViewSet, +) from authentik.outposts.channels import OutpostConsumer from authentik.root.middleware import ChannelsLoggingMiddleware websocket_urlpatterns = [ path("ws/outpost//", ChannelsLoggingMiddleware(OutpostConsumer.as_asgi())), ] + +api_urlpatterns = [ + ("outposts/instances", OutpostViewSet), + ("outposts/service_connections/all", ServiceConnectionViewSet), + ("outposts/service_connections/docker", DockerServiceConnectionViewSet), + ("outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet), +] diff --git a/authentik/policies/dummy/urls.py b/authentik/policies/dummy/urls.py new file mode 100644 index 000000000..1ff9867b3 --- /dev/null +++ b/authentik/policies/dummy/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.policies.dummy.api import DummyPolicyViewSet + +api_urlpatterns = [("policies/dummy", DummyPolicyViewSet)] diff --git a/authentik/policies/event_matcher/urls.py b/authentik/policies/event_matcher/urls.py new file mode 100644 index 000000000..a9a2dfd85 --- /dev/null +++ b/authentik/policies/event_matcher/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.policies.event_matcher.api import EventMatcherPolicyViewSet + +api_urlpatterns = [("policies/event_matcher", EventMatcherPolicyViewSet)] diff --git a/authentik/policies/expiry/urls.py b/authentik/policies/expiry/urls.py new file mode 100644 index 000000000..d5945201b --- /dev/null +++ b/authentik/policies/expiry/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.policies.expiry.api import PasswordExpiryPolicyViewSet + +api_urlpatterns = [("policies/password_expiry", PasswordExpiryPolicyViewSet)] diff --git a/authentik/policies/expression/urls.py b/authentik/policies/expression/urls.py new file mode 100644 index 000000000..ad554fea9 --- /dev/null +++ b/authentik/policies/expression/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.policies.expression.api import ExpressionPolicyViewSet + +api_urlpatterns = [("policies/expression", ExpressionPolicyViewSet)] diff --git a/authentik/policies/password/urls.py b/authentik/policies/password/urls.py new file mode 100644 index 000000000..c979d62ee --- /dev/null +++ b/authentik/policies/password/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.policies.password.api import PasswordPolicyViewSet + +api_urlpatterns = [("policies/password", PasswordPolicyViewSet)] diff --git a/authentik/policies/reputation/urls.py b/authentik/policies/reputation/urls.py new file mode 100644 index 000000000..7af81ae5c --- /dev/null +++ b/authentik/policies/reputation/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.policies.reputation.api import ReputationPolicyViewSet, ReputationViewSet + +api_urlpatterns = [ + ("policies/reputation/scores", ReputationViewSet), + ("policies/reputation", ReputationPolicyViewSet), +] diff --git a/authentik/policies/urls.py b/authentik/policies/urls.py new file mode 100644 index 000000000..377578080 --- /dev/null +++ b/authentik/policies/urls.py @@ -0,0 +1,8 @@ +"""API URLs""" +from authentik.policies.api.bindings import PolicyBindingViewSet +from authentik.policies.api.policies import PolicyViewSet + +api_urlpatterns = [ + ("policies/all", PolicyViewSet), + ("policies/bindings", PolicyBindingViewSet), +] diff --git a/authentik/providers/ldap/urls.py b/authentik/providers/ldap/urls.py new file mode 100644 index 000000000..fc32e4954 --- /dev/null +++ b/authentik/providers/ldap/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.providers.ldap.api import LDAPOutpostConfigViewSet, LDAPProviderViewSet + +api_urlpatterns = [ + ("outposts/ldap", LDAPOutpostConfigViewSet), + ("providers/ldap", LDAPProviderViewSet), +] diff --git a/authentik/providers/oauth2/urls.py b/authentik/providers/oauth2/urls.py index 70c6e1239..f310fa1bc 100644 --- a/authentik/providers/oauth2/urls.py +++ b/authentik/providers/oauth2/urls.py @@ -2,6 +2,13 @@ from django.urls import path from django.views.generic.base import RedirectView +from authentik.providers.oauth2.api.providers import OAuth2ProviderViewSet +from authentik.providers.oauth2.api.scopes import ScopeMappingViewSet +from authentik.providers.oauth2.api.tokens import ( + AccessTokenViewSet, + AuthorizationCodeViewSet, + RefreshTokenViewSet, +) from authentik.providers.oauth2.views.authorize import AuthorizationFlowInitView from authentik.providers.oauth2.views.device_backchannel import DeviceView from authentik.providers.oauth2.views.introspection import TokenIntrospectionView @@ -51,3 +58,11 @@ urlpatterns = [ name="provider-info", ), ] + +api_urlpatterns = [ + ("providers/oauth2", OAuth2ProviderViewSet), + ("propertymappings/scope", ScopeMappingViewSet), + ("oauth2/authorization_codes", AuthorizationCodeViewSet), + ("oauth2/refresh_tokens", RefreshTokenViewSet), + ("oauth2/access_tokens", AccessTokenViewSet), +] diff --git a/authentik/providers/proxy/urls.py b/authentik/providers/proxy/urls.py new file mode 100644 index 000000000..fa4706de6 --- /dev/null +++ b/authentik/providers/proxy/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.providers.proxy.api import ProxyOutpostConfigViewSet, ProxyProviderViewSet + +api_urlpatterns = [ + ("outposts/proxy", ProxyOutpostConfigViewSet), + ("providers/proxy", ProxyProviderViewSet), +] diff --git a/authentik/providers/radius/urls.py b/authentik/providers/radius/urls.py new file mode 100644 index 000000000..b0c1bd33f --- /dev/null +++ b/authentik/providers/radius/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.providers.radius.api import RadiusOutpostConfigViewSet, RadiusProviderViewSet + +api_urlpatterns = [ + ("outposts/radius", RadiusOutpostConfigViewSet), + ("providers/radius", RadiusProviderViewSet), +] diff --git a/authentik/providers/saml/urls.py b/authentik/providers/saml/urls.py index 67907835d..02dda0c38 100644 --- a/authentik/providers/saml/urls.py +++ b/authentik/providers/saml/urls.py @@ -1,6 +1,8 @@ """authentik SAML IDP URLs""" from django.urls import path +from authentik.providers.saml.api.property_mapping import SAMLPropertyMappingViewSet +from authentik.providers.saml.api.providers import SAMLProviderViewSet from authentik.providers.saml.views import metadata, slo, sso urlpatterns = [ @@ -39,3 +41,8 @@ urlpatterns = [ name="metadata-download", ), ] + +api_urlpatterns = [ + ("propertymappings/saml", SAMLPropertyMappingViewSet), + ("providers/saml", SAMLProviderViewSet), +] diff --git a/authentik/providers/scim/urls.py b/authentik/providers/scim/urls.py new file mode 100644 index 000000000..045862dba --- /dev/null +++ b/authentik/providers/scim/urls.py @@ -0,0 +1,8 @@ +"""API URLs""" +from authentik.providers.scim.api.property_mapping import SCIMMappingViewSet +from authentik.providers.scim.api.providers import SCIMProviderViewSet + +api_urlpatterns = [ + ("providers/scim", SCIMProviderViewSet), + ("propertymappings/scim", SCIMMappingViewSet), +] diff --git a/authentik/root/websocket.py b/authentik/root/websocket.py index 8a044056f..df32a35af 100644 --- a/authentik/root/websocket.py +++ b/authentik/root/websocket.py @@ -9,13 +9,15 @@ LOGGER = get_logger() websocket_urlpatterns = [] for _authentik_app in get_apps(): - mountpoint = getattr(_authentik_app, "ws_mountpoint", None) - if not mountpoint: + try: + api_urls = import_module(f"{_authentik_app.name}.urls") + except ModuleNotFoundError: continue - ws_paths = import_module(mountpoint) - websocket_urlpatterns.extend(getattr(ws_paths, "websocket_urlpatterns")) + if not hasattr(api_urls, "websocket_urlpatterns"): + continue + urls: list = getattr(api_urls, "websocket_urlpatterns") + websocket_urlpatterns.extend(urls) LOGGER.debug( - "Mounted URLs", + "Mounted Websocket URLs", app_name=_authentik_app.name, - app_mountpoint=mountpoint, ) diff --git a/authentik/sources/ldap/urls.py b/authentik/sources/ldap/urls.py new file mode 100644 index 000000000..30390f332 --- /dev/null +++ b/authentik/sources/ldap/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet + +api_urlpatterns = [ + ("propertymappings/ldap", LDAPPropertyMappingViewSet), + ("sources/ldap", LDAPSourceViewSet), +] diff --git a/authentik/sources/oauth/urls.py b/authentik/sources/oauth/urls.py index ecc32a14c..5914f7d01 100644 --- a/authentik/sources/oauth/urls.py +++ b/authentik/sources/oauth/urls.py @@ -2,6 +2,8 @@ from django.urls import path +from authentik.sources.oauth.api.source import OAuthSourceViewSet +from authentik.sources.oauth.api.source_connection import UserOAuthSourceConnectionViewSet from authentik.sources.oauth.types.registry import RequestKind from authentik.sources.oauth.views.dispatcher import DispatcherView @@ -17,3 +19,8 @@ urlpatterns = [ name="oauth-client-callback", ), ] + +api_urlpatterns = [ + ("sources/user_connections/oauth", UserOAuthSourceConnectionViewSet), + ("sources/oauth", OAuthSourceViewSet), +] diff --git a/authentik/sources/plex/urls.py b/authentik/sources/plex/urls.py new file mode 100644 index 000000000..d47b26930 --- /dev/null +++ b/authentik/sources/plex/urls.py @@ -0,0 +1,8 @@ +"""API URLs""" +from authentik.sources.plex.api.source import PlexSourceViewSet +from authentik.sources.plex.api.source_connection import PlexSourceConnectionViewSet + +api_urlpatterns = [ + ("sources/user_connections/plex", PlexSourceConnectionViewSet), + ("sources/plex", PlexSourceViewSet), +] diff --git a/authentik/sources/saml/urls.py b/authentik/sources/saml/urls.py index 889f3f57a..ee95631db 100644 --- a/authentik/sources/saml/urls.py +++ b/authentik/sources/saml/urls.py @@ -1,6 +1,8 @@ """saml sp urls""" from django.urls import path +from authentik.sources.saml.api.source import SAMLSourceViewSet +from authentik.sources.saml.api.source_connection import UserSAMLSourceConnectionViewSet from authentik.sources.saml.views import ACSView, InitiateView, MetadataView, SLOView urlpatterns = [ @@ -9,3 +11,8 @@ urlpatterns = [ path("/slo/", SLOView.as_view(), name="slo"), path("/metadata/", MetadataView.as_view(), name="metadata"), ] + +api_urlpatterns = [ + ("sources/user_connections/saml", UserSAMLSourceConnectionViewSet), + ("sources/saml", SAMLSourceViewSet), +] diff --git a/authentik/stages/authenticator_duo/urls.py b/authentik/stages/authenticator_duo/urls.py new file mode 100644 index 000000000..8a4124741 --- /dev/null +++ b/authentik/stages/authenticator_duo/urls.py @@ -0,0 +1,16 @@ +"""API URLs""" +from authentik.stages.authenticator_duo.api import ( + AuthenticatorDuoStageViewSet, + DuoAdminDeviceViewSet, + DuoDeviceViewSet, +) + +api_urlpatterns = [ + ("authenticators/duo", DuoDeviceViewSet), + ( + "authenticators/admin/duo", + DuoAdminDeviceViewSet, + "admin-duodevice", + ), + ("stages/authenticator/duo", AuthenticatorDuoStageViewSet), +] diff --git a/authentik/stages/authenticator_sms/urls.py b/authentik/stages/authenticator_sms/urls.py new file mode 100644 index 000000000..56b315f61 --- /dev/null +++ b/authentik/stages/authenticator_sms/urls.py @@ -0,0 +1,16 @@ +"""API URLs""" +from authentik.stages.authenticator_sms.api import ( + AuthenticatorSMSStageViewSet, + SMSAdminDeviceViewSet, + SMSDeviceViewSet, +) + +api_urlpatterns = [ + ("authenticators/sms", SMSDeviceViewSet), + ( + "authenticators/admin/sms", + SMSAdminDeviceViewSet, + "admin-smsdevice", + ), + ("stages/authenticator/sms", AuthenticatorSMSStageViewSet), +] diff --git a/authentik/stages/authenticator_static/urls.py b/authentik/stages/authenticator_static/urls.py new file mode 100644 index 000000000..57a79cae7 --- /dev/null +++ b/authentik/stages/authenticator_static/urls.py @@ -0,0 +1,16 @@ +"""API URLs""" +from authentik.stages.authenticator_static.api import ( + AuthenticatorStaticStageViewSet, + StaticAdminDeviceViewSet, + StaticDeviceViewSet, +) + +api_urlpatterns = [ + ("authenticators/static", StaticDeviceViewSet), + ( + "authenticators/admin/static", + StaticAdminDeviceViewSet, + "admin-staticdevice", + ), + ("stages/authenticator/static", AuthenticatorStaticStageViewSet), +] diff --git a/authentik/stages/authenticator_totp/urls.py b/authentik/stages/authenticator_totp/urls.py new file mode 100644 index 000000000..7be8d5f79 --- /dev/null +++ b/authentik/stages/authenticator_totp/urls.py @@ -0,0 +1,12 @@ +"""API URLs""" +from authentik.stages.authenticator_totp.api import ( + AuthenticatorTOTPStageViewSet, + TOTPAdminDeviceViewSet, + TOTPDeviceViewSet, +) + +api_urlpatterns = [ + ("authenticators/totp", TOTPDeviceViewSet), + ("authenticators/admin/totp", TOTPAdminDeviceViewSet, "admin-totpdevice"), + ("stages/authenticator/totp", AuthenticatorTOTPStageViewSet), +] diff --git a/authentik/stages/authenticator_validate/urls.py b/authentik/stages/authenticator_validate/urls.py new file mode 100644 index 000000000..30565eaee --- /dev/null +++ b/authentik/stages/authenticator_validate/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageViewSet + +api_urlpatterns = [("stages/authenticator/validate", AuthenticatorValidateStageViewSet)] diff --git a/authentik/stages/authenticator_webauthn/urls.py b/authentik/stages/authenticator_webauthn/urls.py new file mode 100644 index 000000000..9116dbcea --- /dev/null +++ b/authentik/stages/authenticator_webauthn/urls.py @@ -0,0 +1,16 @@ +"""API URLs""" +from authentik.stages.authenticator_webauthn.api import ( + AuthenticateWebAuthnStageViewSet, + WebAuthnAdminDeviceViewSet, + WebAuthnDeviceViewSet, +) + +api_urlpatterns = [ + ("stages/authenticator/webauthn", AuthenticateWebAuthnStageViewSet), + ( + "authenticators/admin/webauthn", + WebAuthnAdminDeviceViewSet, + "admin-webauthndevice", + ), + ("authenticators/webauthn", WebAuthnDeviceViewSet), +] diff --git a/authentik/stages/captcha/urls.py b/authentik/stages/captcha/urls.py new file mode 100644 index 000000000..b0fd79df6 --- /dev/null +++ b/authentik/stages/captcha/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.captcha.api import CaptchaStageViewSet + +api_urlpatterns = [("stages/captcha", CaptchaStageViewSet)] diff --git a/authentik/stages/consent/urls.py b/authentik/stages/consent/urls.py new file mode 100644 index 000000000..5be8f69c4 --- /dev/null +++ b/authentik/stages/consent/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.stages.consent.api import ConsentStageViewSet, UserConsentViewSet + +api_urlpatterns = [ + ("stages/consent", ConsentStageViewSet), + ("core/user_consent", UserConsentViewSet), +] diff --git a/authentik/stages/deny/urls.py b/authentik/stages/deny/urls.py new file mode 100644 index 000000000..4c31ee895 --- /dev/null +++ b/authentik/stages/deny/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.deny.api import DenyStageViewSet + +api_urlpatterns = [("stages/deny", DenyStageViewSet)] diff --git a/authentik/stages/dummy/urls.py b/authentik/stages/dummy/urls.py new file mode 100644 index 000000000..195c5487b --- /dev/null +++ b/authentik/stages/dummy/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.dummy.api import DummyStageViewSet + +api_urlpatterns = [("stages/dummy", DummyStageViewSet)] diff --git a/authentik/stages/email/urls.py b/authentik/stages/email/urls.py new file mode 100644 index 000000000..f435ae56e --- /dev/null +++ b/authentik/stages/email/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.email.api import EmailStageViewSet + +api_urlpatterns = [("stages/email", EmailStageViewSet)] diff --git a/authentik/stages/identification/urls.py b/authentik/stages/identification/urls.py new file mode 100644 index 000000000..a25cd978e --- /dev/null +++ b/authentik/stages/identification/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.identification.api import IdentificationStageViewSet + +api_urlpatterns = [("stages/identification", IdentificationStageViewSet)] diff --git a/authentik/stages/invitation/urls.py b/authentik/stages/invitation/urls.py new file mode 100644 index 000000000..6a8f087c9 --- /dev/null +++ b/authentik/stages/invitation/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.stages.invitation.api import InvitationStageViewSet, InvitationViewSet + +api_urlpatterns = [ + ("stages/invitation/invitations", InvitationViewSet), + ("stages/invitation/stages", InvitationStageViewSet), +] diff --git a/authentik/stages/password/urls.py b/authentik/stages/password/urls.py new file mode 100644 index 000000000..8e89847ca --- /dev/null +++ b/authentik/stages/password/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.password.api import PasswordStageViewSet + +api_urlpatterns = [("stages/password", PasswordStageViewSet)] diff --git a/authentik/stages/prompt/urls.py b/authentik/stages/prompt/urls.py new file mode 100644 index 000000000..dca48c8ad --- /dev/null +++ b/authentik/stages/prompt/urls.py @@ -0,0 +1,7 @@ +"""API URLs""" +from authentik.stages.prompt.api import PromptStageViewSet, PromptViewSet + +api_urlpatterns = [ + ("stages/prompt/prompts", PromptViewSet), + ("stages/prompt/stages", PromptStageViewSet), +] diff --git a/authentik/stages/user_delete/urls.py b/authentik/stages/user_delete/urls.py new file mode 100644 index 000000000..e629a5220 --- /dev/null +++ b/authentik/stages/user_delete/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.user_delete.api import UserDeleteStageViewSet + +api_urlpatterns = [("stages/user_delete", UserDeleteStageViewSet)] diff --git a/authentik/stages/user_login/urls.py b/authentik/stages/user_login/urls.py new file mode 100644 index 000000000..63e21c746 --- /dev/null +++ b/authentik/stages/user_login/urls.py @@ -0,0 +1,6 @@ +"""API URLs""" +from authentik.stages.user_login.api import UserLoginStageViewSet + +api_urlpatterns = [ + ("stages/user_login", UserLoginStageViewSet), +] diff --git a/authentik/stages/user_logout/urls.py b/authentik/stages/user_logout/urls.py new file mode 100644 index 000000000..76a3b3ceb --- /dev/null +++ b/authentik/stages/user_logout/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.user_logout.api import UserLogoutStageViewSet + +api_urlpatterns = [("stages/user_logout", UserLogoutStageViewSet)] diff --git a/authentik/stages/user_write/urls.py b/authentik/stages/user_write/urls.py new file mode 100644 index 000000000..c68a06e8c --- /dev/null +++ b/authentik/stages/user_write/urls.py @@ -0,0 +1,4 @@ +"""API URLs""" +from authentik.stages.user_write.api import UserWriteStageViewSet + +api_urlpatterns = [("stages/user_write", UserWriteStageViewSet)] diff --git a/authentik/tenants/urls.py b/authentik/tenants/urls.py new file mode 100644 index 000000000..741a2caa6 --- /dev/null +++ b/authentik/tenants/urls.py @@ -0,0 +1,6 @@ +"""API URLs""" +from authentik.tenants.api import TenantViewSet + +api_urlpatterns = [ + ("core/tenants", TenantViewSet), +]