diff --git a/.github/workflows/ci-outpost.yml b/.github/workflows/ci-outpost.yml
index fe8ebf3b8..517407003 100644
--- a/.github/workflows/ci-outpost.yml
+++ b/.github/workflows/ci-outpost.yml
@@ -29,7 +29,7 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
- version: v1.52.2
+ version: v1.54.2
args: --timeout 5000s --verbose
skip-cache: true
test-unittest:
diff --git a/.gitignore b/.gitignore
index 17f1a196d..713258ca7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -206,3 +206,6 @@ data/
.netlify
.ruff_cache
source_docs/
+
+### Golang ###
+/vendor/
diff --git a/Dockerfile b/Dockerfile
index 95d20d999..6556ed3a1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -35,7 +35,7 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
RUN npm run build
# Stage 3: Build go proxy
-FROM docker.io/golang:1.21.1-bookworm AS go-builder
+FROM docker.io/golang:1.21.2-bookworm AS go-builder
WORKDIR /go/src/goauthentik.io
diff --git a/Makefile b/Makefile
index 8a122b7e1..bb7f70a43 100644
--- a/Makefile
+++ b/Makefile
@@ -81,7 +81,7 @@ dev-drop-db:
dropdb -U ${pg_user} -h ${pg_host} ${pg_name}
# Also remove the test-db if it exists
dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
- echo redis-cli -n 0 flushall
+ redis-cli -n 0 flushall
dev-create-db:
createdb -U ${pg_user} -h ${pg_host} ${pg_name}
diff --git a/authentik/core/api/users.py b/authentik/core/api/users.py
index 09a5dc553..be59dc1c1 100644
--- a/authentik/core/api/users.py
+++ b/authentik/core/api/users.py
@@ -190,6 +190,7 @@ class UserSerializer(ModelSerializer):
"uid",
"path",
"type",
+ "uuid",
]
extra_kwargs = {
"name": {"allow_blank": True},
diff --git a/authentik/events/monitored_tasks.py b/authentik/events/monitored_tasks.py
index 9acee40b6..70f59f610 100644
--- a/authentik/events/monitored_tasks.py
+++ b/authentik/events/monitored_tasks.py
@@ -206,8 +206,8 @@ def prefill_task(func):
task_call_module=func.__module__,
task_call_func=func.__name__,
# We don't have real values for these attributes but they cannot be null
- start_timestamp=default_timer(),
- finish_timestamp=default_timer(),
+ start_timestamp=0,
+ finish_timestamp=0,
finish_time=datetime.now(),
).save(86400)
LOGGER.debug("prefilled task", task_name=func.__name__)
diff --git a/authentik/flows/apps.py b/authentik/flows/apps.py
index e01640bfc..45ebb8489 100644
--- a/authentik/flows/apps.py
+++ b/authentik/flows/apps.py
@@ -8,6 +8,11 @@ GAUGE_FLOWS_CACHED = Gauge(
"authentik_flows_cached",
"Cached flows",
)
+HIST_FLOW_EXECUTION_STAGE_TIME = Histogram(
+ "authentik_flows_execution_stage_time",
+ "Duration each stage took to execute.",
+ ["stage_type", "method"],
+)
HIST_FLOWS_PLAN_TIME = Histogram(
"authentik_flows_plan_time",
"Duration to build a plan for a flow",
diff --git a/authentik/flows/views/executor.py b/authentik/flows/views/executor.py
index 92b944670..773650c00 100644
--- a/authentik/flows/views/executor.py
+++ b/authentik/flows/views/executor.py
@@ -24,6 +24,7 @@ from structlog.stdlib import BoundLogger, get_logger
from authentik.core.models import Application
from authentik.events.models import Event, EventAction, cleanse_dict
+from authentik.flows.apps import HIST_FLOW_EXECUTION_STAGE_TIME
from authentik.flows.challenge import (
Challenge,
ChallengeResponse,
@@ -266,17 +267,21 @@ class FlowExecutorView(APIView):
)
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Get the next pending challenge from the currently active flow."""
+ class_path = class_to_path(self.current_stage_view.__class__)
self._logger.debug(
"f(exec): Passing GET",
- view_class=class_to_path(self.current_stage_view.__class__),
+ view_class=class_path,
stage=self.current_stage,
)
try:
with Hub.current.start_span(
op="authentik.flow.executor.stage",
- description=class_to_path(self.current_stage_view.__class__),
- ) as span:
- span.set_data("Method", "GET")
+ description=class_path,
+ ) as span, HIST_FLOW_EXECUTION_STAGE_TIME.labels(
+ method=request.method.upper(),
+ stage_type=class_path,
+ ).time():
+ span.set_data("Method", request.method.upper())
span.set_data("authentik Stage", self.current_stage_view)
span.set_data("authentik Flow", self.flow.slug)
stage_response = self.current_stage_view.dispatch(request)
@@ -310,17 +315,21 @@ class FlowExecutorView(APIView):
)
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Solve the previously retrieved challenge and advanced to the next stage."""
+ class_path = class_to_path(self.current_stage_view.__class__)
self._logger.debug(
"f(exec): Passing POST",
- view_class=class_to_path(self.current_stage_view.__class__),
+ view_class=class_path,
stage=self.current_stage,
)
try:
with Hub.current.start_span(
op="authentik.flow.executor.stage",
- description=class_to_path(self.current_stage_view.__class__),
- ) as span:
- span.set_data("Method", "POST")
+ description=class_path,
+ ) as span, HIST_FLOW_EXECUTION_STAGE_TIME.labels(
+ method=request.method.upper(),
+ stage_type=class_path,
+ ).time():
+ span.set_data("Method", request.method.upper())
span.set_data("authentik Stage", self.current_stage_view)
span.set_data("authentik Flow", self.flow.slug)
stage_response = self.current_stage_view.dispatch(request)
diff --git a/authentik/lib/config.py b/authentik/lib/config.py
index 043f77460..63aa3493a 100644
--- a/authentik/lib/config.py
+++ b/authentik/lib/config.py
@@ -24,7 +24,7 @@ ENVIRONMENT = os.getenv(f"{ENV_PREFIX}_ENV", "local")
def get_path_from_dict(root: dict, path: str, sep=".", default=None) -> Any:
- """Recursively walk through `root`, checking each part of `path` split by `sep`.
+ """Recursively walk through `root`, checking each part of `path` separated by `sep`.
If at any point a dict does not exist, return default"""
for comp in path.split(sep):
if root and comp in root:
@@ -34,7 +34,19 @@ def get_path_from_dict(root: dict, path: str, sep=".", default=None) -> Any:
return root
-@dataclass
+def set_path_in_dict(root: dict, path: str, value: Any, sep="."):
+ """Recursively walk through `root`, checking each part of `path` separated by `sep`
+ and setting the last value to `value`"""
+ # Walk each component of the path
+ path_parts = path.split(sep)
+ for comp in path_parts[:-1]:
+ if comp not in root:
+ root[comp] = {}
+ root = root.get(comp, {})
+ root[path_parts[-1]] = value
+
+
+@dataclass(slots=True)
class Attr:
"""Single configuration attribute"""
@@ -55,6 +67,10 @@ class Attr:
# to the config file containing this change or the file containing this value
source: Optional[str] = field(default=None)
+ def __post_init__(self):
+ if isinstance(self.value, Attr):
+ raise RuntimeError(f"config Attr with nested Attr for source {self.source}")
+
class AttrEncoder(JSONEncoder):
"""JSON encoder that can deal with `Attr` classes"""
@@ -227,15 +243,7 @@ class ConfigLoader:
def set(self, path: str, value: Any, sep="."):
"""Set value using same syntax as get()"""
- # Walk sub_dicts before parsing path
- root = self.raw
- # Walk each component of the path
- path_parts = path.split(sep)
- for comp in path_parts[:-1]:
- if comp not in root:
- root[comp] = {}
- root = root.get(comp, {})
- root[path_parts[-1]] = Attr(value)
+ set_path_in_dict(self.raw, path, Attr(value), sep=sep)
CONFIG = ConfigLoader()
diff --git a/authentik/outposts/channels.py b/authentik/outposts/channels.py
index 8b3f978ac..f0b656a47 100644
--- a/authentik/outposts/channels.py
+++ b/authentik/outposts/channels.py
@@ -27,6 +27,9 @@ class WebsocketMessageInstruction(IntEnum):
# Message sent by us to trigger an Update
TRIGGER_UPDATE = 2
+ # Provider specific message
+ PROVIDER_SPECIFIC = 3
+
@dataclass(slots=True)
class WebsocketMessage:
@@ -131,3 +134,14 @@ class OutpostConsumer(AuthJsonConsumer):
self.send_json(
asdict(WebsocketMessage(instruction=WebsocketMessageInstruction.TRIGGER_UPDATE))
)
+
+ def event_provider_specific(self, event):
+ """Event handler which can be called by provider-specific
+ implementations to send specific messages to the outpost"""
+ self.send_json(
+ asdict(
+ WebsocketMessage(
+ instruction=WebsocketMessageInstruction.PROVIDER_SPECIFIC, args=event
+ )
+ )
+ )
diff --git a/authentik/outposts/tasks.py b/authentik/outposts/tasks.py
index 227127352..ddb0d5352 100644
--- a/authentik/outposts/tasks.py
+++ b/authentik/outposts/tasks.py
@@ -5,7 +5,6 @@ from socket import gethostname
from typing import Any, Optional
from urllib.parse import urlparse
-import yaml
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.core.cache import cache
@@ -16,6 +15,7 @@ from docker.constants import DEFAULT_UNIX_SOCKET
from kubernetes.config.incluster_config import SERVICE_TOKEN_FILENAME
from kubernetes.config.kube_config import KUBE_CONFIG_DEFAULT_LOCATION
from structlog.stdlib import get_logger
+from yaml import safe_load
from authentik.events.monitored_tasks import (
MonitoredTask,
@@ -279,7 +279,7 @@ def outpost_connection_discovery(self: MonitoredTask):
with kubeconfig_path.open("r", encoding="utf8") as _kubeconfig:
KubernetesServiceConnection.objects.create(
name=kubeconfig_local_name,
- kubeconfig=yaml.safe_load(_kubeconfig),
+ kubeconfig=safe_load(_kubeconfig),
)
unix_socket_path = urlparse(DEFAULT_UNIX_SOCKET).path
socket = Path(unix_socket_path)
diff --git a/authentik/policies/apps.py b/authentik/policies/apps.py
index 17ef4a3a4..d66b77487 100644
--- a/authentik/policies/apps.py
+++ b/authentik/policies/apps.py
@@ -7,7 +7,11 @@ GAUGE_POLICIES_CACHED = Gauge(
"authentik_policies_cached",
"Cached Policies",
)
-
+HIST_POLICIES_ENGINE_TOTAL_TIME = Histogram(
+ "authentik_policies_engine_time_total_seconds",
+ "(Total) Duration the policy engine took to evaluate a result.",
+ ["obj_type", "obj_pk"],
+)
HIST_POLICIES_EXECUTION_TIME = Histogram(
"authentik_policies_execution_time",
"Execution times for single policies",
@@ -17,6 +21,7 @@ HIST_POLICIES_EXECUTION_TIME = Histogram(
"binding_target_name",
"object_pk",
"object_type",
+ "mode",
],
)
diff --git a/authentik/policies/engine.py b/authentik/policies/engine.py
index a3d8a3191..58295f321 100644
--- a/authentik/policies/engine.py
+++ b/authentik/policies/engine.py
@@ -1,6 +1,7 @@
"""authentik policy engine"""
from multiprocessing import Pipe, current_process
from multiprocessing.connection import Connection
+from timeit import default_timer
from typing import Iterator, Optional
from django.core.cache import cache
@@ -10,6 +11,8 @@ from sentry_sdk.tracing import Span
from structlog.stdlib import BoundLogger, get_logger
from authentik.core.models import User
+from authentik.lib.utils.reflection import class_to_path
+from authentik.policies.apps import HIST_POLICIES_ENGINE_TOTAL_TIME, HIST_POLICIES_EXECUTION_TIME
from authentik.policies.exceptions import PolicyEngineException
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel, PolicyEngineMode
from authentik.policies.process import PolicyProcess, cache_key
@@ -77,6 +80,33 @@ class PolicyEngine:
if binding.policy is not None and binding.policy.__class__ == Policy:
raise PolicyEngineException(f"Policy '{binding.policy}' is root type")
+ def _check_cache(self, binding: PolicyBinding):
+ if not self.use_cache:
+ return False
+ before = default_timer()
+ key = cache_key(binding, self.request)
+ cached_policy = cache.get(key, None)
+ duration = max(default_timer() - before, 0)
+ if not cached_policy:
+ return False
+ self.logger.debug(
+ "P_ENG: Taking result from cache",
+ binding=binding,
+ cache_key=key,
+ request=self.request,
+ )
+ HIST_POLICIES_EXECUTION_TIME.labels(
+ binding_order=binding.order,
+ binding_target_type=binding.target_type,
+ binding_target_name=binding.target_name,
+ object_pk=str(self.request.obj.pk),
+ object_type=class_to_path(self.request.obj.__class__),
+ mode="cache_retrieve",
+ ).observe(duration)
+ # It's a bit silly to time this, but
+ self.__cached_policies.append(cached_policy)
+ return True
+
def build(self) -> "PolicyEngine":
"""Build wrapper which monitors performance"""
with (
@@ -84,6 +114,10 @@ class PolicyEngine:
op="authentik.policy.engine.build",
description=self.__pbm,
) as span,
+ HIST_POLICIES_ENGINE_TOTAL_TIME.labels(
+ obj_type=class_to_path(self.__pbm.__class__),
+ obj_pk=str(self.__pbm.pk),
+ ).time(),
):
span: Span
span.set_data("pbm", self.__pbm)
@@ -92,16 +126,7 @@ class PolicyEngine:
self.__expected_result_count += 1
self._check_policy_type(binding)
- key = cache_key(binding, self.request)
- cached_policy = cache.get(key, None)
- if cached_policy and self.use_cache:
- self.logger.debug(
- "P_ENG: Taking result from cache",
- binding=binding,
- cache_key=key,
- request=self.request,
- )
- self.__cached_policies.append(cached_policy)
+ if self._check_cache(binding):
continue
self.logger.debug("P_ENG: Evaluating policy", binding=binding, request=self.request)
our_end, task_end = Pipe(False)
diff --git a/authentik/policies/process.py b/authentik/policies/process.py
index 89dc548da..aa3ed9ff5 100644
--- a/authentik/policies/process.py
+++ b/authentik/policies/process.py
@@ -11,6 +11,7 @@ from structlog.stdlib import get_logger
from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
from authentik.lib.utils.errors import exception_to_string
+from authentik.lib.utils.reflection import class_to_path
from authentik.policies.apps import HIST_POLICIES_EXECUTION_TIME
from authentik.policies.exceptions import PolicyException
from authentik.policies.models import PolicyBinding
@@ -128,9 +129,8 @@ class PolicyProcess(PROCESS_CLASS):
binding_target_type=self.binding.target_type,
binding_target_name=self.binding.target_name,
object_pk=str(self.request.obj.pk),
- object_type=(
- f"{self.request.obj._meta.app_label}.{self.request.obj._meta.model_name}"
- ),
+ object_type=class_to_path(self.request.obj.__class__),
+ mode="execute_process",
).time(),
):
span: Span
diff --git a/authentik/policies/signals.py b/authentik/policies/signals.py
index 52c5ec767..d7949330f 100644
--- a/authentik/policies/signals.py
+++ b/authentik/policies/signals.py
@@ -17,7 +17,7 @@ LOGGER = get_logger()
@receiver(monitoring_set)
def monitoring_set_policies(sender, **kwargs):
"""set policy gauges"""
- GAUGE_POLICIES_CACHED.set(len(cache.keys(f"{CACHE_PREFIX}_*") or []))
+ GAUGE_POLICIES_CACHED.set(len(cache.keys(f"{CACHE_PREFIX}*") or []))
@receiver(post_save, sender=Policy)
diff --git a/authentik/providers/proxy/apps.py b/authentik/providers/proxy/apps.py
index 5e49fe181..4e1a9a883 100644
--- a/authentik/providers/proxy/apps.py
+++ b/authentik/providers/proxy/apps.py
@@ -9,3 +9,7 @@ class AuthentikProviderProxyConfig(ManagedAppConfig):
label = "authentik_providers_proxy"
verbose_name = "authentik Providers.Proxy"
default = True
+
+ def reconcile_load_providers_proxy_signals(self):
+ """Load proxy signals"""
+ self.import_module("authentik.providers.proxy.signals")
diff --git a/authentik/providers/proxy/signals.py b/authentik/providers/proxy/signals.py
new file mode 100644
index 000000000..3e199d3c3
--- /dev/null
+++ b/authentik/providers/proxy/signals.py
@@ -0,0 +1,20 @@
+"""Proxy provider signals"""
+from django.contrib.auth.signals import user_logged_out
+from django.db.models.signals import pre_delete
+from django.dispatch import receiver
+from django.http import HttpRequest
+
+from authentik.core.models import AuthenticatedSession, User
+from authentik.providers.proxy.tasks import proxy_on_logout
+
+
+@receiver(user_logged_out)
+def logout_proxy_revoke_direct(sender: type[User], request: HttpRequest, **_):
+ """Catch logout by direct logout and forward to proxy providers"""
+ proxy_on_logout.delay(request.session.session_key)
+
+
+@receiver(pre_delete, sender=AuthenticatedSession)
+def logout_proxy_revoke(sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_):
+ """Catch logout by expiring sessions being deleted"""
+ proxy_on_logout.delay(instance.session_key)
diff --git a/authentik/providers/proxy/tasks.py b/authentik/providers/proxy/tasks.py
index a5a4dc45f..630b0d186 100644
--- a/authentik/providers/proxy/tasks.py
+++ b/authentik/providers/proxy/tasks.py
@@ -1,6 +1,9 @@
"""proxy provider tasks"""
+from asgiref.sync import async_to_sync
+from channels.layers import get_channel_layer
from django.db import DatabaseError, InternalError, ProgrammingError
+from authentik.outposts.models import Outpost, OutpostState, OutpostType
from authentik.providers.proxy.models import ProxyProvider
from authentik.root.celery import CELERY_APP
@@ -13,3 +16,20 @@ def proxy_set_defaults():
for provider in ProxyProvider.objects.all():
provider.set_oauth_defaults()
provider.save()
+
+
+@CELERY_APP.task()
+def proxy_on_logout(session_id: str):
+ """Update outpost instances connected to a single outpost"""
+ layer = get_channel_layer()
+ for outpost in Outpost.objects.filter(type=OutpostType.PROXY):
+ for state in OutpostState.for_outpost(outpost):
+ for channel in state.channel_ids:
+ async_to_sync(layer.send)(
+ channel,
+ {
+ "type": "event.provider.specific",
+ "sub_type": "logout",
+ "session_id": session_id,
+ },
+ )
diff --git a/authentik/providers/saml/api/providers.py b/authentik/providers/saml/api/providers.py
index 891289a08..226ec7e58 100644
--- a/authentik/providers/saml/api/providers.py
+++ b/authentik/providers/saml/api/providers.py
@@ -146,6 +146,7 @@ class SAMLProviderSerializer(ProviderSerializer):
"signing_kp",
"verification_kp",
"sp_binding",
+ "default_relay_state",
"url_download_metadata",
"url_sso_post",
"url_sso_redirect",
diff --git a/authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py b/authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py
new file mode 100644
index 000000000..5ece7f52d
--- /dev/null
+++ b/authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py
@@ -0,0 +1,21 @@
+# Generated by Django 4.2.6 on 2023-10-08 20:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("authentik_providers_saml", "0012_managed"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="samlprovider",
+ name="default_relay_state",
+ field=models.TextField(
+ blank=True,
+ default="",
+ help_text="Default relay_state value for IDP-initiated logins",
+ ),
+ ),
+ ]
diff --git a/authentik/providers/saml/models.py b/authentik/providers/saml/models.py
index e92f62943..1a706df8e 100644
--- a/authentik/providers/saml/models.py
+++ b/authentik/providers/saml/models.py
@@ -138,6 +138,10 @@ class SAMLProvider(Provider):
verbose_name=_("Signing Keypair"),
)
+ default_relay_state = models.TextField(
+ default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
+ )
+
@property
def launch_url(self) -> Optional[str]:
"""Use IDP-Initiated SAML flow as launch URL"""
diff --git a/authentik/providers/saml/processors/authn_request_parser.py b/authentik/providers/saml/processors/authn_request_parser.py
index 30eddf0d3..5587cb695 100644
--- a/authentik/providers/saml/processors/authn_request_parser.py
+++ b/authentik/providers/saml/processors/authn_request_parser.py
@@ -175,4 +175,7 @@ class AuthNRequestParser:
def idp_initiated(self) -> AuthNRequest:
"""Create IdP Initiated AuthNRequest"""
- return AuthNRequest()
+ relay_state = None
+ if self.provider.default_relay_state != "":
+ relay_state = self.provider.default_relay_state
+ return AuthNRequest(relay_state=relay_state)
diff --git a/authentik/providers/saml/tests/test_auth_n_request.py b/authentik/providers/saml/tests/test_auth_n_request.py
index 69326bd5f..df19eb736 100644
--- a/authentik/providers/saml/tests/test_auth_n_request.py
+++ b/authentik/providers/saml/tests/test_auth_n_request.py
@@ -8,6 +8,7 @@ from authentik.blueprints.tests import apply_blueprint
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction
+from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import get_request
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.assertion import AssertionProcessor
@@ -264,3 +265,10 @@ class TestAuthNRequest(TestCase):
events.first().context["message"],
"Failed to evaluate property-mapping: 'test'",
)
+
+ def test_idp_initiated(self):
+ """Test IDP-initiated login"""
+ self.provider.default_relay_state = generate_id()
+ request = AuthNRequestParser(self.provider).idp_initiated()
+ self.assertEqual(request.id, None)
+ self.assertEqual(request.relay_state, self.provider.default_relay_state)
diff --git a/authentik/root/test_runner.py b/authentik/root/test_runner.py
index 5141613b0..02425f016 100644
--- a/authentik/root/test_runner.py
+++ b/authentik/root/test_runner.py
@@ -1,8 +1,10 @@
"""Integrate ./manage.py test with pytest"""
+import os
from argparse import ArgumentParser
from unittest import TestCase
from django.conf import settings
+from django.test.runner import DiscoverRunner
from authentik.lib.config import CONFIG
from authentik.lib.sentry import sentry_init
@@ -12,13 +14,11 @@ from tests.e2e.utils import get_docker_tag
TestCase.maxDiff = None
-class PytestTestRunner: # pragma: no cover
+class PytestTestRunner(DiscoverRunner): # pragma: no cover
"""Runs pytest to discover and run tests."""
def __init__(self, verbosity=1, failfast=False, keepdb=False, **kwargs):
- self.verbosity = verbosity
- self.failfast = failfast
- self.keepdb = keepdb
+ super().__init__(verbosity, failfast, keepdb, **kwargs)
self.args = []
if self.failfast:
@@ -47,16 +47,61 @@ class PytestTestRunner: # pragma: no cover
@classmethod
def add_arguments(cls, parser: ArgumentParser):
"""Add more pytest-specific arguments"""
- parser.add_argument("--randomly-seed", type=int)
- parser.add_argument("--keepdb", action="store_true")
+ parser.add_argument(
+ "--randomly-seed",
+ type=int,
+ help="Set the seed that pytest-randomly uses (int), or pass the special value 'last'"
+ "to reuse the seed from the previous run."
+ "Default behaviour: use random.Random().getrandbits(32), so the seed is"
+ "different on each run.",
+ )
+ parser.add_argument(
+ "--keepdb", action="store_true", help="Preserves the test DB between runs."
+ )
- def run_tests(self, test_labels):
+ def run_tests(self, test_labels, extra_tests=None, **kwargs):
"""Run pytest and return the exitcode.
It translates some of Django's test command option to pytest's.
+ It is supported to only run specific classes and methods using
+ a dotted module name i.e. foo.bar[.Class[.method]]
+
+ The extra_tests argument has been deprecated since Django 5.x
+ It is kept for compatibility with PyCharm's Django test runner.
"""
+ for label in test_labels:
+ valid_label_found = False
+ label_as_path = os.path.abspath(label)
+ # File path has been specified
+ if os.path.exists(label_as_path):
+ self.args.append(label_as_path)
+ valid_label_found = True
+ else:
+ # Already correctly formatted test found (file_path::class::method)
+ if "::" in label:
+ self.args.append(label)
+ valid_label_found = True
+ # Convert dotted module path to file_path::class::method
+ else:
+ path_pieces = label.split(".")
+ # Check whether only class or class and method are specified
+ for i in range(-1, -3, -1):
+ path = os.path.join(*path_pieces[:i]) + ".py"
+ label_as_path = os.path.abspath(path)
+ if os.path.exists(label_as_path):
+ path_method = label_as_path + "::" + "::".join(path_pieces[i:])
+ self.args.append(path_method)
+ valid_label_found = True
+ break
+
+ if not valid_label_found:
+ raise RuntimeError(
+ f"One of the test labels: {label!r}, "
+ f"is not supported. Use a dotted module name or "
+ f"path instead."
+ )
+
import pytest
- self.args.extend(test_labels)
return pytest.main(self.args)
diff --git a/authentik/sources/ldap/sync/base.py b/authentik/sources/ldap/sync/base.py
index a131d935c..7490449ec 100644
--- a/authentik/sources/ldap/sync/base.py
+++ b/authentik/sources/ldap/sync/base.py
@@ -9,7 +9,7 @@ from structlog.stdlib import BoundLogger, get_logger
from authentik.core.exceptions import PropertyMappingExpressionException
from authentik.events.models import Event, EventAction
-from authentik.lib.config import CONFIG
+from authentik.lib.config import CONFIG, set_path_in_dict
from authentik.lib.merge import MERGE_LIST_UNIQUE
from authentik.sources.ldap.auth import LDAP_DISTINGUISHED_NAME
from authentik.sources.ldap.models import LDAPPropertyMapping, LDAPSource
@@ -164,7 +164,7 @@ class BaseLDAPSynchronizer:
if object_field.startswith("attributes."):
# Because returning a list might desired, we can't
# rely on self._flatten here. Instead, just save the result as-is
- properties["attributes"][object_field.replace("attributes.", "")] = value
+ set_path_in_dict(properties, object_field, value)
else:
properties[object_field] = self._flatten(value)
except PropertyMappingExpressionException as exc:
diff --git a/authentik/stages/user_write/stage.py b/authentik/stages/user_write/stage.py
index 98494fae1..5a4c80974 100644
--- a/authentik/stages/user_write/stage.py
+++ b/authentik/stages/user_write/stage.py
@@ -14,6 +14,7 @@ from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import StageView
from authentik.flows.views.executor import FlowExecutorView
+from authentik.lib.config import set_path_in_dict
from authentik.stages.password import BACKEND_INBUILT
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
@@ -44,12 +45,7 @@ class UserWriteStageView(StageView):
# this is just a sanity check to ensure that is removed
if parts[0] == "attributes":
parts = parts[1:]
- attrs = user.attributes
- for comp in parts[:-1]:
- if comp not in attrs:
- attrs[comp] = {}
- attrs = attrs.get(comp)
- attrs[parts[-1]] = value
+ set_path_in_dict(user.attributes, ".".join(parts), value)
def ensure_user(self) -> tuple[Optional[User], bool]:
"""Ensure a user exists"""
diff --git a/blueprints/schema.json b/blueprints/schema.json
index 7f7757a28..9dc77b796 100644
--- a/blueprints/schema.json
+++ b/blueprints/schema.json
@@ -4826,6 +4826,11 @@
],
"title": "Service Provider Binding",
"description": "This determines how authentik sends the response back to the Service Provider."
+ },
+ "default_relay_state": {
+ "type": "string",
+ "title": "Default relay state",
+ "description": "Default relay_state value for IDP-initiated logins"
}
},
"required": []
@@ -7427,146 +7432,32 @@
"model_authentik_stages_invitation.invitation": {
"type": "object",
"properties": {
+ "name": {
+ "type": "string",
+ "maxLength": 50,
+ "minLength": 1,
+ "pattern": "^[-a-zA-Z0-9_]+$",
+ "title": "Name"
+ },
"expires": {
"type": "string",
"format": "date-time",
"title": "Expires"
},
- "user": {
+ "fixed_data": {
"type": "object",
- "properties": {
- "username": {
- "type": "string",
- "maxLength": 150,
- "minLength": 1,
- "title": "Username"
- },
- "name": {
- "type": "string",
- "title": "Name",
- "description": "User's display name."
- },
- "is_active": {
- "type": "boolean",
- "title": "Active",
- "description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
- },
- "last_login": {
- "type": [
- "string",
- "null"
- ],
- "format": "date-time",
- "title": "Last login"
- },
- "groups": {
- "type": "array",
- "items": {
- "type": "integer"
- },
- "title": "Groups"
- },
- "email": {
- "type": "string",
- "format": "email",
- "maxLength": 254,
- "title": "Email address"
- },
- "attributes": {
- "type": "object",
- "additionalProperties": true,
- "title": "Attributes"
- },
- "path": {
- "type": "string",
- "minLength": 1,
- "title": "Path"
- },
- "type": {
- "type": "string",
- "enum": [
- "internal",
- "external",
- "service_account",
- "internal_service_account"
- ],
- "title": "Type"
- }
- },
- "required": [
- "username",
- "name"
- ],
- "title": "User"
+ "additionalProperties": true,
+ "title": "Fixed data"
},
- "application": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "minLength": 1,
- "title": "Name",
- "description": "Application's display Name."
- },
- "slug": {
- "type": "string",
- "maxLength": 50,
- "minLength": 1,
- "pattern": "^[-a-zA-Z0-9_]+$",
- "title": "Slug",
- "description": "Internal application name, used in URLs."
- },
- "provider": {
- "type": "integer",
- "title": "Provider"
- },
- "backchannel_providers": {
- "type": "array",
- "items": {
- "type": "integer"
- },
- "title": "Backchannel providers"
- },
- "open_in_new_tab": {
- "type": "boolean",
- "title": "Open in new tab",
- "description": "Open launch URL in a new browser tab or window."
- },
- "meta_launch_url": {
- "type": "string",
- "title": "Meta launch url"
- },
- "meta_description": {
- "type": "string",
- "title": "Meta description"
- },
- "meta_publisher": {
- "type": "string",
- "title": "Meta publisher"
- },
- "policy_engine_mode": {
- "type": "string",
- "enum": [
- "all",
- "any"
- ],
- "title": "Policy engine mode"
- },
- "group": {
- "type": "string",
- "title": "Group"
- }
- },
- "required": [
- "name",
- "slug"
- ],
- "title": "Application"
+ "single_use": {
+ "type": "boolean",
+ "title": "Single use",
+ "description": "When enabled, the invitation will be deleted after usage."
},
- "permissions": {
- "type": "string",
- "minLength": 1,
- "title": "Permissions"
+ "flow": {
+ "type": "integer",
+ "title": "Flow",
+ "description": "When set, only the configured flow can use this invitation."
}
},
"required": []
diff --git a/blueprints/system/providers-proxy.yaml b/blueprints/system/providers-proxy.yaml
index 1214d157d..0086645a8 100644
--- a/blueprints/system/providers-proxy.yaml
+++ b/blueprints/system/providers-proxy.yaml
@@ -15,6 +15,7 @@ entries:
# This mapping is used by the authentik proxy. It passes extra user attributes,
# which are used for example for the HTTP-Basic Authentication mapping.
return {
+ "sid": request.http_request.session.session_key,
"ak_proxy": {
"user_attributes": request.user.group_attributes(request),
"is_superuser": request.user.is_superuser,
diff --git a/go.mod b/go.mod
index a154977b2..a0bd758e2 100644
--- a/go.mod
+++ b/go.mod
@@ -1,12 +1,12 @@
module goauthentik.io
-go 1.20
+go 1.21
require (
beryju.io/ldap v0.1.0
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb
github.com/coreos/go-oidc v2.2.1+incompatible
- github.com/getsentry/sentry-go v0.24.1
+ github.com/getsentry/sentry-go v0.25.0
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-openapi/runtime v0.26.0
@@ -19,6 +19,7 @@ require (
github.com/gorilla/sessions v1.2.1
github.com/gorilla/websocket v1.5.0
github.com/jellydator/ttlcache/v3 v3.1.0
+ github.com/mitchellh/mapstructure v1.5.0
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/pires/go-proxyproto v0.7.0
github.com/prometheus/client_golang v1.17.0
@@ -26,10 +27,10 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
github.com/stretchr/testify v1.8.4
- goauthentik.io/api/v3 v3.2023083.4
+ goauthentik.io/api/v3 v3.2023083.5
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
- golang.org/x/oauth2 v0.12.0
- golang.org/x/sync v0.3.0
+ golang.org/x/oauth2 v0.13.0
+ golang.org/x/sync v0.4.0
gopkg.in/yaml.v2 v2.4.0
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
)
@@ -60,7 +61,6 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
- github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -72,9 +72,9 @@ require (
go.mongodb.org/mongo-driver v1.11.3 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
- golang.org/x/crypto v0.13.0 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sys v0.12.0 // indirect
+ golang.org/x/crypto v0.14.0 // indirect
+ golang.org/x/net v0.16.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
diff --git a/go.sum b/go.sum
index d5a3b1b62..36bc70908 100644
--- a/go.sum
+++ b/go.sum
@@ -49,7 +49,9 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
+github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
+github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -73,11 +75,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/getsentry/sentry-go v0.24.1 h1:W6/0GyTy8J6ge6lVCc94WB6Gx2ZuLrgopnn9w8Hiwuk=
-github.com/getsentry/sentry-go v0.24.1/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
+github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
+github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
+github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -196,6 +199,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -242,6 +246,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -269,6 +274,7 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
+github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -294,6 +300,7 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -343,11 +350,13 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
+go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
-goauthentik.io/api/v3 v3.2023083.4 h1:WIi2+LFfBTvhxcbH/WqvhY/4EsX8bAN6mrPODq02B/w=
-goauthentik.io/api/v3 v3.2023083.4/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
+go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
+goauthentik.io/api/v3 v3.2023083.5 h1:U9/+QWIVpsfZCZivMAsG6E6dq3/4wT5qt/k7uUC9rZc=
+goauthentik.io/api/v3 v3.2023083.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
@@ -359,8 +368,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -427,16 +437,16 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos=
+golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
-golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
+golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
+golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -449,8 +459,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
-golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -490,8 +500,9 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -645,6 +656,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
diff --git a/internal/outpost/ak/api.go b/internal/outpost/ak/api.go
index cfdb41dd0..f6003c02f 100644
--- a/internal/outpost/ak/api.go
+++ b/internal/outpost/ak/api.go
@@ -22,6 +22,8 @@ import (
log "github.com/sirupsen/logrus"
)
+type WSHandler func(ctx context.Context, args map[string]interface{})
+
const ConfigLogLevel = "log_level"
// APIController main controller which connects to the authentik api via http and ws
@@ -42,6 +44,7 @@ type APIController struct {
lastWsReconnect time.Time
wsIsReconnecting bool
wsBackoffMultiplier int
+ wsHandlers []WSHandler
refreshHandlers []func()
instanceUUID uuid.UUID
@@ -106,6 +109,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
reloadOffset: time.Duration(rand.Intn(10)) * time.Second,
instanceUUID: uuid.New(),
Outpost: outpost,
+ wsHandlers: []WSHandler{},
wsBackoffMultiplier: 1,
refreshHandlers: make([]func(), 0),
}
@@ -156,6 +160,10 @@ func (a *APIController) AddRefreshHandler(handler func()) {
a.refreshHandlers = append(a.refreshHandlers, handler)
}
+func (a *APIController) AddWSHandler(handler WSHandler) {
+ a.wsHandlers = append(a.wsHandlers, handler)
+}
+
func (a *APIController) OnRefresh() error {
// Because we don't know the outpost UUID, we simply do a list and pick the first
// The service account this token belongs to should only have access to a single outpost
diff --git a/internal/outpost/ak/api_ws.go b/internal/outpost/ak/api_ws.go
index 681b26fa4..24c5099f4 100644
--- a/internal/outpost/ak/api_ws.go
+++ b/internal/outpost/ak/api_ws.go
@@ -1,6 +1,7 @@
package ak
import (
+ "context"
"crypto/tls"
"fmt"
"net/http"
@@ -145,6 +146,10 @@ func (ac *APIController) startWSHandler() {
"build": constants.BUILD("tagged"),
}).SetToCurrentTime()
}
+ } else if wsMsg.Instruction == WebsocketInstructionProviderSpecific {
+ for _, h := range ac.wsHandlers {
+ h(context.Background(), wsMsg.Args)
+ }
}
}
}
diff --git a/internal/outpost/ak/api_ws_msg.go b/internal/outpost/ak/api_ws_msg.go
index f1f2e3aa8..cedecb93d 100644
--- a/internal/outpost/ak/api_ws_msg.go
+++ b/internal/outpost/ak/api_ws_msg.go
@@ -9,6 +9,8 @@ const (
WebsocketInstructionHello websocketInstruction = 1
// WebsocketInstructionTriggerUpdate Code received to trigger a config update
WebsocketInstructionTriggerUpdate websocketInstruction = 2
+ // WebsocketInstructionProviderSpecific Code received to trigger some provider specific function
+ WebsocketInstructionProviderSpecific websocketInstruction = 3
)
type websocketMessage struct {
diff --git a/internal/outpost/ldap/constants/constants.go b/internal/outpost/ldap/constants/constants.go
index cfa85711e..a60db0e9f 100644
--- a/internal/outpost/ldap/constants/constants.go
+++ b/internal/outpost/ldap/constants/constants.go
@@ -25,6 +25,7 @@ const (
)
const (
+ OCPerson = "person"
OCUser = "user"
OCOrgPerson = "organizationalPerson"
OCInetOrgPerson = "inetOrgPerson"
@@ -54,6 +55,8 @@ func GetContainerOCs() map[string]bool {
func GetUserOCs() map[string]bool {
return map[string]bool{
+ OCTop: true,
+ OCPerson: true,
OCUser: true,
OCOrgPerson: true,
OCInetOrgPerson: true,
diff --git a/internal/outpost/ldap/entries.go b/internal/outpost/ldap/entries.go
index 23bab252d..2236a9964 100644
--- a/internal/outpost/ldap/entries.go
+++ b/internal/outpost/ldap/entries.go
@@ -31,8 +31,8 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry {
u.Email = api.PtrString("")
}
attrs = utils.EnsureAttributes(attrs, map[string][]string{
- "ak-active": {strconv.FormatBool(*u.IsActive)},
- "ak-superuser": {strconv.FormatBool(u.IsSuperuser)},
+ "ak-active": {strings.ToUpper(strconv.FormatBool(*u.IsActive))},
+ "ak-superuser": {strings.ToUpper(strconv.FormatBool(u.IsSuperuser))},
"memberOf": pi.GroupsForUser(u),
"cn": {u.Username},
"sAMAccountName": {u.Username},
@@ -41,11 +41,13 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry {
"displayName": {u.Name},
"mail": {*u.Email},
"objectClass": {
- constants.OCUser,
+ constants.OCTop,
+ constants.OCPerson,
constants.OCOrgPerson,
constants.OCInetOrgPerson,
- constants.OCAKUser,
+ constants.OCUser,
constants.OCPosixAccount,
+ constants.OCAKUser,
},
"uidNumber": {pi.GetUidNumber(u)},
"gidNumber": {pi.GetUidNumber(u)},
diff --git a/internal/outpost/ldap/search/direct/base.go b/internal/outpost/ldap/search/direct/base.go
index 87eadd715..0f87b7bf3 100644
--- a/internal/outpost/ldap/search/direct/base.go
+++ b/internal/outpost/ldap/search/direct/base.go
@@ -33,6 +33,29 @@ func (ds *DirectSearcher) SearchBase(req *search.Request) (ldap.ServerSearchResu
Name: "supportedLDAPVersion",
Values: []string{"3"},
},
+ {
+ Name: "supportedCapabilities",
+ Values: []string{
+ "1.2.840.113556.1.4.800", //LDAP_CAP_ACTIVE_DIRECTORY_OID
+ "1.2.840.113556.1.4.1791", //LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID
+ "1.2.840.113556.1.4.1670", //LDAP_CAP_ACTIVE_DIRECTORY_V51_OID
+ "1.2.840.113556.1.4.1880", //LDAP_CAP_ACTIVE_DIRECTORY_ADAM_DIGEST_OID
+ "1.2.840.113556.1.4.1851", //LDAP_CAP_ACTIVE_DIRECTORY_ADAM_OID
+ "1.2.840.113556.1.4.1920", //LDAP_CAP_ACTIVE_DIRECTORY_PARTIAL_SECRETS_OID
+ "1.2.840.113556.1.4.1935", //LDAP_CAP_ACTIVE_DIRECTORY_V60_OID
+ "1.2.840.113556.1.4.2080", //LDAP_CAP_ACTIVE_DIRECTORY_V61_R2_OID
+ "1.2.840.113556.1.4.2237", //LDAP_CAP_ACTIVE_DIRECTORY_W8_OID
+ },
+ },
+ {
+ Name: "supportedControl",
+ Values: []string{
+ "2.16.840.1.113730.3.4.9", //VLV Request LDAPv3 Control
+ "2.16.840.1.113730.3.4.10", //VLV Response LDAPv3 Control
+ "1.2.840.113556.1.4.474", //Sort result
+ "1.2.840.113556.1.4.319", //Paged Result Control
+ },
+ },
{
Name: "subschemaSubentry",
Values: []string{"cn=subschema"},
diff --git a/internal/outpost/ldap/search/direct/schema.go b/internal/outpost/ldap/search/direct/schema.go
index 81e601846..6fe88ead7 100644
--- a/internal/outpost/ldap/search/direct/schema.go
+++ b/internal/outpost/ldap/search/direct/schema.go
@@ -29,62 +29,80 @@ func (ds *DirectSearcher) SearchSubschema(req *search.Request) (ldap.ServerSearc
},
},
{
- Name: "objectClasses",
+ Name: "dITContentRules",
Values: []string{
- "( 2.5.6.0 NAME 'top' ABSTRACT MUST ( objectClass ) MAY (cn $ description $ displayName $ memberOf $ name ) )",
- "( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( cn ) MAY (sn $ telephoneNumber ) )",
- "( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL MAY (c $ l $ o $ ou $ title $ givenName $ co $ department $ company $ division $ mail $ mobile $ telephoneNumber ) )",
- "( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL MUST (cn $ member ) MAY (o $ ou ) )",
- "( 1.2.840.113556.1.5.9 NAME 'user' SUP organizationalPerson STRUCTURAL MAY ( name $ displayName $ uid $ mail ) )",
- "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY MAY (cn $ description $ homeDirectory $ uid $ uidNumber $ gidNumber ) )",
- "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' AUX ( posixAccount ) MUST ( sAMAccountName ) MAY ( uidNumber $ gidNumber ))",
- // Custom attributes
- // Temporarily use 1.3.6.1.4.1.26027.1.1 as a base
- // https://docs.oracle.com/cd/E19450-01/820-6169/working-with-object-identifiers.html#obtaining-a-base-oid
- "( 1.3.6.1.4.1.26027.1.1.1 NAME 'goauthentik.io/ldap/user' SUP organizationalPerson STRUCTURAL MAY ( ak-active $ sAMAccountName $ goauthentikio-user-sources $ goauthentik.io/user/sources $ goauthentik.io/ldap/active $ goauthentik.io/ldap/superuser ) )",
+ "( 2.5.6.0 NAME 'top' )",
+ "( 2.5.6.6 NAME 'person' )",
+ "( 2.5.6.7 NAME 'organizationalPerson' )",
+ "( 2.5.6.9 NAME 'groupOfNames' )",
+ "( 1.2.840.113556.1.5.9 NAME 'user' )",
+ "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' )",
+ "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' )",
+ "( 1.3.6.1.4.1.26027.1.1.1 NAME 'goauthentik.io/ldap/user' )",
},
},
{
Name: "attributeTypes",
Values: []string{
- "( 2.5.4.0 NAME 'objectClass' DESC 'RFC4512: object classes of the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
- "( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts' DESC 'RFC4512: naming contexts' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )",
- "( 2.5.18.10 NAME 'subschemaSubentry' DESC 'RFC4512: name of controlling subschema entry' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
- "( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion' DESC 'RFC4512: supported LDAP versions' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )",
- "( 1.3.6.1.1.20 NAME 'entryDN' DESC 'DN of the entry' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
- "( 1.3.6.1.1.4 NAME 'vendorName' DESC 'RFC3045: name of implementation vendor' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
- "( 1.3.6.1.1.5 NAME 'vendorVersion' DESC 'RFC3045: version of implementation' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
- "( 0.9.2342.19200300.100.1.1 NAME 'uid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 0.9.2342.19200300.100.1.3 NAME 'mail' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 0.9.2342.19200300.100.1.41 NAME 'mobile' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.2.102 NAME 'memberOf' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' NO-USER-MODIFICATION )",
- "( 1.2.840.113556.1.2.13 NAME 'displayName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.4.1 NAME 'name' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE NO-USER-MODIFICATION )",
- "( 1.2.840.113556.1.2.131 NAME 'co' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.2.141 NAME 'department' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.2.146 NAME 'company' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.4.44 NAME 'homeDirectory' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.4.221 NAME 'sAMAccountName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.2.840.113556.1.4.261 NAME 'division' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 1.3.6.1.1.1.1.0 NAME 'uidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )",
- "( 1.3.6.1.1.1.1.1 NAME 'gidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )",
+ "( 2.5.4.0 NAME 'objectClass' SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' NO-USER-MODIFICATION )",
+ "( 2.5.4.4 NAME 'sn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 2.5.4.3 NAME 'cn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
"( 2.5.4.6 NAME 'c' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
"( 2.5.4.7 NAME 'l' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
"( 2.5.4.10 NAME 'o' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )",
"( 2.5.4.11 NAME 'ou' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )",
- "( 2.5.4.20 NAME 'telephoneNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 2.5.4.42 NAME 'givenName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 2.5.4.0 NAME 'objectClass' SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' NO-USER-MODIFICATION )",
- "( 2.5.4.3 NAME 'cn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
- "( 2.5.4.4 NAME 'sn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
"( 2.5.4.12 NAME 'title' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
"( 2.5.4.13 NAME 'description' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )",
+ "( 2.5.4.20 NAME 'telephoneNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
"( 2.5.4.31 NAME 'member' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' )",
+ "( 2.5.4.42 NAME 'givenName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 2.5.21.2 NAME 'dITContentRules' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )",
+ "( 2.5.21.5 NAME 'attributeTypes' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )",
+ "( 2.5.21.6 NAME 'objectClasses' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )",
+ "( 0.9.2342.19200300.100.1.1 NAME 'uid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 0.9.2342.19200300.100.1.3 NAME 'mail' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 0.9.2342.19200300.100.1.41 NAME 'mobile' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.2.13 NAME 'displayName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.2.146 NAME 'company' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.2.102 NAME 'memberOf' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' NO-USER-MODIFICATION )",
+ "( 1.2.840.113556.1.2.131 NAME 'co' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.2.141 NAME 'department' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.4.1 NAME 'name' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE NO-USER-MODIFICATION )",
+ "( 1.2.840.113556.1.4.44 NAME 'homeDirectory' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.4.221 NAME 'sAMAccountName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.4.261 NAME 'division' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.4.750 NAME 'groupType' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )",
+ "( 1.2.840.113556.1.4.782 NAME 'objectCategory' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' SINGLE-VALUE )",
+ "( 1.3.6.1.1.1.1.0 NAME 'uidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )",
+ "( 1.3.6.1.1.1.1.1 NAME 'gidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )",
+ "( 1.3.6.1.1.1.1.12 NAME 'memberUid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.26' )",
+
// Custom attributes
// Temporarily use 1.3.6.1.4.1.26027.1.1 as a base
// https://docs.oracle.com/cd/E19450-01/820-6169/working-with-object-identifiers.html#obtaining-a-base-oid
"( 1.3.6.1.4.1.26027.1.1.2 NAME ( 'goauthentik.io/ldap/superuser' 'ak-superuser' ) SYNTAX '1.3.6.1.4.1.1466.115.121.1.7' SINGLE-VALUE )",
"( 1.3.6.1.4.1.26027.1.1.3 NAME ( 'goauthentik.io/ldap/active' 'ak-active' ) SYNTAX '1.3.6.1.4.1.1466.115.121.1.7' SINGLE-VALUE )",
+ "( 1.3.6.1.4.1.26027.1.1.4 NAME ( 'goauthentik.io/ldap/sources' 'goauthentikio-user-sources' ) SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
+ },
+ },
+ {
+ Name: "objectClasses",
+ Values: []string{
+ "( 2.5.6.0 NAME 'top' ABSTRACT MUST ( objectClass ) MAY ( objectCategory $ cn $ description $ displayName $ memberOf $ name ) )",
+ "( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( cn ) MAY ( sn $ telephoneNumber ) )",
+ "( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL MAY ( c $ l $ o $ ou $ title $ givenName $ co $ department $ company $ division $ mail $ mobile $ telephoneNumber ) )",
+ "( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL MUST ( cn $ member ) MAY ( o $ ou ) )",
+ "( 1.2.840.113556.1.5.9 NAME 'user' SUP organizationalPerson STRUCTURAL MAY ( name $ displayName $ uid $ mail ) )",
+ "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY MAY ( cn $ description $ homeDirectory $ uid $ uidNumber $ gidNumber ) )",
+ "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' SUP user STRUCTURAL MAY ( uidNumber $ gidNumber $ displayName $ homeDirectory ) )",
+ "( 2.5.6.5 NAME 'organizationalUnit' SUP top STRUCTURAL MUST ( ou ) MAY ( c $ l ) )",
+ "( 1.2.840.113556.1.5.8 NAME 'group' SUP top AUXILIARY MAY ( cn $ groupType $ member ) )",
+ "( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top AUXILIARY MAY ( cn $ description $ gidNumber $ memberUid ) )",
+ "( 2.5.20.1 NAME 'subSchema' SUP top STRUCTURAL MAY ( dITContentRules $ attributeTypes $ objectClasses ) )",
+ // Custom attributes
+ // Temporarily use 1.3.6.1.4.1.26027.1.1 as a base
+ // https://docs.oracle.com/cd/E19450-01/820-6169/working-with-object-identifiers.html#obtaining-a-base-oid
+ "( 1.3.6.1.4.1.26027.1.1.1 NAME 'goauthentik.io/ldap/user' SUP organizationalPerson STRUCTURAL MAY ( ak-superuser $ ak-active $ sAMAccountName $ goauthentikio-user-sources $ goauthentik.io/user/sources $ goauthentik.io/ldap/active $ goauthentik.io/ldap/superuser ) )",
},
},
},
diff --git a/internal/outpost/proxyv2/application/application.go b/internal/outpost/proxyv2/application/application.go
index 657bcbec7..eae4c6774 100644
--- a/internal/outpost/proxyv2/application/application.go
+++ b/internal/outpost/proxyv2/application/application.go
@@ -280,7 +280,9 @@ func (a *Application) handleSignOut(rw http.ResponseWriter, r *http.Request) {
"id_token_hint": []string{cc.RawToken},
}
redirect += "?" + uv.Encode()
- err = a.Logout(r.Context(), cc.Sub)
+ err = a.Logout(r.Context(), func(c Claims) bool {
+ return c.Sub == cc.Sub
+ })
if err != nil {
a.log.WithError(err).Warning("failed to logout of other sessions")
}
diff --git a/internal/outpost/proxyv2/application/claims.go b/internal/outpost/proxyv2/application/claims.go
index bd34e1309..32f4d26eb 100644
--- a/internal/outpost/proxyv2/application/claims.go
+++ b/internal/outpost/proxyv2/application/claims.go
@@ -11,10 +11,11 @@ type Claims struct {
Exp int `json:"exp"`
Email string `json:"email"`
Verified bool `json:"email_verified"`
- Proxy *ProxyClaims `json:"ak_proxy"`
Name string `json:"name"`
PreferredUsername string `json:"preferred_username"`
Groups []string `json:"groups"`
+ Sid string `json:"sid"`
+ Proxy *ProxyClaims `json:"ak_proxy"`
RawToken string
}
diff --git a/internal/outpost/proxyv2/application/session.go b/internal/outpost/proxyv2/application/session.go
index 739b23e84..55d2bbb46 100644
--- a/internal/outpost/proxyv2/application/session.go
+++ b/internal/outpost/proxyv2/application/session.go
@@ -88,7 +88,7 @@ func (a *Application) getAllCodecs() []securecookie.Codec {
return cs
}
-func (a *Application) Logout(ctx context.Context, sub string) error {
+func (a *Application) Logout(ctx context.Context, filter func(c Claims) bool) error {
if _, ok := a.sessions.(*sessions.FilesystemStore); ok {
files, err := os.ReadDir(os.TempDir())
if err != nil {
@@ -118,7 +118,7 @@ func (a *Application) Logout(ctx context.Context, sub string) error {
continue
}
claims := s.Values[constants.SessionClaims].(Claims)
- if claims.Sub == sub {
+ if filter(claims) {
a.log.WithField("path", fullPath).Trace("deleting session")
err := os.Remove(fullPath)
if err != nil {
@@ -153,7 +153,7 @@ func (a *Application) Logout(ctx context.Context, sub string) error {
continue
}
claims := c.(Claims)
- if claims.Sub == sub {
+ if filter(claims) {
a.log.WithField("key", key).Trace("deleting session")
_, err := client.Del(ctx, key).Result()
if err != nil {
diff --git a/internal/outpost/proxyv2/proxyv2.go b/internal/outpost/proxyv2/proxyv2.go
index 154f79e34..70364957f 100644
--- a/internal/outpost/proxyv2/proxyv2.go
+++ b/internal/outpost/proxyv2/proxyv2.go
@@ -65,6 +65,7 @@ func NewProxyServer(ac *ak.APIController) *ProxyServer {
globalMux.PathPrefix("/outpost.goauthentik.io/static").HandlerFunc(s.HandleStatic)
globalMux.Path("/outpost.goauthentik.io/ping").HandlerFunc(sentryutils.SentryNoSample(s.HandlePing))
rootMux.PathPrefix("/").HandlerFunc(s.Handle)
+ ac.AddWSHandler(s.handleWSMessage)
return s
}
diff --git a/internal/outpost/proxyv2/ws.go b/internal/outpost/proxyv2/ws.go
new file mode 100644
index 000000000..b75ba50fd
--- /dev/null
+++ b/internal/outpost/proxyv2/ws.go
@@ -0,0 +1,49 @@
+package proxyv2
+
+import (
+ "context"
+
+ "github.com/mitchellh/mapstructure"
+ "goauthentik.io/internal/outpost/proxyv2/application"
+)
+
+type WSProviderSubType string
+
+const (
+ WSProviderSubTypeLogout WSProviderSubType = "logout"
+)
+
+type WSProviderMsg struct {
+ SubType WSProviderSubType `mapstructure:"sub_type"`
+ SessionID string `mapstructure:"session_id"`
+}
+
+func ParseWSProvider(args map[string]interface{}) (*WSProviderMsg, error) {
+ msg := &WSProviderMsg{}
+ err := mapstructure.Decode(args, &msg)
+ if err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+
+func (ps *ProxyServer) handleWSMessage(ctx context.Context, args map[string]interface{}) {
+ msg, err := ParseWSProvider(args)
+ if err != nil {
+ ps.log.WithError(err).Warning("invalid provider-specific ws message")
+ return
+ }
+ switch msg.SubType {
+ case WSProviderSubTypeLogout:
+ for _, p := range ps.apps {
+ err := p.Logout(ctx, func(c application.Claims) bool {
+ return c.Sid == msg.SessionID
+ })
+ if err != nil {
+ ps.log.WithField("provider", p.Host).WithError(err).Warning("failed to logout")
+ }
+ }
+ default:
+ ps.log.WithField("sub_type", msg.SubType).Warning("invalid sub_type")
+ }
+}
diff --git a/ldap.Dockerfile b/ldap.Dockerfile
index 576a840ea..c43a2a77c 100644
--- a/ldap.Dockerfile
+++ b/ldap.Dockerfile
@@ -1,5 +1,5 @@
# Stage 1: Build
-FROM docker.io/golang:1.21.1-bookworm AS builder
+FROM docker.io/golang:1.21.2-bookworm AS builder
WORKDIR /go/src/goauthentik.io
diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py
index 8eee74adb..68d45dbc3 100755
--- a/lifecycle/migrate.py
+++ b/lifecycle/migrate.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python
"""System Migration handler"""
-import os
from importlib.util import module_from_spec, spec_from_file_location
from inspect import getmembers, isclass
+from os import environ, system
from pathlib import Path
from typing import Any
-from psycopg import connect
+from psycopg import Connection, Cursor, connect
from structlog.stdlib import get_logger
from authentik.lib.config import CONFIG
@@ -16,16 +16,33 @@ ADV_LOCK_UID = 1000
LOCKED = False
+class CommandError(Exception):
+ """Error raised when a system_crit command fails"""
+
+
class BaseMigration:
"""Base System Migration"""
- cur: Any
- con: Any
+ cur: Cursor
+ con: Connection
def __init__(self, cur: Any, con: Any):
self.cur = cur
self.con = con
+ def system_crit(self, command: str):
+ """Run system command"""
+ LOGGER.debug("Running system_crit command", command=command)
+ retval = system(command) # nosec
+ if retval != 0:
+ raise CommandError("Migration error")
+
+ def fake_migration(self, *app_migration: tuple[str, str]):
+ """Fake apply a list of migrations, arguments are
+ expected to be tuples of (app_label, migration_name)"""
+ for app, _migration in app_migration:
+ self.system_crit(f"./manage.py migrate {app} {_migration} --fake")
+
def needs_migration(self) -> bool:
"""Return true if Migration needs to be run"""
return False
@@ -82,7 +99,7 @@ if __name__ == "__main__":
LOGGER.info("Migration finished applying", migration=sub)
release_lock()
LOGGER.info("applying django migrations")
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
+ environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
wait_for_lock()
try:
from django.core.management import execute_from_command_line
diff --git a/lifecycle/system_migrations/install_id.py b/lifecycle/system_migrations/install_id.py
index 28867d8fa..2f66dcafc 100644
--- a/lifecycle/system_migrations/install_id.py
+++ b/lifecycle/system_migrations/install_id.py
@@ -20,18 +20,17 @@ class Migration(BaseMigration):
def upgrade(self, migrate=False):
self.cur.execute(SQL_STATEMENT)
- self.con.commit()
- if migrate:
- # If we already have migrations in the database, assume we're upgrading an existing install
- # and set the install id to the secret key
- self.cur.execute(
- "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),)
- )
- else:
- # Otherwise assume a new install, generate an install ID based on a UUID
- install_id = str(uuid4())
- self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,))
- self.con.commit()
+ with self.con.transaction():
+ if migrate:
+ # If we already have migrations in the database, assume we're upgrading an existing install
+ # and set the install id to the secret key
+ self.cur.execute(
+ "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),)
+ )
+ else:
+ # Otherwise assume a new install, generate an install ID based on a UUID
+ install_id = str(uuid4())
+ self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,))
def run(self):
self.cur.execute(
diff --git a/lifecycle/system_migrations/otp_merge.py b/lifecycle/system_migrations/otp_merge.py
index c3908bffa..7561f0df7 100644
--- a/lifecycle/system_migrations/otp_merge.py
+++ b/lifecycle/system_migrations/otp_merge.py
@@ -1,10 +1,7 @@
# flake8: noqa
-from os import system
-
from lifecycle.migrate import BaseMigration
SQL_STATEMENT = """
-BEGIN TRANSACTION;
DELETE FROM django_migrations WHERE app = 'otp_static';
DELETE FROM django_migrations WHERE app = 'otp_totp';
-- Rename tables (static)
@@ -15,7 +12,7 @@ ALTER SEQUENCE otp_static_staticdevice_id_seq RENAME TO authentik_stages_authent
-- Rename tables (totp)
ALTER TABLE otp_totp_totpdevice RENAME TO authentik_stages_authenticator_totp_totpdevice;
ALTER SEQUENCE otp_totp_totpdevice_id_seq RENAME TO authentik_stages_authenticator_totp_totpdevice_id_seq;
-COMMIT;"""
+"""
class Migration(BaseMigration):
@@ -25,23 +22,24 @@ class Migration(BaseMigration):
)
return bool(self.cur.rowcount)
- def system_crit(self, command):
- retval = system(command) # nosec
- if retval != 0:
- raise Exception("Migration error")
-
def run(self):
- self.cur.execute(SQL_STATEMENT)
- self.con.commit()
- self.system_crit(
- "./manage.py migrate authentik_stages_authenticator_static 0008_initial --fake"
- )
- self.system_crit(
- "./manage.py migrate authentik_stages_authenticator_static 0009_throttling --fake"
- )
- self.system_crit(
- "./manage.py migrate authentik_stages_authenticator_totp 0008_initial --fake"
- )
- self.system_crit(
- "./manage.py migrate authentik_stages_authenticator_totp 0009_auto_20190420_0723 --fake"
- )
+ with self.con.transaction():
+ self.cur.execute(SQL_STATEMENT)
+ self.fake_migration(
+ (
+ "authentik_stages_authenticator_static",
+ "0008_initial",
+ ),
+ (
+ "authentik_stages_authenticator_static",
+ "0009_throttling",
+ ),
+ (
+ "authentik_stages_authenticator_totp",
+ "0008_initial",
+ ),
+ (
+ "authentik_stages_authenticator_totp",
+ "0009_auto_20190420_0723",
+ ),
+ )
diff --git a/lifecycle/system_migrations/to_0_10.py b/lifecycle/system_migrations/to_0_10.py
index 77ff3f69c..84ab45b39 100644
--- a/lifecycle/system_migrations/to_0_10.py
+++ b/lifecycle/system_migrations/to_0_10.py
@@ -1,10 +1,7 @@
# flake8: noqa
-from os import system
-
from lifecycle.migrate import BaseMigration
SQL_STATEMENT = """
-BEGIN TRANSACTION;
DELETE FROM django_migrations WHERE app = 'passbook_stages_prompt';
DROP TABLE passbook_stages_prompt_prompt cascade;
DROP TABLE passbook_stages_prompt_promptstage cascade;
@@ -25,7 +22,7 @@ DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0008_defa
DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0009_source_flows';
DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0010_provider_flows';
DELETE FROM django_migrations WHERE app = 'passbook_stages_password' AND name = '0002_passwordstage_change_flow';
-COMMIT;"""
+"""
class Migration(BaseMigration):
@@ -35,17 +32,14 @@ class Migration(BaseMigration):
)
return bool(self.cur.rowcount)
- def system_crit(self, command):
- retval = system(command) # nosec
- if retval != 0:
- raise Exception("Migration error")
-
def run(self):
- self.cur.execute(SQL_STATEMENT)
- self.con.commit()
- self.system_crit("./manage.py migrate passbook_stages_prompt")
- self.system_crit("./manage.py migrate passbook_flows 0008_default_flows --fake")
- self.system_crit("./manage.py migrate passbook_flows 0009_source_flows --fake")
- self.system_crit("./manage.py migrate passbook_flows 0010_provider_flows --fake")
- self.system_crit("./manage.py migrate passbook_flows")
- self.system_crit("./manage.py migrate passbook_stages_password --fake")
+ with self.con.transaction():
+ self.cur.execute(SQL_STATEMENT)
+ self.system_crit("./manage.py migrate passbook_stages_prompt")
+ self.fake_migration(
+ ("passbook_flows", "0008_default_flows"),
+ ("passbook_flows", "0009_source_flows"),
+ ("passbook_flows", "0010_provider_flows"),
+ )
+ self.system_crit("./manage.py migrate passbook_flows")
+ self.fake_migration(("passbook_stages_password", ""))
diff --git a/lifecycle/system_migrations/to_0_13_authentik.py b/lifecycle/system_migrations/to_0_13_authentik.py
index ff2088349..8ba702132 100644
--- a/lifecycle/system_migrations/to_0_13_authentik.py
+++ b/lifecycle/system_migrations/to_0_13_authentik.py
@@ -4,7 +4,7 @@ from redis import Redis
from authentik.lib.config import CONFIG
from lifecycle.migrate import BaseMigration
-SQL_STATEMENT = """BEGIN TRANSACTION;
+SQL_STATEMENT = """
ALTER TABLE passbook_audit_event RENAME TO authentik_audit_event;
ALTER TABLE passbook_core_application RENAME TO authentik_core_application;
ALTER TABLE passbook_core_group RENAME TO authentik_core_group;
@@ -92,8 +92,7 @@ ALTER SEQUENCE passbook_stages_prompt_promptstage_validation_policies_id_seq REN
UPDATE django_migrations SET app = replace(app, 'passbook', 'authentik');
UPDATE django_content_type SET app_label = replace(app_label, 'passbook', 'authentik');
-
-END TRANSACTION;"""
+"""
class Migration(BaseMigration):
@@ -104,18 +103,18 @@ class Migration(BaseMigration):
return bool(self.cur.rowcount)
def run(self):
- self.cur.execute(SQL_STATEMENT)
- self.con.commit()
- # We also need to clean the cache to make sure no pickeled objects still exist
- for db in [
- CONFIG.get("redis.message_queue_db"),
- CONFIG.get("redis.cache_db"),
- CONFIG.get("redis.ws_db"),
- ]:
- redis = Redis(
- host=CONFIG.get("redis.host"),
- port=6379,
- db=db,
- password=CONFIG.get("redis.password"),
- )
- redis.flushall()
+ with self.con.transaction():
+ self.cur.execute(SQL_STATEMENT)
+ # We also need to clean the cache to make sure no pickeled objects still exist
+ for db in [
+ CONFIG.get("redis.message_queue_db"),
+ CONFIG.get("redis.cache_db"),
+ CONFIG.get("redis.ws_db"),
+ ]:
+ redis = Redis(
+ host=CONFIG.get("redis.host"),
+ port=6379,
+ db=db,
+ password=CONFIG.get("redis.password"),
+ )
+ redis.flushall()
diff --git a/lifecycle/system_migrations/to_0_14_events..py b/lifecycle/system_migrations/to_0_14_events..py
index 4745b8853..b1a0cc727 100644
--- a/lifecycle/system_migrations/to_0_14_events..py
+++ b/lifecycle/system_migrations/to_0_14_events..py
@@ -1,12 +1,9 @@
# flake8: noqa
from lifecycle.migrate import BaseMigration
-SQL_STATEMENT = """BEGIN TRANSACTION;
-ALTER TABLE authentik_audit_event RENAME TO authentik_events_event;
+SQL_STATEMENT = """ALTER TABLE authentik_audit_event RENAME TO authentik_events_event;
UPDATE django_migrations SET app = replace(app, 'authentik_audit', 'authentik_events');
-UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events');
-
-END TRANSACTION;"""
+UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events');"""
class Migration(BaseMigration):
@@ -17,5 +14,5 @@ class Migration(BaseMigration):
return bool(self.cur.rowcount)
def run(self):
- self.cur.execute(SQL_STATEMENT)
- self.con.commit()
+ with self.con.transaction():
+ self.cur.execute(SQL_STATEMENT)
diff --git a/lifecycle/system_migrations/to_2021_3_authenticator.py b/lifecycle/system_migrations/to_2021_3_authenticator.py
index 3dd895bdb..3b633fef1 100644
--- a/lifecycle/system_migrations/to_2021_3_authenticator.py
+++ b/lifecycle/system_migrations/to_2021_3_authenticator.py
@@ -1,7 +1,7 @@
# flake8: noqa
from lifecycle.migrate import BaseMigration
-SQL_STATEMENT = """BEGIN TRANSACTION;
+SQL_STATEMENT = """
ALTER TABLE authentik_stages_otp_static_otpstaticstage RENAME TO authentik_stages_authenticator_static_otpstaticstage;
UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static');
UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static');
@@ -13,8 +13,7 @@ UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_
ALTER TABLE authentik_stages_otp_validate_otpvalidatestage RENAME TO authentik_stages_authenticator_validate_otpvalidatestage;
UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate');
UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate');
-
-END TRANSACTION;"""
+"""
class Migration(BaseMigration):
@@ -26,5 +25,5 @@ class Migration(BaseMigration):
return bool(self.cur.rowcount)
def run(self):
- self.cur.execute(SQL_STATEMENT)
- self.con.commit()
+ with self.con.transaction():
+ self.cur.execute(SQL_STATEMENT)
diff --git a/lifecycle/system_migrations/to_2023_1_hibp_remove.py b/lifecycle/system_migrations/to_2023_1_hibp_remove.py
index 4c8b9e292..c43f6bb85 100644
--- a/lifecycle/system_migrations/to_2023_1_hibp_remove.py
+++ b/lifecycle/system_migrations/to_2023_1_hibp_remove.py
@@ -1,10 +1,8 @@
# flake8: noqa
from lifecycle.migrate import BaseMigration
-SQL_STATEMENT = """BEGIN TRANSACTION;
-DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy";
-DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp';
-END TRANSACTION;"""
+SQL_STATEMENT = """DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy";
+DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp';"""
class Migration(BaseMigration):
@@ -16,5 +14,5 @@ class Migration(BaseMigration):
return bool(self.cur.rowcount)
def run(self):
- self.cur.execute(SQL_STATEMENT)
- self.con.commit()
+ with self.con.transaction():
+ self.cur.execute(SQL_STATEMENT)
diff --git a/poetry.lock b/poetry.lock
index eabcf4729..78d92b40f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -3723,20 +3723,19 @@ wsproto = ">=0.14"
[[package]]
name = "twilio"
-version = "8.9.0"
+version = "8.9.1"
description = "Twilio API client and TwiML generator"
optional = false
python-versions = ">=3.7.0"
files = [
- {file = "twilio-8.9.0-py2.py3-none-any.whl", hash = "sha256:d2f71060575432f73ed73f7cfc33259c53c96b92aa969d2910dacc8da1d1a5d9"},
- {file = "twilio-8.9.0.tar.gz", hash = "sha256:e711b5ea89694cb58a55a6b69f6190ea4c8499a1d6d68eb6a03c9840bb78fbb3"},
+ {file = "twilio-8.9.1-py2.py3-none-any.whl", hash = "sha256:3edc0bcde7320b5ae5f516484af9092bc4df2f5a3b1d4d94a66c29310adb924c"},
+ {file = "twilio-8.9.1.tar.gz", hash = "sha256:7bca5dc476d4d15e89e41d3074f8a265bd61445d1de9e8a697ca96cd8399eda6"},
]
[package.dependencies]
aiohttp = ">=3.8.4"
aiohttp-retry = ">=2.8.3"
PyJWT = ">=2.0.0,<3.0.0"
-pytz = "*"
requests = ">=2.0.0"
[[package]]
diff --git a/proxy.Dockerfile b/proxy.Dockerfile
index f6a226956..ffcde9122 100644
--- a/proxy.Dockerfile
+++ b/proxy.Dockerfile
@@ -15,7 +15,7 @@ COPY web .
RUN npm run build-proxy
# Stage 2: Build
-FROM docker.io/golang:1.21.1-bookworm AS builder
+FROM docker.io/golang:1.21.2-bookworm AS builder
WORKDIR /go/src/goauthentik.io
diff --git a/radius.Dockerfile b/radius.Dockerfile
index 8b6d84900..d2faf4829 100644
--- a/radius.Dockerfile
+++ b/radius.Dockerfile
@@ -1,5 +1,5 @@
# Stage 1: Build
-FROM docker.io/golang:1.21.1-bookworm AS builder
+FROM docker.io/golang:1.21.2-bookworm AS builder
WORKDIR /go/src/goauthentik.io
diff --git a/schema.yml b/schema.yml
index 5b682a7ff..03eed6d01 100644
--- a/schema.yml
+++ b/schema.yml
@@ -16292,6 +16292,10 @@ paths:
schema:
type: string
format: uuid
+ - in: query
+ name: default_relay_state
+ schema:
+ type: string
- in: query
name: digest_algorithm
schema:
@@ -36303,6 +36307,9 @@ components:
* `redirect` - Redirect
* `post` - Post
+ default_relay_state:
+ type: string
+ description: Default relay_state value for IDP-initiated logins
PatchedSAMLSourceRequest:
type: object
description: SAMLSource Serializer
@@ -38480,6 +38487,9 @@ components:
* `redirect` - Redirect
* `post` - Post
+ default_relay_state:
+ type: string
+ description: Default relay_state value for IDP-initiated logins
url_download_metadata:
type: string
description: Get metadata download URL
@@ -38624,6 +38634,9 @@ components:
* `redirect` - Redirect
* `post` - Post
+ default_relay_state:
+ type: string
+ description: Default relay_state value for IDP-initiated logins
required:
- acs_url
- authorization_flow
@@ -40142,6 +40155,10 @@ components:
type: string
type:
$ref: '#/components/schemas/UserTypeEnum'
+ uuid:
+ type: string
+ format: uuid
+ readOnly: true
required:
- avatar
- groups_obj
@@ -40150,6 +40167,7 @@ components:
- pk
- uid
- username
+ - uuid
UserAccountRequest:
type: object
description: Account adding/removing operations
diff --git a/tests/e2e/test_provider_ldap.py b/tests/e2e/test_provider_ldap.py
index 02564e4bd..aa12587ab 100644
--- a/tests/e2e/test_provider_ldap.py
+++ b/tests/e2e/test_provider_ldap.py
@@ -231,6 +231,7 @@ class TestProviderLDAP(SeleniumTestCase):
for obj in response:
del obj["raw_attributes"]
del obj["raw_dn"]
+ obj["attributes"] = dict(obj["attributes"])
o_user = outpost.user
expected = [
{
@@ -244,11 +245,13 @@ class TestProviderLDAP(SeleniumTestCase):
"sn": o_user.name,
"mail": "",
"objectClass": [
- "user",
+ "top",
+ "person",
"organizationalPerson",
"inetOrgPerson",
- "goauthentik.io/ldap/user",
+ "user",
"posixAccount",
+ "goauthentik.io/ldap/user",
],
"uidNumber": 2000 + o_user.pk,
"gidNumber": 2000 + o_user.pk,
@@ -270,11 +273,13 @@ class TestProviderLDAP(SeleniumTestCase):
"sn": embedded_account.name,
"mail": "",
"objectClass": [
- "user",
+ "top",
+ "person",
"organizationalPerson",
"inetOrgPerson",
- "goauthentik.io/ldap/user",
+ "user",
"posixAccount",
+ "goauthentik.io/ldap/user",
],
"uidNumber": 2000 + embedded_account.pk,
"gidNumber": 2000 + embedded_account.pk,
@@ -296,11 +301,13 @@ class TestProviderLDAP(SeleniumTestCase):
"sn": self.user.name,
"mail": self.user.email,
"objectClass": [
- "user",
+ "top",
+ "person",
"organizationalPerson",
"inetOrgPerson",
- "goauthentik.io/ldap/user",
+ "user",
"posixAccount",
+ "goauthentik.io/ldap/user",
],
"uidNumber": 2000 + self.user.pk,
"gidNumber": 2000 + self.user.pk,
diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json
index 78a562d24..db3b5e383 100644
--- a/tests/wdio/package-lock.json
+++ b/tests/wdio/package-lock.json
@@ -9,11 +9,11 @@
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
- "@wdio/cli": "^8.16.19",
- "@wdio/local-runner": "^8.16.19",
- "@wdio/mocha-framework": "^8.16.17",
- "@wdio/spec-reporter": "^8.16.17",
- "eslint": "^8.49.0",
+ "@wdio/cli": "^8.16.22",
+ "@wdio/local-runner": "^8.16.22",
+ "@wdio/mocha-framework": "^8.16.22",
+ "@wdio/spec-reporter": "^8.16.22",
+ "eslint": "^8.51.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-sonarjs": "^0.21.0",
"npm-run-all": "^4.1.5",
@@ -340,9 +340,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.50.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz",
- "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==",
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
+ "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -1067,18 +1067,18 @@
}
},
"node_modules/@wdio/cli": {
- "version": "8.16.19",
- "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.16.19.tgz",
- "integrity": "sha512-MGpRrb56kp0n+r/Z0KMe0o4O1dFgBhhjt/O4HC5l0WcPuf5Ew19w1Nr8PoSZ5XqXklGJi0woFh68YZA1MziInA==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.16.22.tgz",
+ "integrity": "sha512-/cv/fQ3qZoTJEnjmxWwPC2ohPfg5GrtBxi1MXNMJK85l1RHVYLkuNwUq18gSNcLol2vJ7GGoFowadlBjoCj56Q==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.1",
- "@wdio/config": "8.16.17",
- "@wdio/globals": "8.16.19",
+ "@wdio/config": "8.16.22",
+ "@wdio/globals": "8.16.22",
"@wdio/logger": "8.16.17",
"@wdio/protocols": "8.16.5",
- "@wdio/types": "8.16.12",
- "@wdio/utils": "8.16.17",
+ "@wdio/types": "8.16.22",
+ "@wdio/utils": "8.16.22",
"async-exit-hook": "^2.0.1",
"chalk": "^5.2.0",
"chokidar": "^3.5.3",
@@ -1093,7 +1093,7 @@
"lodash.union": "^4.6.0",
"read-pkg-up": "10.1.0",
"recursive-readdir": "^2.2.3",
- "webdriverio": "8.16.19",
+ "webdriverio": "8.16.22",
"yargs": "^17.7.2",
"yarn-install": "^1.0.0"
},
@@ -1117,14 +1117,14 @@
}
},
"node_modules/@wdio/config": {
- "version": "8.16.17",
- "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.17.tgz",
- "integrity": "sha512-9+AY73Dp6N/CHzUYe4KbYV8wcKh3mpzBsMKieNlwXi1bQ3AAirTjOXzQ2BoQn6fg/Yd1GxmT3F0YsVS+bF1PmQ==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.22.tgz",
+ "integrity": "sha512-sxqiVUEq++GFDKeR+HfzlgNhEbYuJZlrkU09p2rZzCRpPM3ty4azzdHB+XEdHHJJlV4UguvqUkp7n2126d9SAQ==",
"dev": true,
"dependencies": {
"@wdio/logger": "8.16.17",
- "@wdio/types": "8.16.12",
- "@wdio/utils": "8.16.17",
+ "@wdio/types": "8.16.22",
+ "@wdio/utils": "8.16.22",
"decamelize": "^6.0.0",
"deepmerge-ts": "^5.0.0",
"glob": "^10.2.2",
@@ -1136,29 +1136,29 @@
}
},
"node_modules/@wdio/globals": {
- "version": "8.16.19",
- "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.16.19.tgz",
- "integrity": "sha512-KziZCYLcEvcsESJm2STkCEUKq2rhIbAP+1lyksULUdMsLoKhqW3yPrb8g6z3qj8G7yAYF8xWpKID0yQejl3UXA==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.16.22.tgz",
+ "integrity": "sha512-YGmGboSDTnFk+Bp/FJX2oPf548YILOr6M2T+wLnZtfgEPV5X8LbhT+XMqOYOiIdnI5MfgWGn8+XIgdjtNumHwQ==",
"dev": true,
"engines": {
"node": "^16.13 || >=18"
},
"optionalDependencies": {
"expect-webdriverio": "^4.2.5",
- "webdriverio": "8.16.19"
+ "webdriverio": "8.16.22"
}
},
"node_modules/@wdio/local-runner": {
- "version": "8.16.19",
- "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.16.19.tgz",
- "integrity": "sha512-YUGF+7JCWoziFRW9/L+JSxuGKLgRiRXkRJ39iKaW97qS3MckBxLtuB4IY7gt3WJ80iDYo6IWLllRZfWtpvAT/A==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.16.22.tgz",
+ "integrity": "sha512-ZhP8lDgjYzBuopIROALMcAmjvo7KGYjk6W+eJAR2p1EgdQy8IFMIuYuK1lWhAGCN3GRMRC1CTVtEVxc79/EJMg==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.0",
"@wdio/logger": "8.16.17",
"@wdio/repl": "8.10.1",
- "@wdio/runner": "8.16.19",
- "@wdio/types": "8.16.12",
+ "@wdio/runner": "8.16.22",
+ "@wdio/types": "8.16.22",
"async-exit-hook": "^2.0.1",
"split2": "^4.1.0",
"stream-buffers": "^3.0.2"
@@ -1195,16 +1195,16 @@
}
},
"node_modules/@wdio/mocha-framework": {
- "version": "8.16.17",
- "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.16.17.tgz",
- "integrity": "sha512-aJ3CMzSBPOCb1i7hPyAsGYwccxPkD96qqdme/YUGL4U4SB+kEgDgNvouTJbyqvAB4VEuCcs+KqNWIMtM+rPi0Q==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.16.22.tgz",
+ "integrity": "sha512-/TgHCr4QoNRChGAXfBNZZHGEs+hMO2A8aU6mNEyrokAcHBoCL3NhnAP2SiQV0uT5wzoAOfv4RXqXOJ3bJa30Rw==",
"dev": true,
"dependencies": {
"@types/mocha": "^10.0.0",
"@types/node": "^20.1.0",
"@wdio/logger": "8.16.17",
- "@wdio/types": "8.16.12",
- "@wdio/utils": "8.16.17",
+ "@wdio/types": "8.16.22",
+ "@wdio/utils": "8.16.22",
"mocha": "^10.0.0"
},
"engines": {
@@ -1230,14 +1230,14 @@
}
},
"node_modules/@wdio/reporter": {
- "version": "8.16.17",
- "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.16.17.tgz",
- "integrity": "sha512-c7B4dnOhCM9qCn/0vlV0IjCTL/Dv++MNOMtZFTQlEEo5qXSX+LNkpsZi0STnkPqnv6ZP7liwz4bA01MFksGaww==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.16.22.tgz",
+ "integrity": "sha512-5f4H2bAaq+mxl51j+4pyDuhgvE5MIJOhF3G75AGCjEnXgDEHYJ+yzpvRwmLxPB98BkxZ/ldxrQth/I/l3+j1fQ==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.0",
"@wdio/logger": "8.16.17",
- "@wdio/types": "8.16.12",
+ "@wdio/types": "8.16.22",
"diff": "^5.0.0",
"object-inspect": "^1.12.0"
},
@@ -1246,35 +1246,35 @@
}
},
"node_modules/@wdio/runner": {
- "version": "8.16.19",
- "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.16.19.tgz",
- "integrity": "sha512-CzLxlxcRfIVzTKGeo+TO5rUmmWHjUUdRaM6/6UGNFhFCcYW5rLvfHd1ojpU7ZKxBIc/bz2RGw2/cQ8KgQbFR3g==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.16.22.tgz",
+ "integrity": "sha512-SgWW1GPlZ7kS/7VZuuCYmCKIF6/WlOccGS2kHAg2rM45MjUId3KegNQ+INi2S3CkgU19M0rH2nNEUozp68dddw==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.0",
- "@wdio/config": "8.16.17",
- "@wdio/globals": "8.16.19",
+ "@wdio/config": "8.16.22",
+ "@wdio/globals": "8.16.22",
"@wdio/logger": "8.16.17",
- "@wdio/types": "8.16.12",
- "@wdio/utils": "8.16.17",
+ "@wdio/types": "8.16.22",
+ "@wdio/utils": "8.16.22",
"deepmerge-ts": "^5.0.0",
"expect-webdriverio": "^4.2.5",
"gaze": "^1.1.2",
- "webdriver": "8.16.17",
- "webdriverio": "8.16.19"
+ "webdriver": "8.16.22",
+ "webdriverio": "8.16.22"
},
"engines": {
"node": "^16.13 || >=18"
}
},
"node_modules/@wdio/spec-reporter": {
- "version": "8.16.17",
- "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.16.17.tgz",
- "integrity": "sha512-CBpZhTJASDWpxJBUK5TLBZKBWbZxsVctpqXjpjG9fl9+IXBG00P5oFecDa90aUa00Dq+eIE1UUsVJa7evd36Tg==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.16.22.tgz",
+ "integrity": "sha512-bOELqVNDGRf4hxAtnYKjQiejMSKr/KNKgIwvyk6Ww2WHavzbZ/3oPRKNiyu5qgQR1lU+IN46V848EQV/RwtG+Q==",
"dev": true,
"dependencies": {
- "@wdio/reporter": "8.16.17",
- "@wdio/types": "8.16.12",
+ "@wdio/reporter": "8.16.22",
+ "@wdio/types": "8.16.22",
"chalk": "^5.1.2",
"easy-table": "^1.2.0",
"pretty-ms": "^7.0.0"
@@ -1296,9 +1296,9 @@
}
},
"node_modules/@wdio/types": {
- "version": "8.16.12",
- "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.12.tgz",
- "integrity": "sha512-TjCZJ3P9ual21G0dRv0lC9QgHGd3Igv+guEINevBKf/oD4/N84PvQ2eZG1nSbZ3xh8X/dvi+O64A6VEv43gx2w==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.22.tgz",
+ "integrity": "sha512-bg30seCgYu5JXukJ7M0qWKZLNATpKROvnl5/lRSOu4oopjm28UUan/+gHfHfyJ3MJ2uFNhaIVotPAvUziVJAdg==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.0"
@@ -1308,14 +1308,14 @@
}
},
"node_modules/@wdio/utils": {
- "version": "8.16.17",
- "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.17.tgz",
- "integrity": "sha512-jDyOrxbQRDJO0OPt9UBgnwpUIKqtRn4+R0gR5VSDrIG/in5ZZg28yer8urrIVY4yY9ut5r/22VaMHZI9LEXF5w==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.22.tgz",
+ "integrity": "sha512-1hQjm7Jweiz+ABakS33TyWXYoxEg7LxL12RqbEYqtGB6ZTJhik+Cwyj/jcJbETSjiYJflmHxDvhFwuOkLR8ljg==",
"dev": true,
"dependencies": {
"@puppeteer/browsers": "^1.6.0",
"@wdio/logger": "8.16.17",
- "@wdio/types": "8.16.12",
+ "@wdio/types": "8.16.22",
"decamelize": "^6.0.0",
"deepmerge-ts": "^5.1.0",
"edgedriver": "^5.3.5",
@@ -2595,11 +2595,10 @@
}
},
"node_modules/devtools-protocol": {
- "version": "0.0.1188743",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1188743.tgz",
- "integrity": "sha512-FZDQC58vLiGR2mjSgsMzU8aEJieovMonIyxf38b775eYdIfAYgSzyAWnDf0Eq6ouF/L9qcbqR8jcQeIC34jp/w==",
- "dev": true,
- "peer": true
+ "version": "0.0.1203626",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz",
+ "integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==",
+ "dev": true
},
"node_modules/diff": {
"version": "5.1.0",
@@ -2946,15 +2945,15 @@
}
},
"node_modules/eslint": {
- "version": "8.50.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz",
- "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==",
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
+ "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "8.50.0",
+ "@eslint/js": "8.51.0",
"@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -8694,18 +8693,18 @@
}
},
"node_modules/webdriver": {
- "version": "8.16.17",
- "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.17.tgz",
- "integrity": "sha512-pG5aEqK6odI9Tr9pr0+1mN6iGqUu5uc5HTVbqbEM6CSX2g035JRVQ/tavFTegCF1HI6yIquHiwAqsfPgLciAnQ==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.22.tgz",
+ "integrity": "sha512-7W3LwQ5Np/qQG/EHD02aujv4QBuiE3/PbDd576s4QRDVa5RHLTvuAg3sZpj5kJ4wZEK2MbPsj1Nb8xqSyCUUqw==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.0",
"@types/ws": "^8.5.3",
- "@wdio/config": "8.16.17",
+ "@wdio/config": "8.16.22",
"@wdio/logger": "8.16.17",
"@wdio/protocols": "8.16.5",
- "@wdio/types": "8.16.12",
- "@wdio/utils": "8.16.17",
+ "@wdio/types": "8.16.22",
+ "@wdio/utils": "8.16.22",
"deepmerge-ts": "^5.1.0",
"got": "^ 12.6.1",
"ky": "^0.33.0",
@@ -8753,18 +8752,18 @@
}
},
"node_modules/webdriverio": {
- "version": "8.16.19",
- "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.19.tgz",
- "integrity": "sha512-b63vRWWuLq7OKYTLMdCn+uvTW48sMFepEyrv8MKFJproaSOCcokw7sqJ/EcQFmqIgrZxKL/mDch+QKjxlW0ORw==",
+ "version": "8.16.22",
+ "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.22.tgz",
+ "integrity": "sha512-fzZtONvimqYc+C7DnnntkOz883+VP50uIvofLkDdH5yXU6duyclclChwWNZWllEHZvkLfpmLgrpgbS7R1wNGQg==",
"dev": true,
"dependencies": {
"@types/node": "^20.1.0",
- "@wdio/config": "8.16.17",
+ "@wdio/config": "8.16.22",
"@wdio/logger": "8.16.17",
"@wdio/protocols": "8.16.5",
"@wdio/repl": "8.10.1",
- "@wdio/types": "8.16.12",
- "@wdio/utils": "8.16.17",
+ "@wdio/types": "8.16.22",
+ "@wdio/utils": "8.16.22",
"archiver": "^6.0.0",
"aria-query": "^5.0.0",
"css-shorthand-properties": "^1.1.1",
@@ -8781,7 +8780,7 @@
"resq": "^1.9.1",
"rgb2hex": "0.2.5",
"serialize-error": "^11.0.1",
- "webdriver": "8.16.17"
+ "webdriver": "8.16.22"
},
"engines": {
"node": "^16.13 || >=18"
@@ -8804,12 +8803,6 @@
"balanced-match": "^1.0.0"
}
},
- "node_modules/webdriverio/node_modules/devtools-protocol": {
- "version": "0.0.1203626",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz",
- "integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==",
- "dev": true
- },
"node_modules/webdriverio/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
diff --git a/tests/wdio/package.json b/tests/wdio/package.json
index 2770bcca1..043f17643 100644
--- a/tests/wdio/package.json
+++ b/tests/wdio/package.json
@@ -6,11 +6,11 @@
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
- "@wdio/cli": "^8.16.19",
- "@wdio/local-runner": "^8.16.19",
- "@wdio/mocha-framework": "^8.16.17",
- "@wdio/spec-reporter": "^8.16.17",
- "eslint": "^8.49.0",
+ "@wdio/cli": "^8.16.22",
+ "@wdio/local-runner": "^8.16.22",
+ "@wdio/mocha-framework": "^8.16.22",
+ "@wdio/spec-reporter": "^8.16.22",
+ "eslint": "^8.51.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-sonarjs": "^0.21.0",
"npm-run-all": "^4.1.5",
diff --git a/web/package-lock.json b/web/package-lock.json
index 19405122f..5a54dcfec 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -17,7 +17,7 @@
"@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.4.2",
"@fortawesome/fontawesome-free": "^6.4.2",
- "@goauthentik/api": "^2023.8.3-1696335052",
+ "@goauthentik/api": "^2023.8.3-1696847703",
"@lit-labs/context": "^0.4.1",
"@lit-labs/task": "^3.0.2",
"@lit/localize": "^0.11.4",
@@ -55,12 +55,12 @@
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
"@lit/localize-tools": "^0.6.10",
- "@rollup/plugin-babel": "^6.0.3",
- "@rollup/plugin-commonjs": "^25.0.4",
- "@rollup/plugin-node-resolve": "^15.2.1",
- "@rollup/plugin-replace": "^5.0.2",
- "@rollup/plugin-terser": "^0.4.3",
- "@rollup/plugin-typescript": "^11.1.4",
+ "@rollup/plugin-babel": "^6.0.4",
+ "@rollup/plugin-commonjs": "^25.0.5",
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "@rollup/plugin-replace": "^5.0.3",
+ "@rollup/plugin-terser": "^0.4.4",
+ "@rollup/plugin-typescript": "^11.1.5",
"@storybook/addon-essentials": "^7.4.6",
"@storybook/addon-links": "^7.4.6",
"@storybook/blocks": "^7.1.1",
@@ -75,19 +75,19 @@
"babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths": "^1.0.3",
"cross-env": "^7.0.3",
- "eslint": "^8.50.0",
+ "eslint": "^8.51.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-custom-elements": "0.0.8",
"eslint-plugin-lit": "^1.9.1",
"eslint-plugin-sonarjs": "^0.21.0",
- "eslint-plugin-storybook": "^0.6.14",
+ "eslint-plugin-storybook": "^0.6.15",
"lit-analyzer": "^1.2.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"pyright": "^1.1.330",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "rollup": "^3.29.4",
+ "rollup": "^4.0.2",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-cssimport": "^1.0.3",
"rollup-plugin-postcss-lit": "^2.1.0",
@@ -2796,9 +2796,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.50.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz",
- "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==",
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
+ "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -2882,9 +2882,9 @@
}
},
"node_modules/@goauthentik/api": {
- "version": "2023.8.3-1696335052",
- "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.3-1696335052.tgz",
- "integrity": "sha512-MFgMdkk8NVvJfgU9RfZlP8ypUjH5xhBtnannnFWDJLuvsYxyyaD6Rbj2cLE2KSaIGHEpbsmzeW3eUy7ZRjpKOw=="
+ "version": "2023.8.3-1696847703",
+ "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.3-1696847703.tgz",
+ "integrity": "sha512-RsOANX4L6RHaGXvMhJNq9g+E0ZLW3cwgl/t5CyQxLYvWgmVvZU4t78hxlOF7vFREoO5nhZUZnOOlD2+n5gOqLg=="
},
"node_modules/@hcaptcha/types": {
"version": "1.0.3",
@@ -4345,9 +4345,9 @@
}
},
"node_modules/@rollup/plugin-babel": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.3.tgz",
- "integrity": "sha512-fKImZKppa1A/gX73eg4JGo+8kQr/q1HBQaCGKECZ0v4YBBv3lFqi14+7xyApECzvkLTHCifx+7ntcrvtBIRcpg==",
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz",
+ "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==",
"dev": true,
"dependencies": {
"@babel/helper-module-imports": "^7.18.6",
@@ -4359,7 +4359,7 @@
"peerDependencies": {
"@babel/core": "^7.0.0",
"@types/babel__core": "^7.1.9",
- "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"@types/babel__core": {
@@ -4371,9 +4371,9 @@
}
},
"node_modules/@rollup/plugin-commonjs": {
- "version": "25.0.4",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.4.tgz",
- "integrity": "sha512-L92Vz9WUZXDnlQQl3EwbypJR4+DM2EbsO+/KOcEkP4Mc6Ct453EeDB2uH9lgRwj4w5yflgNpq9pHOiY8aoUXBQ==",
+ "version": "25.0.5",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.5.tgz",
+ "integrity": "sha512-xY8r/A9oisSeSuLCTfhssyDjo9Vp/eDiRLXkg1MXCcEEgEjPmLU+ZyDB20OOD0NlyDa/8SGbK5uIggF5XTx77w==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
@@ -4387,7 +4387,7 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^2.68.0||^3.0.0"
+ "rollup": "^2.68.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
@@ -4396,9 +4396,9 @@
}
},
"node_modules/@rollup/plugin-node-resolve": {
- "version": "15.2.1",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.1.tgz",
- "integrity": "sha512-nsbUg588+GDSu8/NS8T4UAshO6xeaOfINNuXeVHcKV02LJtoRaM1SiOacClw4kws1SFiNhdLGxlbMY9ga/zs/w==",
+ "version": "15.2.3",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
+ "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
@@ -4412,7 +4412,7 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^2.78.0||^3.0.0"
+ "rollup": "^2.78.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
@@ -4421,9 +4421,9 @@
}
},
"node_modules/@rollup/plugin-replace": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz",
- "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.3.tgz",
+ "integrity": "sha512-je7fu05B800IrMlWjb2wzJcdXzHYW46iTipfChnBDbIbDXhASZs27W1B58T2Yf45jZtJUONegpbce+9Ut2Ti/Q==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
@@ -4433,7 +4433,7 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
@@ -4442,9 +4442,9 @@
}
},
"node_modules/@rollup/plugin-terser": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz",
- "integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==",
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
+ "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
"dev": true,
"dependencies": {
"serialize-javascript": "^6.0.1",
@@ -4455,7 +4455,7 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^2.x || ^3.x"
+ "rollup": "^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
@@ -4464,9 +4464,9 @@
}
},
"node_modules/@rollup/plugin-typescript": {
- "version": "11.1.4",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.4.tgz",
- "integrity": "sha512-WZRh5LBVLQXdKFICUId5J3eIpmjGURaBqntfg3GSZACgeOAFS+lOSMGTwfzDkELTaZVp/lWdMVNU3UkwCUBg/Q==",
+ "version": "11.1.5",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.5.tgz",
+ "integrity": "sha512-rnMHrGBB0IUEv69Q8/JGRD/n4/n6b3nfpufUu26axhUcboUzv/twfZU8fIBbTOphRAe0v8EyxzeDpKXqGHfyDA==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
@@ -4476,7 +4476,7 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^2.14.0||^3.0.0",
+ "rollup": "^2.14.0||^3.0.0||^4.0.0",
"tslib": "*",
"typescript": ">=3.7.0"
},
@@ -4490,9 +4490,9 @@
}
},
"node_modules/@rollup/pluginutils": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz",
- "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==",
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz",
+ "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
@@ -4503,7 +4503,7 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
@@ -4511,6 +4511,162 @@
}
}
},
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.0.2.tgz",
+ "integrity": "sha512-xDvk1pT4vaPU2BOLy0MqHMdYZyntqpaBf8RhBiezlqG9OjY8F50TyctHo8znigYKd+QCFhCmlmXHOL/LoaOl3w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.0.2.tgz",
+ "integrity": "sha512-lqCglytY3E6raze27DD9VQJWohbwCxzqs9aSHcj5X/8hJpzZfNdbsr4Ja9Hqp6iPyF53+5PtPx0pKRlkSvlHZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.0.2.tgz",
+ "integrity": "sha512-nkBKItS6E6CCzvRwgiKad+j+1ibmL7SIInj7oqMWmdkCjiSX6VeVZw2mLlRKIUL+JjsBgpATTfo7BiAXc1v0jA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.0.2.tgz",
+ "integrity": "sha512-vX2C8xvWPIbpEgQht95+dY6BReKAvtDgPDGi0XN0kWJKkm4WdNmq5dnwscv/zxvi+n6jUTBhs6GtpkkWT4q8Gg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.0.2.tgz",
+ "integrity": "sha512-DVFIfcHOjgmeHOAqji4xNz2wczt1Bmzy9MwBZKBa83SjBVO/i38VHDR+9ixo8QpBOiEagmNw12DucG+v55tCrg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.0.2.tgz",
+ "integrity": "sha512-GCK/a9ItUxPI0V5hQEJjH4JtOJO90GF2Hja7TO+EZ8rmkGvEi8/ZDMhXmcuDpQT7/PWrTT9RvnG8snMd5SrhBQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.0.2.tgz",
+ "integrity": "sha512-cLuBp7rOjIB1R2j/VazjCmHC7liWUur2e9mFflLJBAWCkrZ+X0+QwHLvOQakIwDymungzAKv6W9kHZnTp/Mqrg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.0.2.tgz",
+ "integrity": "sha512-Zqw4iVnJr2naoyQus0yLy7sLtisCQcpdMKUCeXPBjkJtpiflRime/TMojbnl8O3oxUAj92mxr+t7im/RbgA20w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.0.2.tgz",
+ "integrity": "sha512-jJRU9TyUD/iMqjf8aLAp7XiN3pIj5v6Qcu+cdzBfVTKDD0Fvua4oUoK8eVJ9ZuKBEQKt3WdlcwJXFkpmMLk6kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.0.2.tgz",
+ "integrity": "sha512-ZkS2NixCxHKC4zbOnw64ztEGGDVIYP6nKkGBfOAxEPW71Sji9v8z3yaHNuae/JHPwXA+14oDefnOuVfxl59SmQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.0.2.tgz",
+ "integrity": "sha512-3SKjj+tvnZ0oZq2BKB+fI+DqYI83VrRzk7eed8tJkxeZ4zxJZcLSE8YDQLYGq1tZAnAX+H076RHHB4gTZXsQzw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.0.2.tgz",
+ "integrity": "sha512-MBdJIOxRauKkry7t2q+rTHa3aWjVez2eioWg+etRVS3dE4tChhmt5oqZYr48R6bPmcwEhxQr96gVRfeQrLbqng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@sentry-internal/tracing": {
"version": "7.73.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.73.0.tgz",
@@ -7500,6 +7656,22 @@
"node": ">=12"
}
},
+ "node_modules/@storybook/builder-vite/node_modules/rollup": {
+ "version": "3.29.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+ "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/@storybook/channels": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.4.1.tgz",
@@ -13606,15 +13778,15 @@
}
},
"node_modules/eslint": {
- "version": "8.50.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz",
- "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==",
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
+ "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "8.50.0",
+ "@eslint/js": "8.51.0",
"@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -13710,9 +13882,9 @@
}
},
"node_modules/eslint-plugin-storybook": {
- "version": "0.6.14",
- "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.14.tgz",
- "integrity": "sha512-IeYigPur/MvESNDo43Z+Z5UvlcEVnt0dDZmnw1odi9X2Th1R3bpGyOZsHXb9bp1pFecOpRUuoMG5xdID2TwwOg==",
+ "version": "0.6.15",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.15.tgz",
+ "integrity": "sha512-lAGqVAJGob47Griu29KXYowI4G7KwMoJDOkEip8ujikuDLxU+oWJ1l0WL6F2oDO4QiyUFXvtDkEkISMOPzo+7w==",
"dev": true,
"dependencies": {
"@storybook/csf": "^0.0.1",
@@ -20233,18 +20405,30 @@
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"node_modules/rollup": {
- "version": "3.29.4",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
- "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.0.2.tgz",
+ "integrity": "sha512-MCScu4usMPCeVFaiLcgMDaBQeYi1z6vpWxz0r0hq0Hv77Y2YuOTZldkuNJ54BdYBH3e+nkrk6j0Rre/NLDBYzg==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
- "node": ">=14.18.0",
+ "node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.0.2",
+ "@rollup/rollup-android-arm64": "4.0.2",
+ "@rollup/rollup-darwin-arm64": "4.0.2",
+ "@rollup/rollup-darwin-x64": "4.0.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.0.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.0.2",
+ "@rollup/rollup-linux-arm64-musl": "4.0.2",
+ "@rollup/rollup-linux-x64-gnu": "4.0.2",
+ "@rollup/rollup-linux-x64-musl": "4.0.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.0.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.0.2",
+ "@rollup/rollup-win32-x64-msvc": "4.0.2",
"fsevents": "~2.3.2"
}
},
@@ -23000,6 +23184,23 @@
}
}
},
+ "node_modules/vite/node_modules/rollup": {
+ "version": "3.29.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+ "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/vscode-css-languageservice": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-4.3.0.tgz",
diff --git a/web/package.json b/web/package.json
index 856e6d98b..08ede48ca 100644
--- a/web/package.json
+++ b/web/package.json
@@ -35,7 +35,7 @@
"@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.4.2",
"@fortawesome/fontawesome-free": "^6.4.2",
- "@goauthentik/api": "^2023.8.3-1696335052",
+ "@goauthentik/api": "^2023.8.3-1696847703",
"@lit-labs/context": "^0.4.1",
"@lit-labs/task": "^3.0.2",
"@lit/localize": "^0.11.4",
@@ -73,12 +73,12 @@
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
"@lit/localize-tools": "^0.6.10",
- "@rollup/plugin-babel": "^6.0.3",
- "@rollup/plugin-commonjs": "^25.0.4",
- "@rollup/plugin-node-resolve": "^15.2.1",
- "@rollup/plugin-replace": "^5.0.2",
- "@rollup/plugin-terser": "^0.4.3",
- "@rollup/plugin-typescript": "^11.1.4",
+ "@rollup/plugin-babel": "^6.0.4",
+ "@rollup/plugin-commonjs": "^25.0.5",
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "@rollup/plugin-replace": "^5.0.3",
+ "@rollup/plugin-terser": "^0.4.4",
+ "@rollup/plugin-typescript": "^11.1.5",
"@storybook/addon-essentials": "^7.4.6",
"@storybook/addon-links": "^7.4.6",
"@storybook/blocks": "^7.1.1",
@@ -93,19 +93,19 @@
"babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths": "^1.0.3",
"cross-env": "^7.0.3",
- "eslint": "^8.50.0",
+ "eslint": "^8.51.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-custom-elements": "0.0.8",
"eslint-plugin-lit": "^1.9.1",
"eslint-plugin-sonarjs": "^0.21.0",
- "eslint-plugin-storybook": "^0.6.14",
+ "eslint-plugin-storybook": "^0.6.15",
"lit-analyzer": "^1.2.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"pyright": "^1.1.330",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "rollup": "^3.29.4",
+ "rollup": "^4.0.2",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-cssimport": "^1.0.3",
"rollup-plugin-postcss-lit": "^2.1.0",
diff --git a/web/src/admin/providers/saml/SAMLProviderForm.ts b/web/src/admin/providers/saml/SAMLProviderForm.ts
index e74fa76b3..012abdcae 100644
--- a/web/src/admin/providers/saml/SAMLProviderForm.ts
+++ b/web/src/admin/providers/saml/SAMLProviderForm.ts
@@ -318,6 +318,24 @@ export class SAMLProviderFormPage extends ModelForm
+ ${msg( + "When using IDP-initiated logins, the relay state will be set to this value.", + )} +
+