Merge branch 'main' into application-wizard-2-with-api-and-tests
* main: (41 commits) lifecycle: fix install_id migration not running (#7116) core: bump Go from 1.20 to 1.21 (#7117) providers/ldap: add windows adsi support (#7098) web: bump API Client version (#7113) translate: Updates for file web/xliff/en.xlf in zh-Hans on branch main (#7112) translate: Updates for file web/xliff/en.xlf in zh_CN on branch main (#7111) web: bump the wdio group in /tests/wdio with 4 updates (#7108) core/api: add uuid field to core api user http response (#7110) core: bump goauthentik.io/api/v3 from 3.2023083.4 to 3.2023083.5 (#7105) core: bump golang.org/x/oauth2 from 0.12.0 to 0.13.0 (#7106) web: bump the eslint group in /tests/wdio with 1 update (#7107) providers/proxy: improve SLO by backchannel logging out sessions (#7099) web: bump @rollup/plugin-node-resolve from 15.2.2 to 15.2.3 in /web (#7104) web: bump the eslint group in /web with 1 update (#7103) web: bump the storybook group in /web with 1 update (#7102) web: bump API Client version (#7101) providers/saml: add default RelayState value for IDP-initiated requests (#7100) lifecycle: improve reliability of system migrations (#7089) sources/ldap: fix attribute path resolution (#7090) root: Ignore the vendor folder (#7094) ...
This commit is contained in:
commit
478258d88f
2
.github/workflows/ci-outpost.yml
vendored
2
.github/workflows/ci-outpost.yml
vendored
|
@ -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:
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -206,3 +206,6 @@ data/
|
|||
.netlify
|
||||
.ruff_cache
|
||||
source_docs/
|
||||
|
||||
### Golang ###
|
||||
/vendor/
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
2
Makefile
2
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}
|
||||
|
|
|
@ -190,6 +190,7 @@ class UserSerializer(ModelSerializer):
|
|||
"uid",
|
||||
"path",
|
||||
"type",
|
||||
"uuid",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"name": {"allow_blank": True},
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
20
authentik/providers/proxy/signals.py
Normal file
20
authentik/providers/proxy/signals.py
Normal file
|
@ -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)
|
|
@ -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,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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"""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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": []
|
||||
|
|
|
@ -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,
|
||||
|
|
18
go.mod
18
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
|
||||
|
|
36
go.sum
36
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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)},
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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 ) )",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
49
internal/outpost/proxyv2/ws.go
Normal file
49
internal/outpost/proxyv2/ws.go
Normal file
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
)
|
||||
|
|
|
@ -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", ""))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
7
poetry.lock
generated
7
poetry.lock
generated
|
@ -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]]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
18
schema.yml
18
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
|
||||
|
|
|
@ -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,
|
||||
|
|
169
tests/wdio/package-lock.json
generated
169
tests/wdio/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
311
web/package-lock.json
generated
311
web/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -318,6 +318,24 @@ export class SAMLProviderFormPage extends ModelForm<SAMLProvider, number> {
|
|||
</p>
|
||||
<ak-utils-time-delta-help></ak-utils-time-delta-help>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Default relay state")}
|
||||
?required=${true}
|
||||
name="defaultRelayState"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${this.instance?.defaultRelayState || ""}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"When using IDP-initiated logins, the relay state will be set to this value.",
|
||||
)}
|
||||
</p>
|
||||
<ak-utils-time-delta-help></ak-utils-time-delta-help>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("Digest algorithm")}
|
||||
|
|
|
@ -994,10 +994,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>SSL-Zertifikate der Upstream-Server prüfen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>Verwenden Sie diesen Provider mit auth_request von Nginx oder forwardAuth von Traefik. Jede Anwendung/Domäne benötigt ihren eigenen Provider. Zusätzlich muss auf jeder Domain /outpost.goauthentik.io an den Außenposten weitergeleitet werden (wenn Sie einen gemanagten Außenposten verwenden, wird dies für Sie erledigt).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>Verwenden Sie diesen Anbieter mit auth_request von nginx oder forwardAuth von traefik. Pro Root-Domain wird nur ein einziger Anbieter benötigt. Sie können keine Autorisierung pro Anwendung vornehmen, aber Sie müssen nicht für jede Anwendung einen Anbieter erstellen.</target>
|
||||
|
@ -5925,6 +5921,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -1041,10 +1041,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>Validate SSL Certificates of upstream servers.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</target>
|
||||
|
@ -6239,6 +6235,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -976,10 +976,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>Validar los certificados SSL de los servidores ascendentes.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>Use este proveedor con auth_request de nginx o ForwardAuth de traefik. Cada aplicación/dominio necesita su propio proveedor. Además, en cada dominio, /outpost.goauthentik.io debe enrutarse al puesto avanzado (cuando se usa un puesto avanzado administrado, esto se hace por usted).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>Use este proveedor con auth_request de nginx o ForwardAuth de traefik. Solo se requiere un único proveedor por dominio raíz. No puede realizar la autorización por solicitud, pero no tiene que crear un proveedor para cada solicitud.</target>
|
||||
|
@ -5833,6 +5829,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -1295,11 +1295,6 @@ Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target>
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>Valider les certificats SSL des serveurs amonts.</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous).</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
|
@ -7816,6 +7811,15 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
|||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
<target>WebAuthn n'est pas supporté pas ce navigateur.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -1002,10 +1002,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>Sprawdź poprawność certyfikatów SSL serwerów nadrzędnych.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>Użyj tego dostawcy z auth_request nginx lub forwardAuth traefik. Każda aplikacja/domena potrzebuje własnego dostawcy. Dodatkowo w każdej domenie /outpost.goauthentik.io musi być przekierowany do placówki (w przypadku korzystania z zarządzanej placówki jest to zrobione za Ciebie).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>Użyj tego dostawcy z auth_request nginx lub forwardAuth traefik. Tylko jeden dostawca jest wymagany na domenę główną. Nie możesz wykonać autoryzacji dla aplikacji, ale nie musisz tworzyć dostawcy dla każdej aplikacji.</target>
|
||||
|
@ -6072,6 +6068,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -1025,10 +1025,6 @@
|
|||
<trans-unit id="s4a26798e1c3c37dd">
|
||||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
|
@ -6174,6 +6170,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -975,10 +975,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>Yayın yukarı akış sunucularının SSL Sertifikalarını doğrulayın.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>Bu sağlayıcıyı nginx'in auth_request veya traefik's forwardAuth ile kullanın. Her uygulama/etki alanının kendi sağlayıcısına ihtiyacı vardır. Ayrıca, her etki alanında /outpost.goauthentik.io üsse yönlendirilmelidir (manged bir üs kullanırken, bu sizin için yapılır).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>Bu sağlayıcıyı nginx'in auth_request veya traefik'in forwardAuth ile kullanın. Kök etki alanı başına yalnızca tek bir sağlayıcı gereklidir. Uygulama başına yetkilendirme yapamazsınız, ancak her uygulama için bir sağlayıcı oluşturmanız gerekmez.</target>
|
||||
|
@ -5826,6 +5822,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file target-language="zh-Hans" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="s4caed5b7a7e5d89b">
|
||||
|
@ -613,9 +613,9 @@
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="saa0e2675da69651b">
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>未找到 URL "
|
||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||
<target>未找到 URL "
|
||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s58cd9c2fe836d9c6">
|
||||
|
@ -1067,8 +1067,8 @@
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa8384c9c26731f83">
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||
<target>要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s55787f4dfcdce52b">
|
||||
|
@ -1295,11 +1295,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>验证上游服务器的 SSL 证书。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
|
@ -1814,8 +1809,8 @@
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa90b7809586c35ce">
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s0410779cb47de312">
|
||||
|
@ -3238,8 +3233,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="s76768bebabb7d543">
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
|
||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s026555347e589f0e">
|
||||
|
@ -4031,8 +4026,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="s7b1fba26d245cb1c">
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
|
||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44536d20bb5c8257">
|
||||
|
@ -4041,8 +4036,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="s3bb51cabb02b997e">
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>格式:"weeks=3;days=2;hours=3,seconds=2"。</target>
|
||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||
<target>格式:"weeks=3;days=2;hours=3,seconds=2"。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s04bfd02201db5ab8">
|
||||
|
@ -4238,10 +4233,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="sa95a538bfbb86111">
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||
<target>您确定要更新
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||
|
@ -5342,7 +5337,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="sdf1d8edef27236f0">
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||
<target>像 YubiKey 这样的“漫游”身份验证器</target>
|
||||
|
||||
</trans-unit>
|
||||
|
@ -5677,10 +5672,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d5f69929bb7221d">
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||
<target>
|
||||
<x id="0" equiv-text="${prompt.name}"/>("
|
||||
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
|
||||
<x id="0" equiv-text="${prompt.name}"/>("
|
||||
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
|
||||
<x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||
|
||||
</trans-unit>
|
||||
|
@ -5729,7 +5724,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||
|
||||
</trans-unit>
|
||||
<trans-unit id="s1608b2f94fa0dbd4">
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||
<target>如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。</target>
|
||||
|
||||
</trans-unit>
|
||||
|
@ -7818,7 +7813,19 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
<target>浏览器不支持 WebAuthn。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
<target>与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
<target>默认中继状态</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
<target>当使用 IDP 发起的登录时,中继状态会被设置为此值。</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
</xliff>
|
|
@ -983,10 +983,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>验证上游服务器的 SSL 证书。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个应用程序/域都需要自己的提供商。此外,在每个域上,/outpost.goauthentik.io必须路由到 Outpost(使用托管的 Outpost 时,这是为您完成的)。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个根域只需要一个提供程序。您无法执行每个应用程序的授权,但不必为每个应用程序创建提供程序。</target>
|
||||
|
@ -5878,6 +5874,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -1295,11 +1295,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>验证上游服务器的 SSL 证书。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。</target>
|
||||
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
|
@ -7818,6 +7813,18 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
<target>浏览器不支持 WebAuthn。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
<target>与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
<target>默认中继状态</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
<target>当使用 IDP 发起的登录时,中继状态会被设置为此值。</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
|
@ -983,10 +983,6 @@
|
|||
<source>Validate SSL Certificates of upstream servers.</source>
|
||||
<target>验证上游服务器的 SSL 证书。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9c73dced379c37a2">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).</source>
|
||||
<target>将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个应用程序/域都需要自己的提供商。此外,在每个域上,/outpost.goauthentik.io必须路由到 Outpost(使用托管的 Outpost 时,这是为您完成的)。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s44c90273f08fb718">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.</source>
|
||||
<target>将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个根域只需要一个提供程序。您无法执行每个应用程序的授权,但不必为每个应用程序创建提供程序。</target>
|
||||
|
@ -5877,6 +5873,15 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||
</trans-unit>
|
||||
<trans-unit id="se9e9e1d6799b86a5">
|
||||
<source>WebAuthn not supported by browser.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sff0ac1ace2d90709">
|
||||
<source>Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you).</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="scb58b8a60cad8762">
|
||||
<source>Default relay state</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s6827a456c9dfc6ee">
|
||||
<source>When using IDP-initiated logins, the relay state will be set to this value.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
|
BIN
website/blog/2023-10-05-SCIMs-many-deviations/image1.png
Normal file
BIN
website/blog/2023-10-05-SCIMs-many-deviations/image1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
81
website/blog/2023-10-05-SCIMs-many-deviations/item.md
Normal file
81
website/blog/2023-10-05-SCIMs-many-deviations/item.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
title: "We need to talk about SCIM: More deviation than standard"
|
||||
description: "SCIM’s many deviations, undocumented edge cases, and lack of official test coverage make it an especially complex protocol to implement."
|
||||
slug: 2023-10-05-SCIMs-many-deviations
|
||||
authors:
|
||||
- name: Jens Langhammer
|
||||
title: CTO at Authentik Security Inc
|
||||
url: https://github.com/BeryJu
|
||||
image_url: https://github.com/BeryJu.png
|
||||
tags:
|
||||
- SCIM
|
||||
- SSO
|
||||
- open source
|
||||
- community
|
||||
- identity provider
|
||||
- security
|
||||
- authentication
|
||||
hide_table_of_contents: false
|
||||
image: ./image1.png
|
||||
---
|
||||
|
||||
> **_authentik is an open source Identity Provider that unifies your identity needs into a single platform, replacing Okta, Active Directory, and auth0. Authentik Security is a [public benefit company](https://github.com/OpenCoreVentures/ocv-public-benefit-company/blob/main/ocv-public-benefit-company-charter.md) building on top of the open source project._**
|
||||
|
||||
---
|
||||
|
||||
As a young security company, we’ve been working on our implementation of SCIM (System for Cross-domain Identity Management), which I’ll share more about below. SCIM is in many ways a great improvement on LDAP, but we’ve run into challenges in implementation and some things just seem to be harder than they need to be. Is it just us?
|
||||
|
||||
!["authentik admin interface"](./image1.png)
|
||||
|
||||
<!--truncate-->
|
||||
|
||||
# Improvements on LDAP
|
||||
|
||||
From a security standpoint, it’s wise not to expose LDAP (Lightweight Directory Access Protocol) to the internet if you’re using Active Directory, OpenLDAP, FreeIPA or anything similar as your source of truth for authentication. SCIM fills a need for directory synchronization in a cloud-native world in which many companies aren’t hosting the software they use on their own servers.
|
||||
|
||||
SCIM, being an HTTP API specification, is much simpler and (in theory) gives you less to worry about than LDAP (being its own specific protocol). SCIM also offers time- and cost-saving advantages over Just in Time provisioning, especially for scaling companies. SCIM can save hours of company time for IT admins who no longer have to manually create individual accounts across multiple applications for new team members. Offboarding is also streamlined as departing team members can be deprovisioned automatically, preventing unauthorized access.
|
||||
|
||||
Most modern SaaS applications support SCIM, making it essential for security vendors to support the protocol, but it does come with its drawbacks.
|
||||
|
||||
# Growing pains
|
||||
|
||||
authentik currently supports SCIM going outwards; which means is that authentik is your source of truth/central directory, and you can use authentik together with a tool like [Sentry](https://sentry.io) that supports SCIM. In this case all your users or employees in authentik automatically get created in Sentry, with their correct group assignment, and they can just log in.
|
||||
|
||||
Most of the information and commentary I see about SCIM focuses on the advantages described above, but I don’t see a lot of talk about the pitfalls of SCIM. I’m sharing our experiences here and am curious if others have found the same or can tell me how they’re avoiding these (I would love to hear that we’re doing this wrong actually!).
|
||||
|
||||
## Deviation from standards isn’t well documented
|
||||
|
||||
Implementing a protocol based on reading the RFCs and then writing the code is in itself not fun (to be fair, this is true for implementing any protocol based on a standard). Having implemented SCIM in line with the specification though, once we actually started testing with different solutions that can receive SCIM, we discovered a lot of quirks along the lines of x solution doesn’t do y (which the documentation says they should) or they do it slightly differently, and so on.
|
||||
|
||||
This leads to a lot of workarounds which shouldn’t be necessary or things that simply don’t work without a clear cause. For example, when we started testing SCIM with Sentry, we ran into a lot of deviations (to their credit these were mostly listed in their [documentation](https://docs.sentry.io/product/accounts/sso/#scim-provisioning)). One of the issues I ran into when testing locally was when we created a user with SCIM, it just returned an error saying, “Please enter a valid email address” even though we _had_ sent it a valid email address. At least Sentry has the advantage of being open source, so we can just go and look at the code and see what’s happening, but this is still no small effort and you don’t have that option with closed source solutions.
|
||||
|
||||
You can see other examples of confusing/unexpected behavior from SCIM [here](https://github.com/goauthentik/authentik/issues/5396) and [here](https://github.com/goauthentik/authentik/issues/6695).
|
||||
|
||||
## Testing isn’t built out
|
||||
|
||||
Some protocols make a big effort to uphold the adherence to the standard. OpenID Connect is another standard that’s well defined by multiple RFCs, but also has a lot of room for vendor-specific quirks. However, with OpenID we have the reassurance that the [OpenID Foundation](https://openid.net/foundation/) is behind it.
|
||||
|
||||
The OpenID Foundation is a non-profit standards body of which Authentik Security is a member, but anyone can join to contribute to working groups that support implementation. OpenID Connect offers an [entire test suite](https://openid.net/certification/about-conformance-suite/) made up of hundreds of tests that you can run against your implementation, testing for edge cases and all the behaviors that they define. If you pass all the required tests you can send them the test results and get a [certification](https://openid.net/certification/) (which we are also working on) that your software adheres to the standards.
|
||||
|
||||
Instead of working in the dark and trying to make sure you’ve interpreted the specs correctly (while testing with vendors who might have their own interpretations), you have some reassurance that you’re doing the right things when developing with OpenID Connect.
|
||||
|
||||
To my knowledge there isn’t an official equivalent for SCIM—there are some smaller community projects that try to do something similar, but again, then you have to rely on someone’s interpretation of the standard. Even the [SCIM website’s overview page](https://scim.cloud/) says, “Information on this overview page is not normative.”
|
||||
|
||||
## Updating a user is unnecessarily complex
|
||||
|
||||
As mentioned above, authentik currently supports SCIM in one direction, but we are [working on making it so that another application can send SCIM to authentik](https://github.com/goauthentik/authentik/pull/3051), to create users in it. In this process we’ve discovered that updating a user is surprisingly annoying to implement. With SCIM [you have two options to update a user](https://datatracker.ietf.org/doc/html/rfc7644#autoid-22):
|
||||
|
||||
- You can either send a request to replace the user (for which you have to send _all_ the user’s data), or
|
||||
- You can send a patch request
|
||||
|
||||
A lot of vendors use the patch request option to update group membership: they send a patch request for a user and just say, for example, “Add that group,” or “Remove that group.” This approach makes more sense in the case of an advanced user with tons of groups, as you’re not replacing everything, just making adjustments to their membership. However, this patch request is done with a custom filtering expression language which is extremely and needlessly complex.
|
||||
|
||||
My first thought when I encountered this was, “Okay, can I just parse this with RegEx?” but it’s not possible. The correct way to parse it is with [ANTLR](https://www.antlr.org/), a parser generator for different kinds of grammars. The thing about ANTLR is that it’s a type of tool usually used to build a compiler: it allows you to define a grammar for which it generates a parser that can then parse things in said grammar. It’s not typically used for filtering language for directories and there are a lot of existing syntaxes that could have been used for this purpose. While luckily some people have written a full grammar for this, I was hoping that there would at least be an official definition for an ANTLR grammar.
|
||||
|
||||
# Immaturity bites
|
||||
|
||||
LDAP, being the more mature protocol (introduced in the ‘90s), has the advantage that deviations have been well documented and kinks ironed out. There are a handful of “standard” implementations like Active Directory, FreeIPA and some others. Similar to SAML support—there’s just been a lot more time to document edge cases and workarounds.
|
||||
|
||||
SCIM, despite being around since 2015, is still subject to a lot of different interpretations of the standard, which leads to varying implementations and quirks with how vendors do SCIM. There’s a maturity challenge at work here in both senses—from the vendors but also from ourselves. Since we’ve added SCIM to our product a lot later than LDAP, there’s still a lot of room for us to catch up and make our implementation better.
|
||||
|
||||
_Have you worked on SCIM implementation? Got advice for us? We’d love to hear from you in the comments._
|
|
@ -51,7 +51,7 @@ Applications can either match users on a unique ID sent by authentik called `ext
|
|||
|
||||
#### OAuth/OIDC
|
||||
|
||||
The default provider configuration for the _Subject mode_ option of _Based on the User's hashed ID_ matches the `externalId` that's generated by default. If any other _Subjet mode_ is selected, the `externalId` attribute can be customized via SCIM mappings.
|
||||
The default provider configuration for the _Subject mode_ option of _Based on the User's hashed ID_ matches the `externalId` that's generated by default. If any other _Subject mode_ is selected, the `externalId` attribute can be customized via SCIM mappings.
|
||||
|
||||
#### SAML
|
||||
|
||||
|
|
Reference in a new issue