tenants: initial implementation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
a1b6e09e8a
commit
ff611f21cd
|
@ -14,13 +14,6 @@ from authentik.core.api.utils import PassiveSerializer
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
|
|
||||||
|
|
||||||
class FooterLinkSerializer(PassiveSerializer):
|
|
||||||
"""Links returned in Config API"""
|
|
||||||
|
|
||||||
href = CharField(read_only=True)
|
|
||||||
name = CharField(read_only=True)
|
|
||||||
|
|
||||||
|
|
||||||
class Capabilities(models.TextChoices):
|
class Capabilities(models.TextChoices):
|
||||||
"""Define capabilities which influence which APIs can/should be used"""
|
"""Define capabilities which influence which APIs can/should be used"""
|
||||||
|
|
||||||
|
@ -30,10 +23,6 @@ class Capabilities(models.TextChoices):
|
||||||
class ConfigSerializer(PassiveSerializer):
|
class ConfigSerializer(PassiveSerializer):
|
||||||
"""Serialize authentik Config into DRF Object"""
|
"""Serialize authentik Config into DRF Object"""
|
||||||
|
|
||||||
branding_logo = CharField(read_only=True)
|
|
||||||
branding_title = CharField(read_only=True)
|
|
||||||
ui_footer_links = ListField(child=FooterLinkSerializer(), read_only=True)
|
|
||||||
|
|
||||||
error_reporting_enabled = BooleanField(read_only=True)
|
error_reporting_enabled = BooleanField(read_only=True)
|
||||||
error_reporting_environment = CharField(read_only=True)
|
error_reporting_environment = CharField(read_only=True)
|
||||||
error_reporting_send_pii = BooleanField(read_only=True)
|
error_reporting_send_pii = BooleanField(read_only=True)
|
||||||
|
@ -59,12 +48,9 @@ class ConfigView(APIView):
|
||||||
"""Retrive public configuration options"""
|
"""Retrive public configuration options"""
|
||||||
config = ConfigSerializer(
|
config = ConfigSerializer(
|
||||||
{
|
{
|
||||||
"branding_logo": CONFIG.y("authentik.branding.logo"),
|
|
||||||
"branding_title": CONFIG.y("authentik.branding.title"),
|
|
||||||
"error_reporting_enabled": CONFIG.y("error_reporting.enabled"),
|
"error_reporting_enabled": CONFIG.y("error_reporting.enabled"),
|
||||||
"error_reporting_environment": CONFIG.y("error_reporting.environment"),
|
"error_reporting_environment": CONFIG.y("error_reporting.environment"),
|
||||||
"error_reporting_send_pii": CONFIG.y("error_reporting.send_pii"),
|
"error_reporting_send_pii": CONFIG.y("error_reporting.send_pii"),
|
||||||
"ui_footer_links": CONFIG.y("authentik.footer_links"),
|
|
||||||
"capabilities": self.get_capabilities(),
|
"capabilities": self.get_capabilities(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -100,6 +100,7 @@ from authentik.stages.user_delete.api import UserDeleteStageViewSet
|
||||||
from authentik.stages.user_login.api import UserLoginStageViewSet
|
from authentik.stages.user_login.api import UserLoginStageViewSet
|
||||||
from authentik.stages.user_logout.api import UserLogoutStageViewSet
|
from authentik.stages.user_logout.api import UserLogoutStageViewSet
|
||||||
from authentik.stages.user_write.api import UserWriteStageViewSet
|
from authentik.stages.user_write.api import UserWriteStageViewSet
|
||||||
|
from authentik.tenants.api import TenantViewSet
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
|
|
||||||
|
@ -111,6 +112,7 @@ router.register("core/groups", GroupViewSet)
|
||||||
router.register("core/users", UserViewSet)
|
router.register("core/users", UserViewSet)
|
||||||
router.register("core/user_consent", UserConsentViewSet)
|
router.register("core/user_consent", UserConsentViewSet)
|
||||||
router.register("core/tokens", TokenViewSet)
|
router.register("core/tokens", TokenViewSet)
|
||||||
|
router.register("core/tenants", TenantViewSet)
|
||||||
|
|
||||||
router.register("outposts/instances", OutpostViewSet)
|
router.register("outposts/instances", OutpostViewSet)
|
||||||
router.register("outposts/service_connections/all", ServiceConnectionViewSet)
|
router.register("outposts/service_connections/all", ServiceConnectionViewSet)
|
||||||
|
|
|
@ -48,9 +48,6 @@ outposts:
|
||||||
authentik:
|
authentik:
|
||||||
avatars: gravatar # gravatar or none
|
avatars: gravatar # gravatar or none
|
||||||
geoip: ""
|
geoip: ""
|
||||||
branding:
|
|
||||||
title: authentik
|
|
||||||
logo: /static/dist/assets/icons/icon_left_brand.svg
|
|
||||||
# Optionally add links to the footer on the login page
|
# Optionally add links to the footer on the login page
|
||||||
footer_links:
|
footer_links:
|
||||||
- name: Documentation
|
- name: Documentation
|
||||||
|
|
|
@ -6,7 +6,7 @@ class AuthentikManagedConfig(AppConfig):
|
||||||
"""authentik Managed app"""
|
"""authentik Managed app"""
|
||||||
|
|
||||||
name = "authentik.managed"
|
name = "authentik.managed"
|
||||||
label = "authentik_Managed"
|
label = "authentik_managed"
|
||||||
verbose_name = "authentik Managed"
|
verbose_name = "authentik Managed"
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
# Generated by Django 3.2.3 on 2021-05-25 12:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_policies_event_matcher", "0014_alter_eventmatcherpolicy_app"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="eventmatcherpolicy",
|
||||||
|
name="app",
|
||||||
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("authentik.admin", "authentik Admin"),
|
||||||
|
("authentik.api", "authentik API"),
|
||||||
|
("authentik.events", "authentik Events"),
|
||||||
|
("authentik.crypto", "authentik Crypto"),
|
||||||
|
("authentik.flows", "authentik Flows"),
|
||||||
|
("authentik.outposts", "authentik Outpost"),
|
||||||
|
("authentik.lib", "authentik lib"),
|
||||||
|
("authentik.policies", "authentik Policies"),
|
||||||
|
("authentik.policies.dummy", "authentik Policies.Dummy"),
|
||||||
|
(
|
||||||
|
"authentik.policies.event_matcher",
|
||||||
|
"authentik Policies.Event Matcher",
|
||||||
|
),
|
||||||
|
("authentik.policies.expiry", "authentik Policies.Expiry"),
|
||||||
|
("authentik.policies.expression", "authentik Policies.Expression"),
|
||||||
|
("authentik.policies.hibp", "authentik Policies.HaveIBeenPwned"),
|
||||||
|
("authentik.policies.password", "authentik Policies.Password"),
|
||||||
|
("authentik.policies.reputation", "authentik Policies.Reputation"),
|
||||||
|
("authentik.providers.proxy", "authentik Providers.Proxy"),
|
||||||
|
("authentik.providers.ldap", "authentik Providers.LDAP"),
|
||||||
|
("authentik.providers.oauth2", "authentik Providers.OAuth2"),
|
||||||
|
("authentik.providers.saml", "authentik Providers.SAML"),
|
||||||
|
("authentik.recovery", "authentik Recovery"),
|
||||||
|
("authentik.sources.ldap", "authentik Sources.LDAP"),
|
||||||
|
("authentik.sources.oauth", "authentik Sources.OAuth"),
|
||||||
|
("authentik.sources.plex", "authentik Sources.Plex"),
|
||||||
|
("authentik.sources.saml", "authentik Sources.SAML"),
|
||||||
|
(
|
||||||
|
"authentik.stages.authenticator_duo",
|
||||||
|
"authentik Stages.Authenticator.Duo",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authentik.stages.authenticator_static",
|
||||||
|
"authentik Stages.Authenticator.Static",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authentik.stages.authenticator_totp",
|
||||||
|
"authentik Stages.Authenticator.TOTP",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authentik.stages.authenticator_validate",
|
||||||
|
"authentik Stages.Authenticator.Validate",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authentik.stages.authenticator_webauthn",
|
||||||
|
"authentik Stages.Authenticator.WebAuthn",
|
||||||
|
),
|
||||||
|
("authentik.stages.captcha", "authentik Stages.Captcha"),
|
||||||
|
("authentik.stages.consent", "authentik Stages.Consent"),
|
||||||
|
("authentik.stages.deny", "authentik Stages.Deny"),
|
||||||
|
("authentik.stages.dummy", "authentik Stages.Dummy"),
|
||||||
|
("authentik.stages.email", "authentik Stages.Email"),
|
||||||
|
(
|
||||||
|
"authentik.stages.identification",
|
||||||
|
"authentik Stages.Identification",
|
||||||
|
),
|
||||||
|
("authentik.stages.invitation", "authentik Stages.User Invitation"),
|
||||||
|
("authentik.stages.password", "authentik Stages.Password"),
|
||||||
|
("authentik.stages.prompt", "authentik Stages.Prompt"),
|
||||||
|
("authentik.stages.user_delete", "authentik Stages.User Delete"),
|
||||||
|
("authentik.stages.user_login", "authentik Stages.User Login"),
|
||||||
|
("authentik.stages.user_logout", "authentik Stages.User Logout"),
|
||||||
|
("authentik.stages.user_write", "authentik Stages.User Write"),
|
||||||
|
("authentik.tenants", "authentik Tenants"),
|
||||||
|
("authentik.core", "authentik Core"),
|
||||||
|
("authentik.managed", "authentik Managed"),
|
||||||
|
],
|
||||||
|
default="",
|
||||||
|
help_text="Match events created by selected application. When left empty, all applications are matched.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -127,6 +127,7 @@ INSTALLED_APPS = [
|
||||||
"authentik.stages.user_login",
|
"authentik.stages.user_login",
|
||||||
"authentik.stages.user_logout",
|
"authentik.stages.user_logout",
|
||||||
"authentik.stages.user_write",
|
"authentik.stages.user_write",
|
||||||
|
"authentik.tenants",
|
||||||
"rest_framework",
|
"rest_framework",
|
||||||
"django_filters",
|
"django_filters",
|
||||||
"drf_spectacular",
|
"drf_spectacular",
|
||||||
|
@ -208,6 +209,7 @@ MIDDLEWARE = [
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"authentik.core.middleware.RequestIDMiddleware",
|
"authentik.core.middleware.RequestIDMiddleware",
|
||||||
|
"authentik.tenants.middleware.TenantMiddleware",
|
||||||
"authentik.events.middleware.AuditMiddleware",
|
"authentik.events.middleware.AuditMiddleware",
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
"django.middleware.common.CommonMiddleware",
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
|
0
authentik/tenants/__init__.py
Normal file
0
authentik/tenants/__init__.py
Normal file
74
authentik/tenants/api.py
Normal file
74
authentik/tenants/api.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
"""Serializer for tenant models"""
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.fields import CharField, ListField
|
||||||
|
from rest_framework.permissions import AllowAny
|
||||||
|
from rest_framework.request import Request
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
from authentik.core.api.utils import PassiveSerializer
|
||||||
|
from authentik.lib.config import CONFIG
|
||||||
|
from authentik.tenants.models import Tenant
|
||||||
|
|
||||||
|
|
||||||
|
class FooterLinkSerializer(PassiveSerializer):
|
||||||
|
"""Links returned in Config API"""
|
||||||
|
|
||||||
|
href = CharField(read_only=True)
|
||||||
|
name = CharField(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TenantSerializer(ModelSerializer):
|
||||||
|
"""Tenant Serializer"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = Tenant
|
||||||
|
fields = [
|
||||||
|
"tenant_uuid",
|
||||||
|
"domain",
|
||||||
|
"default",
|
||||||
|
"branding_title",
|
||||||
|
"branding_logo",
|
||||||
|
"flow_authentication",
|
||||||
|
"flow_invalidation",
|
||||||
|
"flow_recovery",
|
||||||
|
"flow_enrollment",
|
||||||
|
"flow_unenrollment",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class CurrentTenantSerializer(PassiveSerializer):
|
||||||
|
"""Partial tenant information for styling"""
|
||||||
|
|
||||||
|
branding_title = CharField()
|
||||||
|
branding_logo = CharField()
|
||||||
|
ui_footer_links = ListField(
|
||||||
|
child=FooterLinkSerializer(),
|
||||||
|
read_only=True,
|
||||||
|
default=CONFIG.y("authentik.footer_links"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TenantViewSet(ModelViewSet):
|
||||||
|
"""Tenant Viewset"""
|
||||||
|
|
||||||
|
queryset = Tenant.objects.all()
|
||||||
|
serializer_class = TenantSerializer
|
||||||
|
search_fields = [
|
||||||
|
"domain",
|
||||||
|
"branding_title",
|
||||||
|
]
|
||||||
|
ordering = ["domain"]
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
responses=CurrentTenantSerializer(many=False),
|
||||||
|
)
|
||||||
|
@action(methods=["GET"], detail=False, permission_classes=[AllowAny])
|
||||||
|
# pylint: disable=invalid-name, unused-argument
|
||||||
|
def current(self, request: Request) -> Response:
|
||||||
|
"""Get current tenant"""
|
||||||
|
tenant: Tenant = request._request.tenant
|
||||||
|
return Response(CurrentTenantSerializer(tenant).data)
|
10
authentik/tenants/apps.py
Normal file
10
authentik/tenants/apps.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
"""authentik tenant app"""
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AuthentikTenantsConfig(AppConfig):
|
||||||
|
"""authentik Tenant app"""
|
||||||
|
|
||||||
|
name = "authentik.tenants"
|
||||||
|
label = "authentik_tenants"
|
||||||
|
verbose_name = "authentik Tenants"
|
22
authentik/tenants/middleware.py
Normal file
22
authentik/tenants/middleware.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""Inject tenant into current request"""
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from django.http.request import HttpRequest
|
||||||
|
from django.http.response import HttpResponse
|
||||||
|
|
||||||
|
from authentik.tenants.utils import get_tenant_for_request
|
||||||
|
|
||||||
|
|
||||||
|
class TenantMiddleware:
|
||||||
|
"""Add current tenant to http request"""
|
||||||
|
|
||||||
|
get_response: Callable[[HttpRequest], HttpResponse]
|
||||||
|
|
||||||
|
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def __call__(self, request: HttpRequest) -> HttpResponse:
|
||||||
|
if not hasattr(request, "tenant"):
|
||||||
|
tenant = get_tenant_for_request(request)
|
||||||
|
setattr(request, "tenant", tenant)
|
||||||
|
return self.get_response(request)
|
95
authentik/tenants/migrations/0001_initial.py
Normal file
95
authentik/tenants/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
# Generated by Django 3.2.3 on 2021-05-29 12:18
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_flows", "0018_oob_flows"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Tenant",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"tenant_uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4,
|
||||||
|
editable=False,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"domain",
|
||||||
|
models.TextField(
|
||||||
|
help_text="Domain that activates this tenant. Can be a superset, i.e. `a.b` for `aa.b` and `ba.b`"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("default", models.BooleanField(default=False)),
|
||||||
|
("branding_title", models.TextField(default="authentik")),
|
||||||
|
(
|
||||||
|
"branding_logo",
|
||||||
|
models.TextField(
|
||||||
|
default="/static/dist/assets/icons/icon_left_brand.svg"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flow_authentication",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="tenant_authentication",
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flow_enrollment",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="tenant_enrollment",
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flow_invalidation",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="tenant_invalidation",
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flow_recovery",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="tenant_recovery",
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flow_unenrollment",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="tenant_unenrollment",
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Tenant",
|
||||||
|
"verbose_name_plural": "Tenants",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
authentik/tenants/migrations/__init__.py
Normal file
0
authentik/tenants/migrations/__init__.py
Normal file
51
authentik/tenants/models.py
Normal file
51
authentik/tenants/models.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
"""tenant models"""
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from authentik.flows.models import Flow
|
||||||
|
|
||||||
|
|
||||||
|
class Tenant(models.Model):
|
||||||
|
"""Single tenant"""
|
||||||
|
|
||||||
|
tenant_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||||
|
domain = models.TextField(
|
||||||
|
help_text=_(
|
||||||
|
"Domain that activates this tenant. "
|
||||||
|
"Can be a superset, i.e. `a.b` for `aa.b` and `ba.b`"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
default = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
branding_title = models.TextField(default="authentik")
|
||||||
|
branding_logo = models.TextField(
|
||||||
|
default="/static/dist/assets/icons/icon_left_brand.svg"
|
||||||
|
)
|
||||||
|
|
||||||
|
flow_authentication = models.ForeignKey(
|
||||||
|
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_authentication"
|
||||||
|
)
|
||||||
|
flow_invalidation = models.ForeignKey(
|
||||||
|
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_invalidation"
|
||||||
|
)
|
||||||
|
flow_recovery = models.ForeignKey(
|
||||||
|
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_recovery"
|
||||||
|
)
|
||||||
|
flow_enrollment = models.ForeignKey(
|
||||||
|
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_enrollment"
|
||||||
|
)
|
||||||
|
flow_unenrollment = models.ForeignKey(
|
||||||
|
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_unenrollment"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.domain
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("Tenant")
|
||||||
|
verbose_name_plural = _("Tenants")
|
17
authentik/tenants/utils.py
Normal file
17
authentik/tenants/utils.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
"""Tenant utilities"""
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.http.request import HttpRequest
|
||||||
|
|
||||||
|
from authentik.tenants.models import Tenant
|
||||||
|
|
||||||
|
_q_default = Q(default=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_tenant_for_request(request: HttpRequest) -> Tenant:
|
||||||
|
"""Get tenant object for current request"""
|
||||||
|
db_tenants = Tenant.objects.filter(
|
||||||
|
Q(domain__iendswith=request.get_host()) | _q_default
|
||||||
|
)
|
||||||
|
if not db_tenants.exists():
|
||||||
|
return Tenant()
|
||||||
|
return db_tenants.first()
|
408
schema.yml
408
schema.yml
|
@ -1712,6 +1712,231 @@ paths:
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/api/v2beta/core/tenants/:
|
||||||
|
get:
|
||||||
|
operationId: core_tenants_list
|
||||||
|
description: Tenant Viewset
|
||||||
|
parameters:
|
||||||
|
- name: ordering
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: page
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A page number within the paginated result set.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: page_size
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Number of results to return per page.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: search
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PaginatedTenantList'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
post:
|
||||||
|
operationId: core_tenants_create
|
||||||
|
description: Tenant Viewset
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TenantRequest'
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TenantRequest'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TenantRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Tenant'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/api/v2beta/core/tenants/{tenant_uuid}/:
|
||||||
|
get:
|
||||||
|
operationId: core_tenants_retrieve
|
||||||
|
description: Tenant Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: tenant_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this Tenant.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Tenant'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
put:
|
||||||
|
operationId: core_tenants_update
|
||||||
|
description: Tenant Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: tenant_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this Tenant.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TenantRequest'
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TenantRequest'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TenantRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Tenant'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
patch:
|
||||||
|
operationId: core_tenants_partial_update
|
||||||
|
description: Tenant Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: tenant_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this Tenant.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedTenantRequest'
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedTenantRequest'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedTenantRequest'
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Tenant'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
delete:
|
||||||
|
operationId: core_tenants_destroy
|
||||||
|
description: Tenant Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: tenant_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this Tenant.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: No response body
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/api/v2beta/core/tenants/current/:
|
||||||
|
get:
|
||||||
|
operationId: core_tenants_current_retrieve
|
||||||
|
description: Get current tenant
|
||||||
|
tags:
|
||||||
|
- core
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
- cookieAuth: []
|
||||||
|
- {}
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/CurrentTenant'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
/api/v2beta/core/tokens/:
|
/api/v2beta/core/tokens/:
|
||||||
get:
|
get:
|
||||||
operationId: core_tokens_list
|
operationId: core_tokens_list
|
||||||
|
@ -15291,6 +15516,7 @@ components:
|
||||||
- authentik.stages.user_login
|
- authentik.stages.user_login
|
||||||
- authentik.stages.user_logout
|
- authentik.stages.user_logout
|
||||||
- authentik.stages.user_write
|
- authentik.stages.user_write
|
||||||
|
- authentik.tenants
|
||||||
- authentik.core
|
- authentik.core
|
||||||
- authentik.managed
|
- authentik.managed
|
||||||
type: string
|
type: string
|
||||||
|
@ -16151,17 +16377,6 @@ components:
|
||||||
type: object
|
type: object
|
||||||
description: Serialize authentik Config into DRF Object
|
description: Serialize authentik Config into DRF Object
|
||||||
properties:
|
properties:
|
||||||
branding_logo:
|
|
||||||
type: string
|
|
||||||
readOnly: true
|
|
||||||
branding_title:
|
|
||||||
type: string
|
|
||||||
readOnly: true
|
|
||||||
ui_footer_links:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/FooterLink'
|
|
||||||
readOnly: true
|
|
||||||
error_reporting_enabled:
|
error_reporting_enabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
@ -16176,13 +16391,10 @@ components:
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/CapabilitiesEnum'
|
$ref: '#/components/schemas/CapabilitiesEnum'
|
||||||
required:
|
required:
|
||||||
- branding_logo
|
|
||||||
- branding_title
|
|
||||||
- capabilities
|
- capabilities
|
||||||
- error_reporting_enabled
|
- error_reporting_enabled
|
||||||
- error_reporting_environment
|
- error_reporting_environment
|
||||||
- error_reporting_send_pii
|
- error_reporting_send_pii
|
||||||
- ui_footer_links
|
|
||||||
ConsentChallenge:
|
ConsentChallenge:
|
||||||
type: object
|
type: object
|
||||||
description: Challenge info for consent screens
|
description: Challenge info for consent screens
|
||||||
|
@ -16298,6 +16510,28 @@ components:
|
||||||
required:
|
required:
|
||||||
- x_cord
|
- x_cord
|
||||||
- y_cord
|
- y_cord
|
||||||
|
CurrentTenant:
|
||||||
|
type: object
|
||||||
|
description: Partial tenant information for styling
|
||||||
|
properties:
|
||||||
|
branding_title:
|
||||||
|
type: string
|
||||||
|
branding_logo:
|
||||||
|
type: string
|
||||||
|
ui_footer_links:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/FooterLink'
|
||||||
|
readOnly: true
|
||||||
|
default:
|
||||||
|
- href: https://goauthentik.io/docs/
|
||||||
|
name: Documentation
|
||||||
|
- href: https://goauthentik.io/
|
||||||
|
name: authentik Website
|
||||||
|
required:
|
||||||
|
- branding_logo
|
||||||
|
- branding_title
|
||||||
|
- ui_footer_links
|
||||||
DenyStage:
|
DenyStage:
|
||||||
type: object
|
type: object
|
||||||
description: DenyStage Serializer
|
description: DenyStage Serializer
|
||||||
|
@ -20893,6 +21127,41 @@ components:
|
||||||
required:
|
required:
|
||||||
- pagination
|
- pagination
|
||||||
- results
|
- results
|
||||||
|
PaginatedTenantList:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
pagination:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
next:
|
||||||
|
type: number
|
||||||
|
previous:
|
||||||
|
type: number
|
||||||
|
count:
|
||||||
|
type: number
|
||||||
|
current:
|
||||||
|
type: number
|
||||||
|
total_pages:
|
||||||
|
type: number
|
||||||
|
start_index:
|
||||||
|
type: number
|
||||||
|
end_index:
|
||||||
|
type: number
|
||||||
|
required:
|
||||||
|
- next
|
||||||
|
- previous
|
||||||
|
- count
|
||||||
|
- current
|
||||||
|
- total_pages
|
||||||
|
- start_index
|
||||||
|
- end_index
|
||||||
|
results:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Tenant'
|
||||||
|
required:
|
||||||
|
- pagination
|
||||||
|
- results
|
||||||
PaginatedTokenList:
|
PaginatedTokenList:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -22830,6 +23099,40 @@ components:
|
||||||
type: string
|
type: string
|
||||||
description: The human-readable name of this device.
|
description: The human-readable name of this device.
|
||||||
maxLength: 64
|
maxLength: 64
|
||||||
|
PatchedTenantRequest:
|
||||||
|
type: object
|
||||||
|
description: Tenant Serializer
|
||||||
|
properties:
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: Domain that activates this tenant. Can be a superset, i.e.
|
||||||
|
`a.b` for `aa.b` and `ba.b`
|
||||||
|
default:
|
||||||
|
type: boolean
|
||||||
|
branding_title:
|
||||||
|
type: string
|
||||||
|
branding_logo:
|
||||||
|
type: string
|
||||||
|
flow_authentication:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_invalidation:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_recovery:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_enrollment:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_unenrollment:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
PatchedTokenRequest:
|
PatchedTokenRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Token Serializer
|
description: Token Serializer
|
||||||
|
@ -24779,6 +25082,83 @@ components:
|
||||||
- task_description
|
- task_description
|
||||||
- task_finish_timestamp
|
- task_finish_timestamp
|
||||||
- task_name
|
- task_name
|
||||||
|
Tenant:
|
||||||
|
type: object
|
||||||
|
description: Tenant Serializer
|
||||||
|
properties:
|
||||||
|
tenant_uuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
readOnly: true
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: Domain that activates this tenant. Can be a superset, i.e.
|
||||||
|
`a.b` for `aa.b` and `ba.b`
|
||||||
|
default:
|
||||||
|
type: boolean
|
||||||
|
branding_title:
|
||||||
|
type: string
|
||||||
|
branding_logo:
|
||||||
|
type: string
|
||||||
|
flow_authentication:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_invalidation:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_recovery:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_enrollment:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_unenrollment:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
required:
|
||||||
|
- domain
|
||||||
|
- tenant_uuid
|
||||||
|
TenantRequest:
|
||||||
|
type: object
|
||||||
|
description: Tenant Serializer
|
||||||
|
properties:
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: Domain that activates this tenant. Can be a superset, i.e.
|
||||||
|
`a.b` for `aa.b` and `ba.b`
|
||||||
|
default:
|
||||||
|
type: boolean
|
||||||
|
branding_title:
|
||||||
|
type: string
|
||||||
|
branding_logo:
|
||||||
|
type: string
|
||||||
|
flow_authentication:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_invalidation:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_recovery:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_enrollment:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
flow_unenrollment:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
required:
|
||||||
|
- domain
|
||||||
Token:
|
Token:
|
||||||
type: object
|
type: object
|
||||||
description: Token Serializer
|
description: Token Serializer
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Config, Configuration, Middleware, ResponseContext, RootApi } from "authentik-api";
|
import { Config, Configuration, CoreApi, CurrentTenant, Middleware, ResponseContext, RootApi, Tenant } from "authentik-api";
|
||||||
import { getCookie } from "../utils";
|
import { getCookie } from "../utils";
|
||||||
import { API_DRAWER_MIDDLEWARE } from "../elements/notifications/APIDrawer";
|
import { API_DRAWER_MIDDLEWARE } from "../elements/notifications/APIDrawer";
|
||||||
import { MessageMiddleware } from "../elements/messages/Middleware";
|
import { MessageMiddleware } from "../elements/messages/Middleware";
|
||||||
|
@ -20,6 +20,14 @@ export function config(): Promise<Config> {
|
||||||
return globalConfigPromise;
|
return globalConfigPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let globalTenantPromise: Promise<CurrentTenant>;
|
||||||
|
export function tenant(): Promise<CurrentTenant> {
|
||||||
|
if (!globalTenantPromise) {
|
||||||
|
globalTenantPromise = new CoreApi(DEFAULT_CONFIG).coreTenantsCurrentRetrieve();
|
||||||
|
}
|
||||||
|
return globalTenantPromise;
|
||||||
|
}
|
||||||
|
|
||||||
export const DEFAULT_CONFIG = new Configuration({
|
export const DEFAULT_CONFIG = new Configuration({
|
||||||
basePath: "",
|
basePath: "",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import AKGlobal from "../authentik.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import { EVENT_SIDEBAR_TOGGLE, TITLE_DEFAULT } from "../constants";
|
import { EVENT_SIDEBAR_TOGGLE, TITLE_DEFAULT } from "../constants";
|
||||||
import { config } from "../api/Config";
|
import { tenant } from "../api/Config";
|
||||||
|
|
||||||
@customElement("ak-page-header")
|
@customElement("ak-page-header")
|
||||||
export class PageHeader extends LitElement {
|
export class PageHeader extends LitElement {
|
||||||
|
@ -18,11 +18,11 @@ export class PageHeader extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
set header(value: string) {
|
set header(value: string) {
|
||||||
config().then(config => {
|
tenant().then(tenant => {
|
||||||
if (value !== "") {
|
if (value !== "") {
|
||||||
document.title = `${value} - ${config.brandingTitle}`;
|
document.title = `${value} - ${tenant.brandingTitle}`;
|
||||||
} else {
|
} else {
|
||||||
document.title = config.brandingTitle || TITLE_DEFAULT;
|
document.title = tenant.brandingTitle || TITLE_DEFAULT;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this._header = value;
|
this._header = value;
|
||||||
|
|
|
@ -6,29 +6,25 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import AKGlobal from "../../authentik.css";
|
import AKGlobal from "../../authentik.css";
|
||||||
|
|
||||||
import { configureSentry } from "../../api/Sentry";
|
import { configureSentry } from "../../api/Sentry";
|
||||||
import { Config } from "authentik-api";
|
import { CurrentTenant } from "authentik-api";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import { EVENT_SIDEBAR_TOGGLE } from "../../constants";
|
import { EVENT_SIDEBAR_TOGGLE } from "../../constants";
|
||||||
|
import { tenant } from "../../api/Config";
|
||||||
|
|
||||||
// If the viewport is wider than MIN_WIDTH, the sidebar
|
// If the viewport is wider than MIN_WIDTH, the sidebar
|
||||||
// is shown besides the content, and not overlayed.
|
// is shown besides the content, and not overlayed.
|
||||||
export const MIN_WIDTH = 1200;
|
export const MIN_WIDTH = 1200;
|
||||||
|
|
||||||
export const DefaultConfig: Config = {
|
export const DefaultTenant: CurrentTenant = {
|
||||||
brandingLogo: " /static/dist/assets/icons/icon_left_brand.svg",
|
brandingLogo: " /static/dist/assets/icons/icon_left_brand.svg",
|
||||||
brandingTitle: "authentik",
|
brandingTitle: "authentik",
|
||||||
|
|
||||||
errorReportingEnabled: false,
|
|
||||||
errorReportingEnvironment: "",
|
|
||||||
errorReportingSendPii: false,
|
|
||||||
uiFooterLinks: [],
|
uiFooterLinks: [],
|
||||||
capabilities: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("ak-sidebar-brand")
|
@customElement("ak-sidebar-brand")
|
||||||
export class SidebarBrand extends LitElement {
|
export class SidebarBrand extends LitElement {
|
||||||
@property({attribute: false})
|
@property({attribute: false})
|
||||||
config: Config = DefaultConfig;
|
tenant: CurrentTenant = DefaultTenant;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
|
@ -68,7 +64,8 @@ export class SidebarBrand extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
configureSentry(true).then((c) => {this.config = c;});
|
configureSentry(true);
|
||||||
|
tenant().then(tenant => this.tenant = tenant);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
|
@ -89,7 +86,7 @@ export class SidebarBrand extends LitElement {
|
||||||
` : html``}
|
` : html``}
|
||||||
<a href="#/" class="pf-c-page__header-brand-link">
|
<a href="#/" class="pf-c-page__header-brand-link">
|
||||||
<div class="pf-c-brand ak-brand">
|
<div class="pf-c-brand ak-brand">
|
||||||
<img src="${ifDefined(this.config.brandingLogo)}" alt="authentik icon" loading="lazy" />
|
<img src="${ifDefined(this.tenant.brandingLogo)}" alt="authentik icon" loading="lazy" />
|
||||||
</div>
|
</div>
|
||||||
</a>`;
|
</a>`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ import "./stages/password/PasswordStage";
|
||||||
import "./stages/prompt/PromptStage";
|
import "./stages/prompt/PromptStage";
|
||||||
import "./sources/plex/PlexLoginInit";
|
import "./sources/plex/PlexLoginInit";
|
||||||
import { StageHost } from "./stages/base";
|
import { StageHost } from "./stages/base";
|
||||||
import { ChallengeChoices, Config, FlowChallengeRequest, FlowChallengeResponseRequest, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
|
import { ChallengeChoices, CurrentTenant, FlowChallengeRequest, FlowChallengeResponseRequest, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
|
||||||
import { config, DEFAULT_CONFIG } from "../api/Config";
|
import { DEFAULT_CONFIG, tenant } from "../api/Config";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
import { PFSize } from "../elements/Spinner";
|
import { PFSize } from "../elements/Spinner";
|
||||||
|
@ -46,7 +46,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
config?: Config;
|
tenant?: CurrentTenant;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [PFBase, PFLogin, PFButton, PFTitle, PFList, PFBackgroundImage, AKGlobal].concat(css`
|
return [PFBase, PFLogin, PFButton, PFTitle, PFList, PFBackgroundImage, AKGlobal].concat(css`
|
||||||
|
@ -85,11 +85,11 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
private postUpdate(): void {
|
private postUpdate(): void {
|
||||||
config().then(config => {
|
tenant().then(tenant => {
|
||||||
if (this.challenge?.title) {
|
if (this.challenge?.title) {
|
||||||
document.title = `${this.challenge.title} - ${config.brandingTitle}`;
|
document.title = `${this.challenge.title} - ${tenant.brandingTitle}`;
|
||||||
} else {
|
} else {
|
||||||
document.title = config.brandingTitle || TITLE_DEFAULT;
|
document.title = tenant.brandingTitle || TITLE_DEFAULT;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,8 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
configureSentry().then((config) => {
|
configureSentry();
|
||||||
this.config = config;
|
tenant().then(tenant => this.tenant = tenant);
|
||||||
});
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
||||||
flowSlug: this.flowSlug,
|
flowSlug: this.flowSlug,
|
||||||
|
@ -255,7 +254,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
<div class="ak-login-container">
|
<div class="ak-login-container">
|
||||||
<header class="pf-c-login__header">
|
<header class="pf-c-login__header">
|
||||||
<div class="pf-c-brand ak-brand">
|
<div class="pf-c-brand ak-brand">
|
||||||
<img src="${ifDefined(this.config?.brandingLogo)}" alt="authentik icon" />
|
<img src="${ifDefined(this.tenant?.brandingLogo)}" alt="authentik icon" />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="pf-c-login__main">
|
<div class="pf-c-login__main">
|
||||||
|
@ -264,12 +263,12 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
<footer class="pf-c-login__footer">
|
<footer class="pf-c-login__footer">
|
||||||
<p></p>
|
<p></p>
|
||||||
<ul class="pf-c-list pf-m-inline">
|
<ul class="pf-c-list pf-m-inline">
|
||||||
${until(this.config?.uiFooterLinks?.map((link) => {
|
${until(this.tenant?.uiFooterLinks?.map((link) => {
|
||||||
return html`<li>
|
return html`<li>
|
||||||
<a href="${link.href || ""}">${link.name}</a>
|
<a href="${link.href || ""}">${link.name}</a>
|
||||||
</li>`;
|
</li>`;
|
||||||
}))}
|
}))}
|
||||||
${this.config?.brandingTitle != "authentik" ? html`
|
${this.tenant?.brandingTitle != "authentik" ? html`
|
||||||
<li><a href="https://goauthentik.io">${t`Powered by authentik`}</a></li>` : html``}
|
<li><a href="https://goauthentik.io">${t`Powered by authentik`}</a></li>` : html``}
|
||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -522,6 +522,14 @@ msgstr "Changelog"
|
||||||
msgid "Characters which are considered as symbols."
|
msgid "Characters which are considered as symbols."
|
||||||
msgstr "Characters which are considered as symbols."
|
msgstr "Characters which are considered as symbols."
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
|
msgid "Check"
|
||||||
|
msgstr "Check"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
|
msgid "Check Application access"
|
||||||
|
msgstr "Check Application access"
|
||||||
|
|
||||||
#: src/pages/policies/reputation/ReputationPolicyForm.ts
|
#: src/pages/policies/reputation/ReputationPolicyForm.ts
|
||||||
msgid "Check IP"
|
msgid "Check IP"
|
||||||
msgstr "Check IP"
|
msgstr "Check IP"
|
||||||
|
@ -530,6 +538,10 @@ msgstr "Check IP"
|
||||||
msgid "Check Username"
|
msgid "Check Username"
|
||||||
msgstr "Check Username"
|
msgstr "Check Username"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
|
msgid "Check access"
|
||||||
|
msgstr "Check access"
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
msgid "Check status"
|
msgid "Check status"
|
||||||
msgstr "Check status"
|
msgstr "Check status"
|
||||||
|
@ -1625,6 +1637,7 @@ msgstr "Hide service-accounts"
|
||||||
#: src/pages/sources/plex/PlexSourceForm.ts
|
#: src/pages/sources/plex/PlexSourceForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
#: src/pages/stages/identification/IdentificationStageForm.ts
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
#: src/pages/stages/password/PasswordStageForm.ts
|
#: src/pages/stages/password/PasswordStageForm.ts
|
||||||
#: src/pages/stages/prompt/PromptStageForm.ts
|
#: src/pages/stages/prompt/PromptStageForm.ts
|
||||||
#: src/pages/stages/prompt/PromptStageForm.ts
|
#: src/pages/stages/prompt/PromptStageForm.ts
|
||||||
|
@ -1866,6 +1879,7 @@ msgid "Loading"
|
||||||
msgstr "Loading"
|
msgstr "Loading"
|
||||||
|
|
||||||
#: src/elements/Spinner.ts
|
#: src/elements/Spinner.ts
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/applications/ApplicationForm.ts
|
#: src/pages/applications/ApplicationForm.ts
|
||||||
#: src/pages/events/RuleForm.ts
|
#: src/pages/events/RuleForm.ts
|
||||||
#: src/pages/events/RuleForm.ts
|
#: src/pages/events/RuleForm.ts
|
||||||
|
@ -1916,6 +1930,7 @@ msgstr "Loading"
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
#: src/pages/stages/identification/IdentificationStageForm.ts
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
#: src/pages/stages/identification/IdentificationStageForm.ts
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
#: src/pages/stages/password/PasswordStageForm.ts
|
#: src/pages/stages/password/PasswordStageForm.ts
|
||||||
#: src/pages/stages/prompt/PromptStageForm.ts
|
#: src/pages/stages/prompt/PromptStageForm.ts
|
||||||
#: src/pages/stages/prompt/PromptStageForm.ts
|
#: src/pages/stages/prompt/PromptStageForm.ts
|
||||||
|
@ -1986,6 +2001,7 @@ msgstr "Maximum age (in days)"
|
||||||
msgid "Members"
|
msgid "Members"
|
||||||
msgstr "Members"
|
msgstr "Members"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/events/EventInfo.ts
|
#: src/pages/events/EventInfo.ts
|
||||||
#: src/pages/policies/PolicyTestForm.ts
|
#: src/pages/policies/PolicyTestForm.ts
|
||||||
#: src/pages/system-tasks/SystemTaskListPage.ts
|
#: src/pages/system-tasks/SystemTaskListPage.ts
|
||||||
|
@ -2130,6 +2146,7 @@ msgstr "Need an account?"
|
||||||
msgid "New version available!"
|
msgid "New version available!"
|
||||||
msgstr "New version available!"
|
msgstr "New version available!"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/crypto/CertificateKeyPairListPage.ts
|
#: src/pages/crypto/CertificateKeyPairListPage.ts
|
||||||
#: src/pages/groups/GroupListPage.ts
|
#: src/pages/groups/GroupListPage.ts
|
||||||
#: src/pages/groups/MemberSelectModal.ts
|
#: src/pages/groups/MemberSelectModal.ts
|
||||||
|
@ -2408,6 +2425,7 @@ msgstr "Parent"
|
||||||
msgid "Pass policy?"
|
msgid "Pass policy?"
|
||||||
msgstr "Pass policy?"
|
msgstr "Pass policy?"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/events/EventInfo.ts
|
#: src/pages/events/EventInfo.ts
|
||||||
#: src/pages/policies/PolicyTestForm.ts
|
#: src/pages/policies/PolicyTestForm.ts
|
||||||
msgid "Passing"
|
msgid "Passing"
|
||||||
|
@ -2887,6 +2905,10 @@ msgstr "Select an identification method."
|
||||||
msgid "Select one of the sources below to login."
|
msgid "Select one of the sources below to login."
|
||||||
msgstr "Select one of the sources below to login."
|
msgstr "Select one of the sources below to login."
|
||||||
|
|
||||||
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
|
msgid "Select sources should be shown for users to authenticate with. This only affects web-based sources, not LDAP."
|
||||||
|
msgstr "Select sources should be shown for users to authenticate with. This only affects web-based sources, not LDAP."
|
||||||
|
|
||||||
#: src/pages/groups/MemberSelectModal.ts
|
#: src/pages/groups/MemberSelectModal.ts
|
||||||
msgid "Select users to add"
|
msgid "Select users to add"
|
||||||
msgstr "Select users to add"
|
msgstr "Select users to add"
|
||||||
|
@ -3054,6 +3076,7 @@ msgstr "Source {0}"
|
||||||
|
|
||||||
#: src/interfaces/AdminInterface.ts
|
#: src/interfaces/AdminInterface.ts
|
||||||
#: src/pages/sources/SourcesListPage.ts
|
#: src/pages/sources/SourcesListPage.ts
|
||||||
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
msgid "Sources"
|
msgid "Sources"
|
||||||
msgstr "Sources"
|
msgstr "Sources"
|
||||||
|
|
||||||
|
@ -3321,6 +3344,7 @@ msgstr "Successfully imported flow."
|
||||||
msgid "Successfully imported provider."
|
msgid "Successfully imported provider."
|
||||||
msgstr "Successfully imported provider."
|
msgstr "Successfully imported provider."
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/policies/PolicyTestForm.ts
|
#: src/pages/policies/PolicyTestForm.ts
|
||||||
#: src/pages/property-mappings/PropertyMappingTestForm.ts
|
#: src/pages/property-mappings/PropertyMappingTestForm.ts
|
||||||
msgid "Successfully sent test-request."
|
msgid "Successfully sent test-request."
|
||||||
|
@ -3516,6 +3540,7 @@ msgstr "Task finished with warnings"
|
||||||
msgid "Template"
|
msgid "Template"
|
||||||
msgstr "Template"
|
msgstr "Template"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
#: src/pages/events/TransportListPage.ts
|
#: src/pages/events/TransportListPage.ts
|
||||||
#: src/pages/policies/PolicyListPage.ts
|
#: src/pages/policies/PolicyListPage.ts
|
||||||
#: src/pages/policies/PolicyListPage.ts
|
#: src/pages/policies/PolicyListPage.ts
|
||||||
|
@ -3925,6 +3950,7 @@ msgstr "Use this redirect URL:"
|
||||||
|
|
||||||
#: src/elements/events/ObjectChangelog.ts
|
#: src/elements/events/ObjectChangelog.ts
|
||||||
#: src/elements/events/UserEvents.ts
|
#: src/elements/events/UserEvents.ts
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/events/EventInfo.ts
|
#: src/pages/events/EventInfo.ts
|
||||||
#: src/pages/events/EventListPage.ts
|
#: src/pages/events/EventListPage.ts
|
||||||
#: src/pages/policies/PolicyBindingForm.ts
|
#: src/pages/policies/PolicyBindingForm.ts
|
||||||
|
@ -4178,6 +4204,7 @@ msgstr ""
|
||||||
msgid "X509 Subject"
|
msgid "X509 Subject"
|
||||||
msgstr "X509 Subject"
|
msgstr "X509 Subject"
|
||||||
|
|
||||||
|
#: src/pages/applications/ApplicationCheckAccessForm.ts
|
||||||
#: src/pages/crypto/CertificateKeyPairListPage.ts
|
#: src/pages/crypto/CertificateKeyPairListPage.ts
|
||||||
#: src/pages/groups/GroupListPage.ts
|
#: src/pages/groups/GroupListPage.ts
|
||||||
#: src/pages/groups/MemberSelectModal.ts
|
#: src/pages/groups/MemberSelectModal.ts
|
||||||
|
|
|
@ -518,6 +518,14 @@ msgstr ""
|
||||||
msgid "Characters which are considered as symbols."
|
msgid "Characters which are considered as symbols."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Check"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Check Application access"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Check IP"
|
msgid "Check IP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -526,6 +534,10 @@ msgstr ""
|
||||||
msgid "Check Username"
|
msgid "Check Username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Check access"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Check status"
|
msgid "Check status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1620,6 +1632,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Hold control/command to select multiple items."
|
msgid "Hold control/command to select multiple items."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1911,6 +1924,8 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
|
#:
|
||||||
msgid "Loading..."
|
msgid "Loading..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1981,6 +1996,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Messages"
|
msgid "Messages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2133,6 +2149,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2400,6 +2417,7 @@ msgstr ""
|
||||||
msgid "Pass policy?"
|
msgid "Pass policy?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Passing"
|
msgid "Passing"
|
||||||
|
@ -2879,6 +2897,10 @@ msgstr ""
|
||||||
msgid "Select one of the sources below to login."
|
msgid "Select one of the sources below to login."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Select sources should be shown for users to authenticate with. This only affects web-based sources, not LDAP."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Select users to add"
|
msgid "Select users to add"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3044,6 +3066,7 @@ msgstr ""
|
||||||
msgid "Source {0}"
|
msgid "Source {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Sources"
|
msgid "Sources"
|
||||||
|
@ -3313,6 +3336,7 @@ msgstr ""
|
||||||
msgid "Successfully imported provider."
|
msgid "Successfully imported provider."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Successfully sent test-request."
|
msgid "Successfully sent test-request."
|
||||||
|
@ -3513,6 +3537,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Test"
|
msgid "Test"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3923,6 +3948,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "User"
|
msgid "User"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -4175,6 +4201,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
Reference in a new issue