*: allow URLs without domain and custom schemas
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
8794c840cf
commit
6ed7d842e4
|
@ -3,7 +3,6 @@
|
||||||
import uuid
|
import uuid
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.apps.registry import Apps
|
from django.apps.registry import Apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -12,6 +11,7 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
import authentik.core.models
|
import authentik.core.models
|
||||||
|
import authentik.lib.models
|
||||||
|
|
||||||
|
|
||||||
def migrate_sessions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
def migrate_sessions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||||
|
@ -161,7 +161,7 @@ class Migration(migrations.Migration):
|
||||||
model_name="application",
|
model_name="application",
|
||||||
name="meta_launch_url",
|
name="meta_launch_url",
|
||||||
field=models.TextField(
|
field=models.TextField(
|
||||||
blank=True, default="", validators=[django.core.validators.URLValidator()]
|
blank=True, default="", validators=[authentik.lib.models.DomainlessURLValidator()]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.RunPython(
|
migrations.RunPython(
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
# Generated by Django 3.2.3 on 2021-06-02 21:51
|
# Generated by Django 3.2.3 on 2021-06-02 21:51
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import authentik.lib.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ class Migration(migrations.Migration):
|
||||||
field=models.TextField(
|
field=models.TextField(
|
||||||
blank=True,
|
blank=True,
|
||||||
default="",
|
default="",
|
||||||
validators=[django.core.validators.URLValidator()],
|
validators=[authentik.lib.models.DomainlessURLValidator()],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,7 +9,6 @@ from deepmerge import always_merger
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||||
from django.core import validators
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q, QuerySet, options
|
from django.db.models import Q, QuerySet, options
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
@ -29,7 +28,7 @@ from authentik.core.types import UILoginButton, UserSettingSerializer
|
||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.generators import generate_id
|
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.lib.utils.http import get_client_ip
|
||||||
from authentik.managed.models import ManagedModel
|
from authentik.managed.models import ManagedModel
|
||||||
from authentik.policies.models import PolicyBindingModel
|
from authentik.policies.models import PolicyBindingModel
|
||||||
|
@ -246,7 +245,7 @@ class Application(PolicyBindingModel):
|
||||||
)
|
)
|
||||||
|
|
||||||
meta_launch_url = models.TextField(
|
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/*
|
# For template applications, this can be set to /static/authentik/applications/*
|
||||||
meta_icon = models.FileField(
|
meta_icon = models.FileField(
|
||||||
|
|
|
@ -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"""
|
"""Generate a test-admin user"""
|
||||||
uid = generate_id(20) if not name else name
|
uid = generate_id(20) if not name else name
|
||||||
group = Group.objects.create(name=uid, is_superuser=True)
|
group = Group.objects.create(name=uid, is_superuser=True)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import uuid
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.apps.registry import Apps
|
from django.apps.registry import Apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -12,6 +11,7 @@ from django.db import migrations, models
|
||||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||||
|
|
||||||
import authentik.events.models
|
import authentik.events.models
|
||||||
|
import authentik.lib.models
|
||||||
from authentik.events.models import EventAction, NotificationSeverity, TransportMode
|
from authentik.events.models import EventAction, NotificationSeverity, TransportMode
|
||||||
|
|
||||||
|
|
||||||
|
@ -826,6 +826,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="notificationtransport",
|
model_name="notificationtransport",
|
||||||
name="webhook_url",
|
name="webhook_url",
|
||||||
field=models.TextField(blank=True, validators=[django.core.validators.URLValidator()]),
|
field=models.TextField(
|
||||||
|
blank=True, validators=[authentik.lib.models.DomainlessURLValidator()]
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
# Generated by Django 3.2.7 on 2021-10-04 15:31
|
# Generated by Django 3.2.7 on 2021-10-04 15:31
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import authentik.lib.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
@ -14,6 +15,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="notificationtransport",
|
model_name="notificationtransport",
|
||||||
name="webhook_url",
|
name="webhook_url",
|
||||||
field=models.TextField(blank=True, validators=[django.core.validators.URLValidator()]),
|
field=models.TextField(
|
||||||
|
blank=True, validators=[authentik.lib.models.DomainlessURLValidator()]
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Optional, Type, Union
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.validators import URLValidator
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.http.request import QueryDict
|
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.core.models import ExpiringModel, Group, PropertyMapping, User
|
||||||
from authentik.events.geo import GEOIP_READER
|
from authentik.events.geo import GEOIP_READER
|
||||||
from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict
|
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.sentry import SentryIgnoredException
|
||||||
from authentik.lib.utils.http import get_client_ip, get_http_session
|
from authentik.lib.utils.http import get_client_ip, get_http_session
|
||||||
from authentik.lib.utils.time import timedelta_from_string
|
from authentik.lib.utils.time import timedelta_from_string
|
||||||
|
@ -224,7 +224,7 @@ class NotificationTransport(models.Model):
|
||||||
name = models.TextField(unique=True)
|
name = models.TextField(unique=True)
|
||||||
mode = models.TextField(choices=TransportMode.choices)
|
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(
|
webhook_mapping = models.ForeignKey(
|
||||||
"NotificationWebhookMapping", on_delete=models.SET_DEFAULT, null=True, default=None
|
"NotificationWebhookMapping", on_delete=models.SET_DEFAULT, null=True, default=None
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Generic models"""
|
"""Generic models"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import URLValidator
|
from django.core.validators import URLValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.regex_helper import _lazy_re_compile
|
from django.utils.regex_helper import _lazy_re_compile
|
||||||
|
@ -66,3 +67,11 @@ class DomainlessURLValidator(URLValidator):
|
||||||
r"\Z",
|
r"\Z",
|
||||||
re.IGNORECASE,
|
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)
|
||||||
|
|
|
@ -61,7 +61,7 @@ class SeleniumTestCase(ChannelsLiveServerTestCase):
|
||||||
self.driver.implicitly_wait(30)
|
self.driver.implicitly_wait(30)
|
||||||
self.wait = WebDriverWait(self.driver, self.wait_timeout)
|
self.wait = WebDriverWait(self.driver, self.wait_timeout)
|
||||||
self.logger = get_logger()
|
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():
|
if specs := self.get_container_specs():
|
||||||
self.container = self._start_container(specs)
|
self.container = self._start_container(specs)
|
||||||
|
|
||||||
|
|
Reference in New Issue