"""brand models""" from uuid import uuid4 from django.db import models from django.http import HttpRequest from django.utils.translation import gettext_lazy as _ from rest_framework.serializers import Serializer from structlog.stdlib import get_logger from authentik.crypto.models import CertificateKeyPair from authentik.flows.models import Flow from authentik.lib.config import CONFIG from authentik.lib.models import SerializerModel LOGGER = get_logger() class Brand(SerializerModel): """Single brand""" brand_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) domain = models.TextField( help_text=_( "Domain that activates this brand. 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") branding_favicon = models.TextField(default="/static/dist/assets/icons/icon.png") branding_custom_css = models.TextField(default="", blank=True) branding_default_flow_background = models.TextField( default="/static/dist/assets/images/flow_background.jpg" ) flow_authentication = models.ForeignKey( Flow, null=True, on_delete=models.SET_NULL, related_name="brand_authentication" ) flow_invalidation = models.ForeignKey( Flow, null=True, on_delete=models.SET_NULL, related_name="brand_invalidation" ) flow_recovery = models.ForeignKey( Flow, null=True, on_delete=models.SET_NULL, related_name="brand_recovery" ) flow_unenrollment = models.ForeignKey( Flow, null=True, on_delete=models.SET_NULL, related_name="brand_unenrollment" ) flow_user_settings = models.ForeignKey( Flow, null=True, on_delete=models.SET_NULL, related_name="brand_user_settings" ) flow_device_code = models.ForeignKey( Flow, null=True, on_delete=models.SET_NULL, related_name="brand_device_code" ) default_application = models.ForeignKey( "authentik_core.Application", null=True, default=None, on_delete=models.SET_DEFAULT, help_text=_( "When set, external users will be redirected to this application after authenticating." ), ) web_certificate = models.ForeignKey( CertificateKeyPair, null=True, default=None, on_delete=models.SET_DEFAULT, help_text=_("Web Certificate used by the authentik Core webserver."), related_name="+", ) client_certificates = models.ManyToManyField( CertificateKeyPair, default=None, blank=True, help_text=_("Certificates used for client authentication."), ) attributes = models.JSONField(default=dict, blank=True) def branding_logo_url(self) -> str: """Get branding_logo with the correct prefix""" if self.branding_logo.startswith("/static"): return CONFIG.get("web.path", "/")[:-1] + self.branding_logo return self.branding_logo def branding_favicon_url(self) -> str: """Get branding_favicon with the correct prefix""" if self.branding_favicon.startswith("/static"): return CONFIG.get("web.path", "/")[:-1] + self.branding_favicon return self.branding_favicon def branding_default_flow_background_url(self) -> str: """Get branding_default_flow_background with the correct prefix""" if self.branding_default_flow_background.startswith("/static"): return CONFIG.get("web.path", "/")[:-1] + self.branding_default_flow_background return self.branding_default_flow_background @property def serializer(self) -> Serializer: from authentik.brands.api import BrandSerializer return BrandSerializer @property def default_locale(self) -> str: """Get default locale""" try: return self.attributes.get("settings", {}).get("locale", "") except Exception as exc: LOGGER.warning("Failed to get default locale", exc=exc) return "" def __str__(self) -> str: if self.default: return "Default brand" return f"Brand {self.domain}" class Meta: verbose_name = _("Brand") verbose_name_plural = _("Brands") indexes = [ models.Index(fields=["domain"]), models.Index(fields=["default"]), ] class WebfingerProvider(models.Model): """Provider which supports webfinger discovery""" class Meta: abstract = True def webfinger(self, resource: str, request: HttpRequest) -> dict: raise NotImplementedError()