diff --git a/authentik/core/migrations/0018_auto_20210330_1345_squashed_0028_alter_token_intent.py b/authentik/core/migrations/0018_auto_20210330_1345_squashed_0028_alter_token_intent.py index eb762a0a5..2d934c9bd 100644 --- a/authentik/core/migrations/0018_auto_20210330_1345_squashed_0028_alter_token_intent.py +++ b/authentik/core/migrations/0018_auto_20210330_1345_squashed_0028_alter_token_intent.py @@ -3,7 +3,6 @@ import uuid from os import environ -import django.core.validators import django.db.models.deletion from django.apps.registry import Apps from django.conf import settings @@ -12,6 +11,7 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor from django.db.models import Count import authentik.core.models +import authentik.lib.models def migrate_sessions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): @@ -161,7 +161,7 @@ class Migration(migrations.Migration): model_name="application", name="meta_launch_url", field=models.TextField( - blank=True, default="", validators=[django.core.validators.URLValidator()] + blank=True, default="", validators=[authentik.lib.models.DomainlessURLValidator()] ), ), migrations.RunPython( diff --git a/authentik/core/migrations/0023_alter_application_meta_launch_url.py b/authentik/core/migrations/0023_alter_application_meta_launch_url.py index 2a313c8e6..f94dfa57b 100644 --- a/authentik/core/migrations/0023_alter_application_meta_launch_url.py +++ b/authentik/core/migrations/0023_alter_application_meta_launch_url.py @@ -1,8 +1,9 @@ # Generated by Django 3.2.3 on 2021-06-02 21:51 -import django.core.validators from django.db import migrations, models +import authentik.lib.models + class Migration(migrations.Migration): @@ -17,7 +18,7 @@ class Migration(migrations.Migration): field=models.TextField( blank=True, default="", - validators=[django.core.validators.URLValidator()], + validators=[authentik.lib.models.DomainlessURLValidator()], ), ), ] diff --git a/authentik/core/models.py b/authentik/core/models.py index 2e022d667..63718c2d4 100644 --- a/authentik/core/models.py +++ b/authentik/core/models.py @@ -9,7 +9,6 @@ from deepmerge import always_merger from django.conf import settings from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import UserManager as DjangoUserManager -from django.core import validators from django.db import models from django.db.models import Q, QuerySet, options from django.http import HttpRequest @@ -29,7 +28,7 @@ from authentik.core.types import UILoginButton, UserSettingSerializer from authentik.flows.models import Flow from authentik.lib.config import CONFIG from authentik.lib.generators import generate_id -from authentik.lib.models import CreatedUpdatedModel, SerializerModel +from authentik.lib.models import CreatedUpdatedModel, DomainlessURLValidator, SerializerModel from authentik.lib.utils.http import get_client_ip from authentik.managed.models import ManagedModel from authentik.policies.models import PolicyBindingModel @@ -246,7 +245,7 @@ class Application(PolicyBindingModel): ) meta_launch_url = models.TextField( - default="", blank=True, validators=[validators.URLValidator()] + default="", blank=True, validators=[DomainlessURLValidator()] ) # For template applications, this can be set to /static/authentik/applications/* meta_icon = models.FileField( diff --git a/authentik/core/tests/utils.py b/authentik/core/tests/utils.py index fe230d341..74fbc048a 100644 --- a/authentik/core/tests/utils.py +++ b/authentik/core/tests/utils.py @@ -22,7 +22,7 @@ def create_test_flow(designation: FlowDesignation = FlowDesignation.STAGE_CONFIG ) -def create_test_admin_user(name: Optional[str] = None, set_password=False) -> User: +def create_test_admin_user(name: Optional[str] = None) -> User: """Generate a test-admin user""" uid = generate_id(20) if not name else name group = Group.objects.create(name=uid, is_superuser=True) diff --git a/authentik/events/migrations/0001_squashed_0019_alter_notificationtransport_webhook_url.py b/authentik/events/migrations/0001_squashed_0019_alter_notificationtransport_webhook_url.py index 3c5897432..10a3a04aa 100644 --- a/authentik/events/migrations/0001_squashed_0019_alter_notificationtransport_webhook_url.py +++ b/authentik/events/migrations/0001_squashed_0019_alter_notificationtransport_webhook_url.py @@ -4,7 +4,6 @@ import uuid from datetime import timedelta from typing import Iterable -import django.core.validators import django.db.models.deletion from django.apps.registry import Apps from django.conf import settings @@ -12,6 +11,7 @@ from django.db import migrations, models from django.db.backends.base.schema import BaseDatabaseSchemaEditor import authentik.events.models +import authentik.lib.models from authentik.events.models import EventAction, NotificationSeverity, TransportMode @@ -826,6 +826,8 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="notificationtransport", name="webhook_url", - field=models.TextField(blank=True, validators=[django.core.validators.URLValidator()]), + field=models.TextField( + blank=True, validators=[authentik.lib.models.DomainlessURLValidator()] + ), ), ] diff --git a/authentik/events/migrations/0019_alter_notificationtransport_webhook_url.py b/authentik/events/migrations/0019_alter_notificationtransport_webhook_url.py index 4738d3e0a..65a83f247 100644 --- a/authentik/events/migrations/0019_alter_notificationtransport_webhook_url.py +++ b/authentik/events/migrations/0019_alter_notificationtransport_webhook_url.py @@ -1,8 +1,9 @@ # Generated by Django 3.2.7 on 2021-10-04 15:31 -import django.core.validators from django.db import migrations, models +import authentik.lib.models + class Migration(migrations.Migration): @@ -14,6 +15,8 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="notificationtransport", name="webhook_url", - field=models.TextField(blank=True, validators=[django.core.validators.URLValidator()]), + field=models.TextField( + blank=True, validators=[authentik.lib.models.DomainlessURLValidator()] + ), ), ] diff --git a/authentik/events/models.py b/authentik/events/models.py index af5022b99..a2aa89680 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Optional, Type, Union from uuid import uuid4 from django.conf import settings -from django.core.validators import URLValidator from django.db import models from django.http import HttpRequest from django.http.request import QueryDict @@ -20,6 +19,7 @@ from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION from authentik.core.models import ExpiringModel, Group, PropertyMapping, User from authentik.events.geo import GEOIP_READER from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict +from authentik.lib.models import DomainlessURLValidator from authentik.lib.sentry import SentryIgnoredException from authentik.lib.utils.http import get_client_ip, get_http_session from authentik.lib.utils.time import timedelta_from_string @@ -224,7 +224,7 @@ class NotificationTransport(models.Model): name = models.TextField(unique=True) mode = models.TextField(choices=TransportMode.choices) - webhook_url = models.TextField(blank=True, validators=[URLValidator()]) + webhook_url = models.TextField(blank=True, validators=[DomainlessURLValidator()]) webhook_mapping = models.ForeignKey( "NotificationWebhookMapping", on_delete=models.SET_DEFAULT, null=True, default=None ) diff --git a/authentik/lib/models.py b/authentik/lib/models.py index 202c692c3..928d13395 100644 --- a/authentik/lib/models.py +++ b/authentik/lib/models.py @@ -1,6 +1,7 @@ """Generic models""" import re +from django.core.exceptions import ValidationError from django.core.validators import URLValidator from django.db import models from django.utils.regex_helper import _lazy_re_compile @@ -66,3 +67,11 @@ class DomainlessURLValidator(URLValidator): r"\Z", re.IGNORECASE, ) + self.schemes = ["http", "https", "blank"] + + def __call__(self, value): + # Check if the scheme is valid. + scheme = value.split("://")[0].lower() + if scheme not in self.schemes: + value = "default" + value + return super().__call__(value) diff --git a/tests/e2e/utils.py b/tests/e2e/utils.py index 3ec254399..08ff15b6f 100644 --- a/tests/e2e/utils.py +++ b/tests/e2e/utils.py @@ -61,7 +61,7 @@ class SeleniumTestCase(ChannelsLiveServerTestCase): self.driver.implicitly_wait(30) self.wait = WebDriverWait(self.driver, self.wait_timeout) self.logger = get_logger() - self.user = create_test_admin_user(set_password=True) + self.user = create_test_admin_user() if specs := self.get_container_specs(): self.container = self._start_container(specs)