Compare commits

..

11 Commits

Author SHA1 Message Date
efdecf949d fix a bunch of tests
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:47:25 +02:00
9ea5f56715 start updating some default policies
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:47:10 +02:00
8228b56b75 allow importing from API client
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:46:56 +02:00
518e10dbdb fix yaml?
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:46:55 +02:00
79ddad28a8 fiiine use the user pk
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:45:52 +02:00
beeec85c15 generate evaluator jwt secret
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:45:52 +02:00
0561b8d578 make it work
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:45:52 +02:00
201481bde3 generate api client
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-04-29 19:45:21 +02:00
7d04903d5b docs: remove imports
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-04-29 19:38:09 +02:00
db7d880116 wip
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-04-29 19:38:09 +02:00
259cc81723 wip
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-04-29 19:36:43 +02:00
81 changed files with 2842 additions and 3346 deletions

View File

@ -155,8 +155,8 @@ jobs:
- uses: actions/checkout@v4
- name: Run test suite in final docker images
run: |
echo "PG_PASS=$(openssl rand 32 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64)" >> .env
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker compose pull -q
docker compose up --no-start
docker compose start postgresql redis

View File

@ -14,8 +14,8 @@ jobs:
- uses: actions/checkout@v4
- name: Pre-release test
run: |
echo "PG_PASS=$(openssl rand 32 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64)" >> .env
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker buildx install
mkdir -p ./gen-ts-api
docker build -t testing:latest .

View File

@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Stage 1: Build website
FROM --platform=${BUILDPLATFORM} docker.io/node:22 as website-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as website-builder
ENV NODE_ENV=production
@ -20,7 +20,7 @@ COPY ./SECURITY.md /work/
RUN npm run build-bundled
# Stage 2: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/node:22 as web-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as web-builder
ENV NODE_ENV=production

View File

@ -46,8 +46,8 @@ test-go:
go test -timeout 0 -v -race -cover ./...
test-docker: ## Run all tests in a docker-compose
echo "PG_PASS=$(shell openssl rand 32 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(shell openssl rand 32 | base64)" >> .env
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker compose pull -q
docker compose up --no-start
docker compose start postgresql redis

View File

@ -73,6 +73,11 @@ def auth_user_lookup(raw_header: bytes) -> User | None:
if user:
CTX_AUTH_VIA.set("secret_key")
return user
# then try to auth via expression JWT
user = token_expression_jwt(auth_credentials)
if user:
CTX_AUTH_VIA.set("expression_jwt")
return user
raise AuthenticationFailed("Token invalid/expired")
@ -90,6 +95,13 @@ def token_secret_key(value: str) -> User | None:
return outpost.user
def token_expression_jwt(value: str) -> User | None:
"""Authenticate API call made by Expressions"""
from authentik.lib.expression.evaluator import authenticate_token
return authenticate_token(value)
class TokenAuthentication(BaseAuthentication):
"""Token-based authentication using HTTP Bearer authentication"""

View File

@ -36,7 +36,7 @@ class PropertyMappingEvaluator(BaseEvaluator):
_filename = model.name
else:
_filename = str(model)
super().__init__(filename=_filename)
super().__init__(None, filename=_filename)
req = PolicyRequest(user=User())
req.obj = model
if user:

View File

@ -4,7 +4,7 @@ from django.utils.text import slugify
from authentik.brands.models import Brand
from authentik.core.models import Group, User
from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow, FlowDesignation
from authentik.lib.generators import generate_id
@ -50,10 +50,12 @@ def create_test_brand(**kwargs) -> Brand:
return Brand.objects.create(domain=uid, default=True, **kwargs)
def create_test_cert(alg=PrivateKeyAlg.RSA) -> CertificateKeyPair:
def create_test_cert(use_ec_private_key=False) -> CertificateKeyPair:
"""Generate a certificate for testing"""
builder = CertificateBuilder(f"{generate_id()}.self-signed.goauthentik.io")
builder.alg = alg
builder = CertificateBuilder(
name=f"{generate_id()}.self-signed.goauthentik.io",
use_ec_private_key=use_ec_private_key,
)
builder.build(
subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"],
validity_days=360,

View File

@ -14,13 +14,7 @@ from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import (
CharField,
ChoiceField,
DateTimeField,
IntegerField,
SerializerMethodField,
)
from rest_framework.fields import CharField, DateTimeField, IntegerField, SerializerMethodField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request
from rest_framework.response import Response
@ -32,7 +26,7 @@ from authentik.api.authorization import SecretKeyFilter
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.crypto.apps import MANAGED_KEY
from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction
from authentik.rbac.decorators import permission_required
@ -184,7 +178,6 @@ class CertificateGenerationSerializer(PassiveSerializer):
common_name = CharField()
subject_alt_name = CharField(required=False, allow_blank=True, label=_("Subject-alt name"))
validity_days = IntegerField(initial=365)
alg = ChoiceField(default=PrivateKeyAlg.RSA, choices=PrivateKeyAlg.choices)
class CertificateKeyPairFilter(FilterSet):
@ -247,7 +240,6 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
raw_san = data.validated_data.get("subject_alt_name", "")
sans = raw_san.split(",") if raw_san != "" else []
builder = CertificateBuilder(data.validated_data["common_name"])
builder.alg = data.validated_data["alg"]
builder.build(
subject_alt_names=sans,
validity_days=int(data.validated_data["validity_days"]),

View File

@ -9,28 +9,20 @@ from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, rsa
from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
from cryptography.x509.oid import NameOID
from django.db import models
from django.utils.translation import gettext_lazy as _
from authentik import __version__
from authentik.crypto.models import CertificateKeyPair
class PrivateKeyAlg(models.TextChoices):
"""Algorithm to create private key with"""
RSA = "rsa", _("rsa")
ECDSA = "ecdsa", _("ecdsa")
class CertificateBuilder:
"""Build self-signed certificates"""
common_name: str
alg: PrivateKeyAlg
def __init__(self, name: str):
self.alg = PrivateKeyAlg.RSA
_use_ec_private_key: bool
def __init__(self, name: str, use_ec_private_key=False):
self._use_ec_private_key = use_ec_private_key
self.__public_key = None
self.__private_key = None
self.__builder = None
@ -50,13 +42,11 @@ class CertificateBuilder:
def generate_private_key(self) -> PrivateKeyTypes:
"""Generate private key"""
if self.alg == PrivateKeyAlg.ECDSA:
if self._use_ec_private_key:
return ec.generate_private_key(curve=ec.SECP256R1())
if self.alg == PrivateKeyAlg.RSA:
return rsa.generate_private_key(
public_exponent=65537, key_size=4096, backend=default_backend()
)
raise ValueError(f"Invalid alg: {self.alg}")
return rsa.generate_private_key(
public_exponent=65537, key_size=4096, backend=default_backend()
)
def build(
self,

View File

@ -95,6 +95,9 @@ outposts:
discover: true
disable_embedded_outpost: false
expressions:
global_runtime: python # or python_restricted
ldap:
task_timeout_hours: 2
page_size: 50

View File

@ -3,27 +3,117 @@
import re
import socket
from collections.abc import Iterable
from datetime import timedelta
from functools import lru_cache
from ipaddress import ip_address, ip_network
from pathlib import Path
from tempfile import gettempdir
from textwrap import indent
from typing import Any
from authentik_client.api.admin_api import AdminApi
from authentik_client.api.authenticators_api import AuthenticatorsApi
from authentik_client.api.core_api import CoreApi
from authentik_client.api.crypto_api import CryptoApi
from authentik_client.api.enterprise_api import EnterpriseApi
from authentik_client.api.events_api import EventsApi
from authentik_client.api.flows_api import FlowsApi
from authentik_client.api.managed_api import ManagedApi
from authentik_client.api.oauth2_api import Oauth2Api
from authentik_client.api.outposts_api import OutpostsApi
from authentik_client.api.policies_api import PoliciesApi
from authentik_client.api.propertymappings_api import PropertymappingsApi
from authentik_client.api.providers_api import ProvidersApi
from authentik_client.api.rac_api import RacApi
from authentik_client.api.rbac_api import RbacApi
from authentik_client.api.root_api import RootApi
from authentik_client.api.schema_api import SchemaApi
from authentik_client.api.sources_api import SourcesApi
from authentik_client.api.stages_api import StagesApi
from authentik_client.api.tenants_api import TenantsApi
from authentik_client.api_client import ApiClient
from authentik_client.configuration import Configuration
from cachetools import TLRUCache, cached
from django.conf import settings
from django.core.exceptions import FieldError
from django.utils.timezone import now
from guardian.shortcuts import get_anonymous_user
from jwt import PyJWTError, decode, encode
from rest_framework.serializers import ValidationError
from RestrictedPython import compile_restricted, limited_builtins, safe_builtins, utility_builtins
from sentry_sdk.hub import Hub
from sentry_sdk.tracing import Span
from structlog.stdlib import get_logger
from authentik.core.models import User
from authentik.events.models import Event
from authentik.lib.utils.http import get_http_session
from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_key
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.http import authentik_user_agent, get_http_session
from authentik.lib.utils.reflection import get_apps
from authentik.policies.models import Policy, PolicyBinding
from authentik.policies.process import PolicyProcess
from authentik.policies.types import PolicyRequest, PolicyResult
from authentik.stages.authenticator import devices_for_user
LOGGER = get_logger()
_tmp = Path(gettempdir())
token_path = _tmp / "authentik-evaluator-token"
API_CLIENTS = {
"AdminApi": AdminApi,
"AuthenticatorsApi": AuthenticatorsApi,
"CoreApi": CoreApi,
"CryptoApi": CryptoApi,
"EnterpriseApi": EnterpriseApi,
"EventsApi": EventsApi,
"FlowsApi": FlowsApi,
"ManagedApi": ManagedApi,
"Oauth2Api": Oauth2Api,
"OutpostsApi": OutpostsApi,
"PoliciesApi": PoliciesApi,
"PropertymappingsApi": PropertymappingsApi,
"ProvidersApi": ProvidersApi,
"RacApi": RacApi,
"RbacApi": RbacApi,
"RootApi": RootApi,
"SchemaApi": SchemaApi,
"SourcesApi": SourcesApi,
"StagesApi": StagesApi,
"TenantsApi": TenantsApi,
}
JWT_AUD = "goauthentik.io/api/expression"
_SAFE_MODULES = frozenset(("authentik_client",))
def _safe_import(name, *args, **kwargs):
if name not in _SAFE_MODULES:
raise Exception(f"Don't you even think about {name!r}")
return __import__(name, *args, **kwargs)
@lru_cache
def get_api_token_secret():
if token_path.exists():
with open(token_path) as _token_file:
return _token_file.read()
key = generate_key()
with open(_tmp / "authentik-evaluator-token", "w") as _token_file:
_token_file.write(key)
return key
def authenticate_token(raw_value: str):
"""Authenticate API call from evaluator token"""
try:
jwt = decode(raw_value, get_api_token_secret(), ["HS256"], audience=JWT_AUD)
return User.objects.filter(pk=jwt["sub"]).first()
except PyJWTError as exc:
LOGGER.debug("failed to auth", exc=exc)
return None
class BaseEvaluator:
@ -37,8 +127,14 @@ class BaseEvaluator:
# Filename used for exec
_filename: str
def __init__(self, filename: str | None = None):
_user: User
# Timeout in seconds, used for the expiration of the API key
timeout = 30
def __init__(self, user: User, filename: str | None = None):
self._filename = filename if filename else "BaseEvaluator"
self._user = user
# update website/docs/expressions/_objects.md
# update website/docs/expressions/_functions.md
self._globals = {
@ -57,8 +153,44 @@ class BaseEvaluator:
"resolve_dns": BaseEvaluator.expr_resolve_dns,
"reverse_dns": BaseEvaluator.expr_reverse_dns,
}
for app in get_apps():
# Load models from each app
for model in app.get_models():
self._globals[model.__name__] = model
self._globals.update(API_CLIENTS)
self._context = {}
def get_token(self) -> str:
"""Generate API token to be used by the API Client"""
_now = now()
if not self._user:
self._user = get_anonymous_user()
return encode(
{
"aud": JWT_AUD,
"iss": f"goauthentik.io/expression/{self._filename}",
"sub": str(self._user.pk),
"iat": int(_now.timestamp()),
"exp": int((_now + timedelta(seconds=self.timeout)).timestamp()),
},
get_api_token_secret(),
)
def get_api_client(self):
token = self.get_token()
config = Configuration(
f"unix://{str(_tmp.joinpath('authentik-core.sock'))}/api/v3",
api_key={
"authentik": token,
},
api_key_prefix={"authentik": "Bearer"},
)
if settings.DEBUG:
config.host = "http://localhost:8000/api/v3"
client = ApiClient(config)
client.user_agent = authentik_user_agent()
return client
@cached(cache=TLRUCache(maxsize=32, ttu=lambda key, value, now: now + 180))
@staticmethod
def expr_resolve_dns(host: str, ip_version: int | None = None) -> list[str]:
@ -185,7 +317,16 @@ class BaseEvaluator:
def compile(self, expression: str) -> Any:
"""Parse expression. Raises SyntaxError or ValueError if the syntax is incorrect."""
param_keys = self._context.keys()
return compile(self.wrap_expression(expression, param_keys), self._filename, "exec")
compiler = (
compile_restricted
if CONFIG.get("expressions.global_runtime") == "python_restricted"
else compile
)
return compiler(
self.wrap_expression(expression, param_keys),
self._filename,
"exec",
)
def evaluate(self, expression_source: str) -> Any:
"""Parse and evaluate expression. If the syntax is incorrect, a SyntaxError is raised.
@ -201,7 +342,17 @@ class BaseEvaluator:
self.handle_error(exc, expression_source)
raise exc
try:
if CONFIG.get("expressions.global_runtime") == "python_restricted":
self._globals["__builtins__"] = {
**safe_builtins,
**limited_builtins,
**utility_builtins,
"__import__": _safe_import,
}
_locals = self._context
# We need to create the API Client later so that the token is valid
# from when the execution starts
self._globals["api"] = self.get_api_client()
# Yes this is an exec, yes it is potentially bad. Since we limit what variables are
# available here, and these policies can only be edited by admins, this is a risk
# we're willing to take.
@ -209,6 +360,7 @@ class BaseEvaluator:
exec(ast_obj, self._globals, _locals) # nosec # noqa
result = _locals["result"]
except Exception as exc:
print(exception_to_string(exc))
# So, this is a bit questionable. Essentially, we are edit the stacktrace
# so the user only sees information relevant to them
# and none of our surrounding error handling

View File

@ -1,6 +1,7 @@
"""Test Evaluator base functions"""
from django.test import TestCase
from guardian.shortcuts import get_anonymous_user
from authentik.core.tests.utils import create_test_admin_user
from authentik.events.models import Event
@ -33,7 +34,7 @@ class TestEvaluator(TestCase):
def test_expr_event_create(self):
"""Test expr_event_create"""
evaluator = BaseEvaluator(generate_id())
evaluator = BaseEvaluator(get_anonymous_user(), generate_id())
evaluator._context = {
"foo": "bar",
}

View File

@ -14,12 +14,13 @@ class ExpressionPolicySerializer(PolicySerializer):
def validate_expression(self, expr: str) -> str:
"""validate the syntax of the expression"""
name = "temp-policy" if not self.instance else self.instance.name
PolicyEvaluator(name).validate(expr)
request = self.context.get("request")
PolicyEvaluator(request.user if request else None, name).validate(expr)
return expr
class Meta:
model = ExpressionPolicy
fields = PolicySerializer.Meta.fields + ["expression"]
fields = PolicySerializer.Meta.fields + ["expression", "execution_user"]
class ExpressionPolicyViewSet(UsedByMixin, ModelViewSet):

View File

@ -1,11 +1,12 @@
"""Authentik policy_expression app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPolicyExpressionConfig(AppConfig):
class AuthentikPolicyExpressionConfig(ManagedAppConfig):
"""Authentik policy_expression app config"""
name = "authentik.policies.expression"
label = "authentik_policies_expression"
verbose_name = "authentik Policies.Expression"
default = True

View File

@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Optional
from django.http import HttpRequest
from structlog.stdlib import get_logger
from authentik.core.models import User
from authentik.flows.planner import PLAN_CONTEXT_SSO
from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.policies.exceptions import PolicyException
@ -24,8 +25,8 @@ class PolicyEvaluator(BaseEvaluator):
policy: Optional["ExpressionPolicy"] = None
def __init__(self, policy_name: str | None = None):
super().__init__(policy_name or "PolicyEvaluator")
def __init__(self, user: User, policy_name: str | None = None):
super().__init__(user, policy_name or "PolicyEvaluator")
self._messages = []
# update website/docs/expressions/_objects.md
# update website/docs/expressions/_functions.md
@ -44,6 +45,8 @@ class PolicyEvaluator(BaseEvaluator):
if request.http_request:
self.set_http_request(request.http_request)
self._context["request"] = request
if not self._user:
self._user = request.user
self._context["context"] = request.context
def set_http_request(self, request: HttpRequest):

View File

@ -0,0 +1,26 @@
# Generated by Django 5.0.3 on 2024-03-20 12:14
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_policies_expression", "0004_expressionpolicy_authentik_p_policy__fb6feb_idx"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name="expressionpolicy",
name="execution_user",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to=settings.AUTH_USER_MODEL,
),
),
]

View File

@ -12,6 +12,9 @@ from authentik.policies.types import PolicyRequest, PolicyResult
class ExpressionPolicy(Policy):
"""Execute arbitrary Python code to implement custom checks and validation."""
execution_user = models.ForeignKey(
"authentik_core.User", default=None, null=True, on_delete=models.SET_DEFAULT
)
expression = models.TextField()
@property
@ -26,17 +29,11 @@ class ExpressionPolicy(Policy):
def passes(self, request: PolicyRequest) -> PolicyResult:
"""Evaluate and render expression. Returns PolicyResult(false) on error."""
evaluator = PolicyEvaluator(self.name)
evaluator = PolicyEvaluator(self.execution_user, self.name)
evaluator.policy = self
evaluator.set_policy_request(request)
return evaluator.evaluate(self.expression)
def save(self, *args, **kwargs):
evaluator = PolicyEvaluator(self.name)
evaluator.policy = self
evaluator.validate(self.expression)
return super().save(*args, **kwargs)
class Meta(Policy.PolicyMeta):
verbose_name = _("Expression Policy")
verbose_name_plural = _("Expression Policies")

View File

@ -0,0 +1,13 @@
from django.db.models.signals import pre_save
from django.dispatch import receiver
from authentik.policies.expression.evaluator import PolicyEvaluator
from authentik.policies.expression.models import ExpressionPolicy
@receiver(pre_save, sender=ExpressionPolicy)
def pre_save_expression_policy(sender: type[ExpressionPolicy], instance: ExpressionPolicy, **_):
"""Ensure policy is valid before saving"""
evaluator = PolicyEvaluator(instance.execution_user, instance.name)
evaluator.policy = instance
evaluator.validate(instance.expression)

View File

@ -41,14 +41,14 @@ class TestEvaluator(TestCase):
def test_valid(self):
"""test simple value expression"""
template = "return True"
evaluator = PolicyEvaluator("test")
evaluator = PolicyEvaluator(self.request.user, "test")
evaluator.set_policy_request(self.request)
self.assertEqual(evaluator.evaluate(template).passing, True)
def test_messages(self):
"""test expression with message return"""
template = 'ak_message("some message");return False'
evaluator = PolicyEvaluator("test")
evaluator = PolicyEvaluator(self.request.user, "test")
evaluator.set_policy_request(self.request)
result = evaluator.evaluate(template)
self.assertEqual(result.passing, False)
@ -57,7 +57,7 @@ class TestEvaluator(TestCase):
def test_invalid_syntax(self):
"""test invalid syntax"""
template = ";"
evaluator = PolicyEvaluator("test")
evaluator = PolicyEvaluator(self.request.user, "test")
evaluator.set_policy_request(self.request)
with self.assertRaises(PolicyException):
evaluator.evaluate(template)
@ -65,14 +65,14 @@ class TestEvaluator(TestCase):
def test_validate(self):
"""test validate"""
template = "True"
evaluator = PolicyEvaluator("test")
evaluator = PolicyEvaluator(self.request.user, "test")
result = evaluator.validate(template)
self.assertEqual(result, True)
def test_validate_invalid(self):
"""test validate"""
template = ";"
evaluator = PolicyEvaluator("test")
evaluator = PolicyEvaluator(self.request.user, "test")
with self.assertRaises(ValidationError):
evaluator.validate(template)
@ -83,7 +83,7 @@ class TestEvaluator(TestCase):
execution_logging=True,
expression="ak_message(request.http_request.path)\nreturn True",
)
evaluator = PolicyEvaluator("test")
evaluator = PolicyEvaluator(self.request.user, "test")
evaluator.set_policy_request(self.request)
proc = PolicyProcess(PolicyBinding(policy=expr), request=self.request, connection=None)
res = proc.profiling_wrapper()

View File

@ -10,7 +10,6 @@ from jwt import PyJWKSet
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.crypto.builder import PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair
from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import OAuth2Provider
@ -83,7 +82,7 @@ class TestJWKS(OAuthTestCase):
client_id="test",
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
signing_key=create_test_cert(use_ec_private_key=True),
)
app = Application.objects.create(name="test", slug="test", provider=provider)
response = self.client.get(

View File

@ -1,44 +0,0 @@
# Generated by Django 5.0.4 on 2024-05-01 15:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_saml", "0013_samlprovider_default_relay_state"),
]
operations = [
migrations.AlterField(
model_name="samlprovider",
name="digest_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#sha1", "SHA1"),
("http://www.w3.org/2001/04/xmlenc#sha256", "SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#sha384", "SHA384"),
("http://www.w3.org/2001/04/xmlenc#sha512", "SHA512"),
],
default="http://www.w3.org/2001/04/xmlenc#sha256",
),
),
migrations.AlterField(
model_name="samlprovider",
name="signature_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#rsa-sha1", "RSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "RSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "RSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "RSA-SHA512"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1", "ECDSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", "ECDSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", "ECDSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", "ECDSA-SHA512"),
("http://www.w3.org/2000/09/xmldsig#dsa-sha1", "DSA-SHA1"),
],
default="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
),
),
]

View File

@ -11,10 +11,6 @@ from authentik.crypto.models import CertificateKeyPair
from authentik.lib.utils.time import timedelta_string_validator
from authentik.sources.saml.processors.constants import (
DSA_SHA1,
ECDSA_SHA1,
ECDSA_SHA256,
ECDSA_SHA384,
ECDSA_SHA512,
RSA_SHA1,
RSA_SHA256,
RSA_SHA384,
@ -96,7 +92,8 @@ class SAMLProvider(Provider):
),
)
digest_algorithm = models.TextField(
digest_algorithm = models.CharField(
max_length=50,
choices=(
(SHA1, _("SHA1")),
(SHA256, _("SHA256")),
@ -105,16 +102,13 @@ class SAMLProvider(Provider):
),
default=SHA256,
)
signature_algorithm = models.TextField(
signature_algorithm = models.CharField(
max_length=50,
choices=(
(RSA_SHA1, _("RSA-SHA1")),
(RSA_SHA256, _("RSA-SHA256")),
(RSA_SHA384, _("RSA-SHA384")),
(RSA_SHA512, _("RSA-SHA512")),
(ECDSA_SHA1, _("ECDSA-SHA1")),
(ECDSA_SHA256, _("ECDSA-SHA256")),
(ECDSA_SHA384, _("ECDSA-SHA384")),
(ECDSA_SHA512, _("ECDSA-SHA512")),
(DSA_SHA1, _("DSA-SHA1")),
),
default=RSA_SHA256,

View File

@ -7,14 +7,13 @@ from lxml import etree # nosec
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.crypto.builder import PrivateKeyAlg
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import load_fixture
from authentik.lib.xml import lxml_from_string
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.metadata import MetadataProcessor
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
from authentik.sources.saml.processors.constants import NS_MAP, NS_SAML_METADATA
class TestServiceProviderMetadataParser(TestCase):
@ -108,41 +107,12 @@ class TestServiceProviderMetadataParser(TestCase):
load_fixture("fixtures/cert.xml").replace("/apps/user_saml", "")
)
def test_signature_rsa(self):
"""Test signature validation (RSA)"""
def test_signature(self):
"""Test signature validation"""
provider = SAMLProvider.objects.create(
name=generate_id(),
authorization_flow=self.flow,
signing_kp=create_test_cert(PrivateKeyAlg.RSA),
)
Application.objects.create(
name=generate_id(),
slug=generate_id(),
provider=provider,
)
request = self.factory.get("/")
metadata = MetadataProcessor(provider, request).build_entity_descriptor()
root = fromstring(metadata.encode())
xmlsec.tree.add_ids(root, ["ID"])
signature_nodes = root.xpath("/md:EntityDescriptor/ds:Signature", namespaces=NS_MAP)
signature_node = signature_nodes[0]
ctx = xmlsec.SignatureContext()
key = xmlsec.Key.from_memory(
provider.signing_kp.certificate_data,
xmlsec.constants.KeyDataFormatCertPem,
None,
)
ctx.key = key
ctx.verify(signature_node)
def test_signature_ecdsa(self):
"""Test signature validation (ECDSA)"""
provider = SAMLProvider.objects.create(
name=generate_id(),
authorization_flow=self.flow,
signing_kp=create_test_cert(PrivateKeyAlg.ECDSA),
signature_algorithm=ECDSA_SHA256,
signing_kp=create_test_cert(),
)
Application.objects.create(
name=generate_id(),

View File

@ -3,7 +3,7 @@
from structlog.stdlib import get_logger
from authentik.providers.scim.models import SCIMProvider
from authentik.providers.scim.tasks import scim_task_wrapper
from authentik.providers.scim.tasks import scim_sync
from authentik.tenants.management import TenantCommand
LOGGER = get_logger()
@ -21,4 +21,4 @@ class Command(TenantCommand):
if not provider:
LOGGER.warning("Provider does not exist", name=provider_name)
continue
scim_task_wrapper(provider.pk).get()
scim_sync.delay(provider.pk).get()

View File

@ -9,7 +9,7 @@ from structlog.stdlib import get_logger
from authentik.core.models import Group, User
from authentik.lib.utils.reflection import class_to_path
from authentik.providers.scim.models import SCIMProvider
from authentik.providers.scim.tasks import scim_signal_direct, scim_signal_m2m, scim_task_wrapper
from authentik.providers.scim.tasks import scim_signal_direct, scim_signal_m2m, scim_sync
LOGGER = get_logger()
@ -17,7 +17,7 @@ LOGGER = get_logger()
@receiver(post_save, sender=SCIMProvider)
def post_save_provider(sender: type[Model], instance, created: bool, **_):
"""Trigger sync when SCIM provider is saved"""
scim_task_wrapper(instance.pk)
scim_sync.delay(instance.pk)
@receiver(post_save, sender=User)

View File

@ -38,23 +38,7 @@ def client_for_model(provider: SCIMProvider, model: Model) -> SCIMClient:
def scim_sync_all():
"""Run sync for all providers"""
for provider in SCIMProvider.objects.filter(backchannel_application__isnull=False):
scim_task_wrapper(provider.pk)
def scim_task_wrapper(provider_pk: int):
"""Wrap scim_sync to set the correct timeouts"""
provider: SCIMProvider = SCIMProvider.objects.filter(
pk=provider_pk, backchannel_application__isnull=False
).first()
if not provider:
return
users_paginator = Paginator(provider.get_user_qs(), PAGE_SIZE)
groups_paginator = Paginator(provider.get_group_qs(), PAGE_SIZE)
soft_time_limit = (users_paginator.num_pages + groups_paginator.num_pages) * PAGE_TIMEOUT
time_limit = soft_time_limit * 1.5
return scim_sync.apply_async(
(provider.pk,), time_limit=int(time_limit), soft_time_limit=int(soft_time_limit)
)
scim_sync.delay(provider.pk)
@CELERY_APP.task(bind=True, base=SystemTask)
@ -76,7 +60,7 @@ def scim_sync(self: SystemTask, provider_pk: int) -> None:
users_paginator = Paginator(provider.get_user_qs(), PAGE_SIZE)
groups_paginator = Paginator(provider.get_group_qs(), PAGE_SIZE)
self.soft_time_limit = self.time_limit = (
users_paginator.num_pages + groups_paginator.num_pages
users_paginator.count + groups_paginator.count
) * PAGE_TIMEOUT
with allow_join_result():
try:

View File

@ -8,7 +8,7 @@ from authentik.core.models import Application, Group, User
from authentik.lib.generators import generate_id
from authentik.providers.scim.clients.schema import ServiceProviderConfiguration
from authentik.providers.scim.models import SCIMMapping, SCIMProvider
from authentik.providers.scim.tasks import scim_task_wrapper
from authentik.providers.scim.tasks import scim_sync
from authentik.tenants.models import Tenant
@ -79,7 +79,7 @@ class SCIMMembershipTests(TestCase):
)
self.configure()
scim_task_wrapper(self.provider.pk).get()
scim_sync.delay(self.provider.pk).get()
self.assertEqual(mocker.call_count, 6)
self.assertEqual(mocker.request_history[0].method, "GET")
@ -169,7 +169,7 @@ class SCIMMembershipTests(TestCase):
)
self.configure()
scim_task_wrapper(self.provider.pk).get()
scim_sync.delay(self.provider.pk).get()
self.assertEqual(mocker.call_count, 6)
self.assertEqual(mocker.request_history[0].method, "GET")

View File

@ -10,7 +10,7 @@ from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application, Group, User
from authentik.lib.generators import generate_id
from authentik.providers.scim.models import SCIMMapping, SCIMProvider
from authentik.providers.scim.tasks import scim_task_wrapper
from authentik.providers.scim.tasks import scim_sync
from authentik.tenants.models import Tenant
@ -236,7 +236,7 @@ class SCIMUserTests(TestCase):
email=f"{uid}@goauthentik.io",
)
scim_task_wrapper(self.provider.pk).get()
scim_sync.delay(self.provider.pk).get()
self.assertEqual(mock.call_count, 5)
self.assertEqual(mock.request_history[0].method, "GET")

View File

@ -1,44 +0,0 @@
# Generated by Django 5.0.4 on 2024-05-01 15:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_saml", "0013_samlsource_verification_kp_and_more"),
]
operations = [
migrations.AlterField(
model_name="samlsource",
name="digest_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#sha1", "SHA1"),
("http://www.w3.org/2001/04/xmlenc#sha256", "SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#sha384", "SHA384"),
("http://www.w3.org/2001/04/xmlenc#sha512", "SHA512"),
],
default="http://www.w3.org/2001/04/xmlenc#sha256",
),
),
migrations.AlterField(
model_name="samlsource",
name="signature_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#rsa-sha1", "RSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "RSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "RSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "RSA-SHA512"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1", "ECDSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", "ECDSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", "ECDSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", "ECDSA-SHA512"),
("http://www.w3.org/2000/09/xmldsig#dsa-sha1", "DSA-SHA1"),
],
default="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
),
),
]

View File

@ -15,10 +15,6 @@ from authentik.flows.models import Flow
from authentik.lib.utils.time import timedelta_string_validator
from authentik.sources.saml.processors.constants import (
DSA_SHA1,
ECDSA_SHA1,
ECDSA_SHA256,
ECDSA_SHA384,
ECDSA_SHA512,
RSA_SHA1,
RSA_SHA256,
RSA_SHA384,
@ -147,7 +143,8 @@ class SAMLSource(Source):
verbose_name=_("Signing Keypair"),
)
digest_algorithm = models.TextField(
digest_algorithm = models.CharField(
max_length=50,
choices=(
(SHA1, _("SHA1")),
(SHA256, _("SHA256")),
@ -156,16 +153,13 @@ class SAMLSource(Source):
),
default=SHA256,
)
signature_algorithm = models.TextField(
signature_algorithm = models.CharField(
max_length=50,
choices=(
(RSA_SHA1, _("RSA-SHA1")),
(RSA_SHA256, _("RSA-SHA256")),
(RSA_SHA384, _("RSA-SHA384")),
(RSA_SHA512, _("RSA-SHA512")),
(ECDSA_SHA1, _("ECDSA-SHA1")),
(ECDSA_SHA256, _("ECDSA-SHA256")),
(ECDSA_SHA384, _("ECDSA-SHA384")),
(ECDSA_SHA512, _("ECDSA-SHA512")),
(DSA_SHA1, _("DSA-SHA1")),
),
default=RSA_SHA256,

View File

@ -26,16 +26,9 @@ SAML_BINDING_REDIRECT = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
# https://datatracker.ietf.org/doc/html/rfc4051#section-2.3.2
RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
# https://datatracker.ietf.org/doc/html/rfc4051#section-2.3.6
ECDSA_SHA1 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"
ECDSA_SHA224 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224"
ECDSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"
ECDSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"
ECDSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"
SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256"
@ -48,11 +41,6 @@ SIGN_ALGORITHM_TRANSFORM_MAP = {
RSA_SHA256: xmlsec.constants.TransformRsaSha256,
RSA_SHA384: xmlsec.constants.TransformRsaSha384,
RSA_SHA512: xmlsec.constants.TransformRsaSha512,
ECDSA_SHA1: xmlsec.constants.TransformEcdsaSha1,
ECDSA_SHA224: xmlsec.constants.TransformEcdsaSha224,
ECDSA_SHA256: xmlsec.constants.TransformEcdsaSha256,
ECDSA_SHA384: xmlsec.constants.TransformEcdsaSha384,
ECDSA_SHA512: xmlsec.constants.TransformEcdsaSha512,
}
DIGEST_ALGORITHM_TRANSLATION_MAP = {

File diff suppressed because one or more lines are too long

View File

@ -1,23 +0,0 @@
# Generated by Django 5.0.4 on 2024-05-01 15:32
import authentik.lib.utils.time
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_tenants", "0002_tenant_default_token_duration_and_more"),
]
operations = [
migrations.AlterField(
model_name="tenant",
name="default_token_duration",
field=models.TextField(
default="days=1",
help_text="Default token duration",
validators=[authentik.lib.utils.time.timedelta_string_validator],
),
),
]

View File

@ -85,30 +85,19 @@ entries:
model: authentik_stages_prompt.prompt
- attrs:
expression: |
from authentik.core.models import (
USER_ATTRIBUTE_CHANGE_EMAIL,
USER_ATTRIBUTE_CHANGE_NAME,
USER_ATTRIBUTE_CHANGE_USERNAME
)
prompt_data = request.context.get("prompt_data")
if not request.user.group_attributes(request.http_request).get(
USER_ATTRIBUTE_CHANGE_EMAIL, request.http_request.tenant.default_user_change_email
):
user_group_attributes = request.user.group_attributes(request.http_request)
if not user_group_attributes.get(USER_ATTRIBUTE_CHANGE_EMAIL, request.http_request.tenant.default_user_change_email):
if prompt_data.get("email") != request.user.email:
ak_message("Not allowed to change email address.")
return False
if not request.user.group_attributes(request.http_request).get(
USER_ATTRIBUTE_CHANGE_NAME, request.http_request.tenant.default_user_change_name
):
if not user_group_attributes.get(USER_ATTRIBUTE_CHANGE_NAME, request.http_request.tenant.default_user_change_name):
if prompt_data.get("name") != request.user.name:
ak_message("Not allowed to change name.")
return False
if not request.user.group_attributes(request.http_request).get(
USER_ATTRIBUTE_CHANGE_USERNAME, request.http_request.tenant.default_user_change_username
):
if not user_group_attributes.get(USER_ATTRIBUTE_CHANGE_USERNAME, request.http_request.tenant.default_user_change_username):
if prompt_data.get("username") != request.user.username:
ak_message("Not allowed to change username.")
return False

View File

@ -89,10 +89,9 @@ entries:
expression: |
# This policy ensures that the setup flow can only be
# used one time
from authentik.flows.models import Flow, FlowAuthenticationRequirement
Flow.objects.filter(slug="initial-setup").update(
authentication=FlowAuthenticationRequirement.REQUIRE_SUPERUSER,
)
FlowsApi(api).flows_instances_partial_update("initial-setup", {
"authentication": "REQUIRE_SUPERUSER"
})
return True
id: policy-default-oobe-flow-set-authentication
identifiers:

View File

@ -3477,6 +3477,10 @@
"type": "string",
"minLength": 1,
"title": "Expression"
},
"execution_user": {
"type": "integer",
"title": "Execution user"
}
},
"required": []
@ -4131,10 +4135,6 @@
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
"http://www.w3.org/2000/09/xmldsig#dsa-sha1"
],
"title": "Signature algorithm"
@ -4939,10 +4939,6 @@
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
"http://www.w3.org/2000/09/xmldsig#dsa-sha1"
],
"title": "Signature algorithm"

2
go.mod
View File

@ -28,7 +28,7 @@ require (
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.9.0
github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2024041.2
goauthentik.io/api/v3 v3.2024041.1
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.19.0
golang.org/x/sync v0.7.0

4
go.sum
View File

@ -294,8 +294,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
goauthentik.io/api/v3 v3.2024041.2 h1:gbquIA8RU+9jJbFdGckQTtJzOfWVp2+QdF4LuNVTAWM=
goauthentik.io/api/v3 v3.2024041.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
goauthentik.io/api/v3 v3.2024041.1 h1:oYj6DYqmZJd6/wyknBZLnLa+4+ShT4ry7HQn0W8VXxY=
goauthentik.io/api/v3 v3.2024041.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=

View File

@ -117,8 +117,6 @@ def run_migrations():
)
finally:
release_lock(curr)
curr.close()
conn.close()
if __name__ == "__main__":

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-05-03 00:08+0000\n"
"POT-Creation-Date: 2024-04-16 00:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -363,14 +363,6 @@ msgstr ""
msgid "Subject-alt name"
msgstr ""
#: authentik/crypto/builder.py
msgid "rsa"
msgstr ""
#: authentik/crypto/builder.py
msgid "ecdsa"
msgstr ""
#: authentik/crypto/models.py
msgid "PEM-encoded Certificate data"
msgstr ""
@ -1557,22 +1549,6 @@ msgstr ""
msgid "RSA-SHA512"
msgstr ""
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "ECDSA-SHA1"
msgstr ""
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "ECDSA-SHA256"
msgstr ""
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "ECDSA-SHA384"
msgstr ""
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "ECDSA-SHA512"
msgstr ""
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "DSA-SHA1"
msgstr ""

1954
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Stage 1: Build website
FROM --platform=${BUILDPLATFORM} docker.io/node:22 as web-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as web-builder
ENV NODE_ENV=production
WORKDIR /static

View File

@ -83,13 +83,13 @@ filterwarnings = [
]
[tool.poetry.dependencies]
authentik_client = "2024.4.1.post1714149882"
argon2-cffi = "*"
celery = "*"
channels = { version = "*", extras = ["daphne"] }
channels-redis = "*"
codespell = "*"
colorama = "*"
cryptography = "*"
dacite = "*"
deepmerge = "*"
defusedxml = "*"
@ -102,7 +102,7 @@ django-redis = "*"
django-storages = { extras = ["s3"], version = "*" }
# See https://github.com/django-tenants/django-tenants/pull/997
django-tenants = { git = "https://github.com/rissson/django-tenants.git", branch="authentik-fixes" }
djangorestframework = "3.14.0"
djangorestframework = "*"
djangorestframework-guardian = "*"
docker = "*"
drf-spectacular = "*"
@ -116,17 +116,24 @@ gunicorn = "*"
jsonpatch = "*"
kubernetes = "*"
ldap3 = "*"
lxml = "*"
lxml = [
# 5.0.0 works with libxml2 2.11.x, which is standard on brew
{ version = "5.0.0", platform = "darwin" },
# 4.9.x works with previous libxml2 versions, which is what we get on linux
{ version = "4.9.4", platform = "linux" },
]
opencontainers = { extras = ["reggie"], version = "*" }
packaging = "*"
paramiko = "*"
psycopg = { extras = ["c"], version = "*" }
pycryptodome = "*"
pydantic = "*"
pydantic-scim = "*"
pyjwt = "*"
python = "~3.12"
pyyaml = "*"
requests-oauthlib = "*"
restrictedpython = "*"
scim2-filter-parser = "*"
sentry-sdk = "*"
service_identity = "*"

View File

@ -18,7 +18,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
go build -o /go/rac ./cmd/rac
# Stage 2: Run
FROM ghcr.io/beryju/guacd:1.5.5
FROM ghcr.io/beryju/guacd:1.5.3
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH

View File

@ -11852,6 +11852,10 @@ paths:
name: execution_logging
schema:
type: boolean
- in: query
name: execution_user
schema:
type: integer
- in: query
name: expression
schema:
@ -17051,10 +17055,6 @@ paths:
enum:
- http://www.w3.org/2000/09/xmldsig#dsa-sha1
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
@ -20914,10 +20914,6 @@ paths:
enum:
- http://www.w3.org/2000/09/xmldsig#dsa-sha1
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
@ -30458,11 +30454,6 @@ components:
- pending_user
- pending_user_avatar
- type
AlgEnum:
enum:
- rsa
- ecdsa
type: string
App:
type: object
description: Serialize Application info
@ -32120,10 +32111,6 @@ components:
type: string
validity_days:
type: integer
alg:
allOf:
- $ref: '#/components/schemas/AlgEnum'
default: rsa
required:
- common_name
- validity_days
@ -33582,6 +33569,9 @@ components:
readOnly: true
expression:
type: string
execution_user:
type: integer
nullable: true
required:
- bound_to
- component
@ -33605,6 +33595,9 @@ components:
expression:
type: string
minLength: 1
execution_user:
type: integer
nullable: true
required:
- expression
- name
@ -38858,6 +38851,9 @@ components:
expression:
type: string
minLength: 1
execution_user:
type: integer
nullable: true
PatchedFlowRequest:
type: object
description: Flow Serializer
@ -43675,10 +43671,6 @@ components:
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2000/09/xmldsig#dsa-sha1
type: string
Source:

File diff suppressed because it is too large Load Diff

405
web/package-lock.json generated
View File

@ -11,13 +11,13 @@
"dependencies": {
"@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.6",
"@codemirror/lang-python": "^6.1.5",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/legacy-modes": "^6.4.0",
"@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.2",
"@goauthentik/api": "^2024.4.1-1714655911",
"@goauthentik/api": "^2024.4.1-1714149838",
"@lit-labs/task": "^3.1.0",
"@lit/context": "^1.1.1",
"@lit/localize": "^0.12.1",
@ -25,7 +25,8 @@
"@open-wc/lit-helpers": "^0.7.0",
"@patternfly/elements": "^3.0.1",
"@patternfly/patternfly": "^4.224.2",
"@sentry/browser": "^7.113.0",
"@rollup/rollup-linux-x64-gnu": "4.17.0",
"@sentry/browser": "^7.112.2",
"@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1",
"chart.js": "^4.4.2",
@ -47,13 +48,13 @@
"yaml": "^2.4.2"
},
"devDependencies": {
"@babel/core": "^7.24.5",
"@babel/core": "^7.24.4",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.24.1",
"@babel/plugin-transform-private-methods": "^7.24.1",
"@babel/plugin-transform-private-property-in-object": "^7.24.5",
"@babel/plugin-transform-private-property-in-object": "^7.24.1",
"@babel/plugin-transform-runtime": "^7.24.3",
"@babel/preset-env": "^7.24.5",
"@babel/preset-env": "^7.24.4",
"@babel/preset-typescript": "^7.24.1",
"@hcaptcha/types": "^1.0.3",
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
@ -111,9 +112,9 @@
"@esbuild/darwin-arm64": "^0.20.1",
"@esbuild/linux-amd64": "^0.18.11",
"@esbuild/linux-arm64": "^0.20.1",
"@rollup/rollup-darwin-arm64": "4.17.2",
"@rollup/rollup-linux-arm64-gnu": "4.17.2",
"@rollup/rollup-linux-x64-gnu": "4.17.2"
"@rollup/rollup-darwin-arm64": "4.17.0",
"@rollup/rollup-linux-arm64-gnu": "4.17.0",
"@rollup/rollup-linux-x64-gnu": "4.17.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -185,21 +186,21 @@
}
},
"node_modules/@babel/core": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz",
"integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz",
"integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.2",
"@babel/generator": "^7.24.5",
"@babel/generator": "^7.24.4",
"@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-module-transforms": "^7.24.5",
"@babel/helpers": "^7.24.5",
"@babel/parser": "^7.24.5",
"@babel/helper-module-transforms": "^7.23.3",
"@babel/helpers": "^7.24.4",
"@babel/parser": "^7.24.4",
"@babel/template": "^7.24.0",
"@babel/traverse": "^7.24.5",
"@babel/types": "^7.24.5",
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@ -215,12 +216,12 @@
}
},
"node_modules/@babel/generator": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz",
"integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
"integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.24.5",
"@babel/types": "^7.24.0",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
@ -272,19 +273,19 @@
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz",
"integrity": "sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz",
"integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-member-expression-to-functions": "^7.24.5",
"@babel/helper-member-expression-to-functions": "^7.23.0",
"@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-replace-supers": "^7.24.1",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.24.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"semver": "^6.3.1"
},
"engines": {
@ -366,12 +367,13 @@
}
},
"node_modules/@babel/helper-member-expression-to-functions": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz",
"integrity": "sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
"integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.24.5"
"@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
@ -390,16 +392,17 @@
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz",
"integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-module-imports": "^7.24.3",
"@babel/helper-simple-access": "^7.24.5",
"@babel/helper-split-export-declaration": "^7.24.5",
"@babel/helper-validator-identifier": "^7.24.5"
"@babel/helper-module-imports": "^7.22.15",
"@babel/helper-simple-access": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/helper-validator-identifier": "^7.22.20"
},
"engines": {
"node": ">=6.9.0"
@ -422,10 +425,11 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
"integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
"version": "7.24.0",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@ -465,12 +469,13 @@
}
},
"node_modules/@babel/helper-simple-access": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz",
"integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
"integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.24.5"
"@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@ -490,31 +495,34 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
"integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.24.5"
"@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
"integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
"version": "7.23.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
"integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
"integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@ -544,14 +552,14 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz",
"integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
"integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==",
"dev": true,
"dependencies": {
"@babel/template": "^7.24.0",
"@babel/traverse": "^7.24.5",
"@babel/types": "^7.24.5"
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@ -573,9 +581,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
"integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
"integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@ -585,13 +593,13 @@
}
},
"node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz",
"integrity": "sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz",
"integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-plugin-utils": "^7.24.5"
"@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@ -1063,12 +1071,12 @@
}
},
"node_modules/@babel/plugin-transform-block-scoping": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz",
"integrity": "sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz",
"integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.5"
"@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@ -1111,18 +1119,18 @@
}
},
"node_modules/@babel/plugin-transform-classes": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz",
"integrity": "sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz",
"integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-plugin-utils": "^7.24.5",
"@babel/helper-plugin-utils": "^7.24.0",
"@babel/helper-replace-supers": "^7.24.1",
"@babel/helper-split-export-declaration": "^7.24.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"globals": "^11.1.0"
},
"engines": {
@ -1149,12 +1157,12 @@
}
},
"node_modules/@babel/plugin-transform-destructuring": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz",
"integrity": "sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz",
"integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.5"
"@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@ -1485,15 +1493,15 @@
}
},
"node_modules/@babel/plugin-transform-object-rest-spread": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz",
"integrity": "sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz",
"integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==",
"dev": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-plugin-utils": "^7.24.5",
"@babel/helper-plugin-utils": "^7.24.0",
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
"@babel/plugin-transform-parameters": "^7.24.5"
"@babel/plugin-transform-parameters": "^7.24.1"
},
"engines": {
"node": ">=6.9.0"
@ -1535,12 +1543,12 @@
}
},
"node_modules/@babel/plugin-transform-optional-chaining": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz",
"integrity": "sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz",
"integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.5",
"@babel/helper-plugin-utils": "^7.24.0",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
},
@ -1552,12 +1560,12 @@
}
},
"node_modules/@babel/plugin-transform-parameters": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz",
"integrity": "sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz",
"integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.5"
"@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@ -1583,14 +1591,14 @@
}
},
"node_modules/@babel/plugin-transform-private-property-in-object": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz",
"integrity": "sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz",
"integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-create-class-features-plugin": "^7.24.5",
"@babel/helper-plugin-utils": "^7.24.5",
"@babel/helper-create-class-features-plugin": "^7.24.1",
"@babel/helper-plugin-utils": "^7.24.0",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
},
"engines": {
@ -1728,12 +1736,12 @@
}
},
"node_modules/@babel/plugin-transform-typeof-symbol": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz",
"integrity": "sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz",
"integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.24.5"
"@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@ -1824,16 +1832,16 @@
}
},
"node_modules/@babel/preset-env": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.5.tgz",
"integrity": "sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==",
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz",
"integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==",
"dev": true,
"dependencies": {
"@babel/compat-data": "^7.24.4",
"@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-plugin-utils": "^7.24.5",
"@babel/helper-plugin-utils": "^7.24.0",
"@babel/helper-validator-option": "^7.23.5",
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.5",
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4",
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1",
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1",
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1",
@ -1860,12 +1868,12 @@
"@babel/plugin-transform-async-generator-functions": "^7.24.3",
"@babel/plugin-transform-async-to-generator": "^7.24.1",
"@babel/plugin-transform-block-scoped-functions": "^7.24.1",
"@babel/plugin-transform-block-scoping": "^7.24.5",
"@babel/plugin-transform-block-scoping": "^7.24.4",
"@babel/plugin-transform-class-properties": "^7.24.1",
"@babel/plugin-transform-class-static-block": "^7.24.4",
"@babel/plugin-transform-classes": "^7.24.5",
"@babel/plugin-transform-classes": "^7.24.1",
"@babel/plugin-transform-computed-properties": "^7.24.1",
"@babel/plugin-transform-destructuring": "^7.24.5",
"@babel/plugin-transform-destructuring": "^7.24.1",
"@babel/plugin-transform-dotall-regex": "^7.24.1",
"@babel/plugin-transform-duplicate-keys": "^7.24.1",
"@babel/plugin-transform-dynamic-import": "^7.24.1",
@ -1885,13 +1893,13 @@
"@babel/plugin-transform-new-target": "^7.24.1",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1",
"@babel/plugin-transform-numeric-separator": "^7.24.1",
"@babel/plugin-transform-object-rest-spread": "^7.24.5",
"@babel/plugin-transform-object-rest-spread": "^7.24.1",
"@babel/plugin-transform-object-super": "^7.24.1",
"@babel/plugin-transform-optional-catch-binding": "^7.24.1",
"@babel/plugin-transform-optional-chaining": "^7.24.5",
"@babel/plugin-transform-parameters": "^7.24.5",
"@babel/plugin-transform-optional-chaining": "^7.24.1",
"@babel/plugin-transform-parameters": "^7.24.1",
"@babel/plugin-transform-private-methods": "^7.24.1",
"@babel/plugin-transform-private-property-in-object": "^7.24.5",
"@babel/plugin-transform-private-property-in-object": "^7.24.1",
"@babel/plugin-transform-property-literals": "^7.24.1",
"@babel/plugin-transform-regenerator": "^7.24.1",
"@babel/plugin-transform-reserved-words": "^7.24.1",
@ -1899,7 +1907,7 @@
"@babel/plugin-transform-spread": "^7.24.1",
"@babel/plugin-transform-sticky-regex": "^7.24.1",
"@babel/plugin-transform-template-literals": "^7.24.1",
"@babel/plugin-transform-typeof-symbol": "^7.24.5",
"@babel/plugin-transform-typeof-symbol": "^7.24.1",
"@babel/plugin-transform-unicode-escapes": "^7.24.1",
"@babel/plugin-transform-unicode-property-regex": "^7.24.1",
"@babel/plugin-transform-unicode-regex": "^7.24.1",
@ -2155,19 +2163,19 @@
}
},
"node_modules/@babel/traverse": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz",
"integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==",
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
"integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.24.2",
"@babel/generator": "^7.24.5",
"@babel/code-frame": "^7.24.1",
"@babel/generator": "^7.24.1",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.24.5",
"@babel/parser": "^7.24.5",
"@babel/types": "^7.24.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.24.1",
"@babel/types": "^7.24.0",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@ -2176,13 +2184,14 @@
}
},
"node_modules/@babel/types": {
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
"integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
"version": "7.24.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.24.1",
"@babel/helper-validator-identifier": "^7.24.5",
"@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -2270,9 +2279,9 @@
}
},
"node_modules/@codemirror/lang-python": {
"version": "6.1.6",
"resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.6.tgz",
"integrity": "sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==",
"version": "6.1.5",
"resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.5.tgz",
"integrity": "sha512-hCm+8X6wrnXJCGf+QhmFu1AXkdTVG7dHy0Ly6SI1N3SRPptaMvwX6oNQonOXOMPvmcjiB0xq342KAxX3BYpijw==",
"dependencies": {
"@codemirror/autocomplete": "^6.3.2",
"@codemirror/language": "^6.8.0",
@ -2663,9 +2672,9 @@
}
},
"node_modules/@goauthentik/api": {
"version": "2024.4.1-1714655911",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.4.1-1714655911.tgz",
"integrity": "sha512-x7ViXuDh928e7B4dbQlOJXCtFnWJGGmOQcGI4IG6eWafUcq9+jgDnFrd0qqkDGcipqjKiY52B4RSdRNRxRsucA=="
"version": "2024.4.1-1714149838",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.4.1-1714149838.tgz",
"integrity": "sha512-Diat0nFTRm7gDb57d5KnKLYTumXKegT0ifpB2YdWSHioP9XQWdbIGQyL7+A1xcQdhVJo3vAbpiq0XI3J+gaHJg=="
},
"node_modules/@hcaptcha/types": {
"version": "1.0.3",
@ -4027,9 +4036,9 @@
"peer": true
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz",
"integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.0.tgz",
"integrity": "sha512-Oj6Tp0unMpGTBjvNwbSRv3DopMNLu+mjBzhKTt2zLbDJ/45fB1pltr/rqrO4bE95LzuYwhYn127pop+x/pzf5w==",
"cpu": [
"arm64"
],
@ -4067,9 +4076,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz",
"integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.0.tgz",
"integrity": "sha512-zL5rBFtJ+2EGnMRm2TqKjdjgFqlotSU+ZJEN37nV+fiD3I6Gy0dUh3jBWN0wSlcXVDEJYW7YBe+/2j0N9unb2w==",
"cpu": [
"arm64"
],
@ -4135,9 +4144,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz",
"integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.0.tgz",
"integrity": "sha512-v6eiam/1w3HUfU/ZjzIDodencqgrSqzlNuNtiwH7PFJHYSo1ezL0/UIzmS2lpSJF1ORNaplXeKHYmmdt81vV2g==",
"cpu": [
"x64"
],
@ -4203,83 +4212,83 @@
"peer": true
},
"node_modules/@sentry-internal/feedback": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.113.0.tgz",
"integrity": "sha512-eEmL8QXauUnM3FXGv0GT29RpL0Jo0pkn/uMu3aqjhQo7JKNqUGVYIUxJxiGWbVMbDXqPQ7L66bjjMS3FR1GM2g==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.112.2.tgz",
"integrity": "sha512-z+XP8BwB8B3pa+i8xqbrPsbtDWUFUS6wo+FJbmOYUqOusJJbVFDAhBoEdKoo5ZjOcsAZG7XR6cA9zrhJynIWBA==",
"dependencies": {
"@sentry/core": "7.113.0",
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0"
"@sentry/core": "7.112.2",
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.113.0.tgz",
"integrity": "sha512-K8uA42aobNF/BAXf14el15iSAi9fonLBUrjZi6nPDq7zaA8rPvfcTL797hwCbqkETz2zDf52Jz7I3WFCshDoUw==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.112.2.tgz",
"integrity": "sha512-BCCCxrZ1wJvN6La5gg1JJbKitAhJI5MATCnhtklsZbUcHkHB9iZoj19J65+P56gwssvHz5xh63AjNiITaetIRg==",
"dependencies": {
"@sentry/core": "7.113.0",
"@sentry/replay": "7.113.0",
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0"
"@sentry/core": "7.112.2",
"@sentry/replay": "7.112.2",
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry-internal/tracing": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.113.0.tgz",
"integrity": "sha512-8MDnYENRMnEfQjvN4gkFYFaaBSiMFSU/6SQZfY9pLI3V105z6JQ4D0PGMAUVowXilwNZVpKNYohE7XByuhEC7Q==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.112.2.tgz",
"integrity": "sha512-fT1Y46J4lfXZkgFkb03YMNeIEs2xS6jdKMoukMFQfRfVvL9fSWEbTgZpHPd/YTT8r2i082XzjtAoQNgklm/0Hw==",
"dependencies": {
"@sentry/core": "7.113.0",
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0"
"@sentry/core": "7.112.2",
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.113.0.tgz",
"integrity": "sha512-PdyVHPOprwoxGfKGsP2dXDWO0MBDW1eyP7EZlfZvM1A4hjk6ZRNfCv30g+TrqX4hiZDKzyqN3+AdP7N/J2IX0Q==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.112.2.tgz",
"integrity": "sha512-wULwavCch84+d0bueAdFm6CDm1u0TfOjN91VgY+sj/vxUV2vesvDgI8zRZfmbZEor3MYA90zerkZT3ehZQKbYw==",
"dependencies": {
"@sentry-internal/feedback": "7.113.0",
"@sentry-internal/replay-canvas": "7.113.0",
"@sentry-internal/tracing": "7.113.0",
"@sentry/core": "7.113.0",
"@sentry/integrations": "7.113.0",
"@sentry/replay": "7.113.0",
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0"
"@sentry-internal/feedback": "7.112.2",
"@sentry-internal/replay-canvas": "7.112.2",
"@sentry-internal/tracing": "7.112.2",
"@sentry/core": "7.112.2",
"@sentry/integrations": "7.112.2",
"@sentry/replay": "7.112.2",
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/core": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.113.0.tgz",
"integrity": "sha512-pg75y3C5PG2+ur27A0Re37YTCEnX0liiEU7EOxWDGutH17x3ySwlYqLQmZsFZTSnvzv7t3MGsNZ8nT5O0746YA==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.112.2.tgz",
"integrity": "sha512-gHPCcJobbMkk0VR18J65WYQTt3ED4qC6X9lHKp27Ddt63E+MDGkG6lvYBU1LS8cV7CdyBGC1XXDCfor61GvLsA==",
"dependencies": {
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0"
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/integrations": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.113.0.tgz",
"integrity": "sha512-w0sspGBQ+6+V/9bgCkpuM3CGwTYoQEVeTW6iNebFKbtN7MrM3XsGAM9I2cW1jVxFZROqCBPFtd2cs5n0j14aAg==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.112.2.tgz",
"integrity": "sha512-ioC2yyU6DqtLkdmWnm87oNvdn2+9oKctJeA4t+jkS6JaJ10DcezjCwiLscX4rhB9aWJV3IWF7Op0O6K3w0t2Hg==",
"dependencies": {
"@sentry/core": "7.113.0",
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0",
"@sentry/core": "7.112.2",
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2",
"localforage": "^1.8.1"
},
"engines": {
@ -4287,33 +4296,33 @@
}
},
"node_modules/@sentry/replay": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.113.0.tgz",
"integrity": "sha512-UD2IaphOWKFdeGR+ZiaNAQ+wFsnwbJK6PNwcW6cHmWKv9COlKufpFt06lviaqFZ8jmNrM4H+r+R8YVTrqCuxgg==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.112.2.tgz",
"integrity": "sha512-7Ns/8D54WPsht1nlVj93Inf6rXyve2AZoibYN0YfcM2w3lI4NO51gPPHJU0lFEfMwzwK4ZBJWzOeW9098a+uEg==",
"dependencies": {
"@sentry-internal/tracing": "7.113.0",
"@sentry/core": "7.113.0",
"@sentry/types": "7.113.0",
"@sentry/utils": "7.113.0"
"@sentry-internal/tracing": "7.112.2",
"@sentry/core": "7.112.2",
"@sentry/types": "7.112.2",
"@sentry/utils": "7.112.2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry/types": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.113.0.tgz",
"integrity": "sha512-PJbTbvkcPu/LuRwwXB1He8m+GjDDLKBtu3lWg5xOZaF5IRdXQU2xwtdXXsjge4PZR00tF7MO7X8ZynTgWbYaew==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.112.2.tgz",
"integrity": "sha512-kCMLt7yhY5OkWE9MeowlTNmox9pqDxcpvqguMo4BDNZM5+v9SEb1AauAdR78E1a1V8TyCzjBD7JDfXWhvpYBcQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/utils": {
"version": "7.113.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.113.0.tgz",
"integrity": "sha512-nzKsErwmze1mmEsbW2AwL2oB+I5v6cDEJY4sdfLekA4qZbYZ8pV5iWza6IRl4XfzGTE1qpkZmEjPU9eyo0yvYw==",
"version": "7.112.2",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.112.2.tgz",
"integrity": "sha512-OjLh0hx0t1EcL4ZIjf+4svlmmP+tHUDGcr5qpFWH78tjmkPW4+cqPuZCZfHSuWcDdeiaXi8TnYoVRqDcJKK/eQ==",
"dependencies": {
"@sentry/types": "7.113.0"
"@sentry/types": "7.112.2"
},
"engines": {
"node": ">=8"

View File

@ -14,8 +14,8 @@
"build": "run-s build-locales esbuild:build",
"build-proxy": "run-s build-locales esbuild:build-proxy",
"watch": "run-s build-locales esbuild:watch",
"lint": "cross-env NODE_OPTIONS='--max_old_space_size=65536' eslint . --max-warnings 0 --fix",
"lint:precommit": "cross-env NODE_OPTIONS='--max_old_space_size=65536' node scripts/eslint-precommit.mjs",
"lint": "cross-env NODE_OPTIONS='--max_old_space_size=16384' eslint . --max-warnings 0 --fix",
"lint:precommit": "cross-env NODE_OPTIONS='--max_old_space_size=16384' node scripts/eslint-precommit.mjs",
"lint:spelling": "node scripts/check-spelling.mjs",
"lit-analyse": "lit-analyzer src",
"precommit": "npm-run-all --parallel tsc lit-analyse lint:spelling --sequential lint:precommit prettier",
@ -32,13 +32,13 @@
"dependencies": {
"@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.6",
"@codemirror/lang-python": "^6.1.5",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/legacy-modes": "^6.4.0",
"@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.2",
"@goauthentik/api": "^2024.4.1-1714655911",
"@goauthentik/api": "^2024.4.1-1714149838",
"@lit-labs/task": "^3.1.0",
"@lit/context": "^1.1.1",
"@lit/localize": "^0.12.1",
@ -46,7 +46,7 @@
"@open-wc/lit-helpers": "^0.7.0",
"@patternfly/elements": "^3.0.1",
"@patternfly/patternfly": "^4.224.2",
"@sentry/browser": "^7.113.0",
"@sentry/browser": "^7.112.2",
"@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1",
"chart.js": "^4.4.2",
@ -68,13 +68,13 @@
"yaml": "^2.4.2"
},
"devDependencies": {
"@babel/core": "^7.24.5",
"@babel/core": "^7.24.4",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.24.1",
"@babel/plugin-transform-private-methods": "^7.24.1",
"@babel/plugin-transform-private-property-in-object": "^7.24.5",
"@babel/plugin-transform-private-property-in-object": "^7.24.1",
"@babel/plugin-transform-runtime": "^7.24.3",
"@babel/preset-env": "^7.24.5",
"@babel/preset-env": "^7.24.4",
"@babel/preset-typescript": "^7.24.1",
"@hcaptcha/types": "^1.0.3",
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
@ -129,9 +129,9 @@
"@esbuild/darwin-arm64": "^0.20.1",
"@esbuild/linux-amd64": "^0.18.11",
"@esbuild/linux-arm64": "^0.20.1",
"@rollup/rollup-darwin-arm64": "4.17.2",
"@rollup/rollup-linux-arm64-gnu": "4.17.2",
"@rollup/rollup-linux-x64-gnu": "4.17.2"
"@rollup/rollup-darwin-arm64": "4.17.0",
"@rollup/rollup-linux-arm64-gnu": "4.17.0",
"@rollup/rollup-linux-x64-gnu": "4.17.0"
},
"engines": {
"node": ">=20"

View File

@ -29,9 +29,5 @@ export const signatureAlgorithmOptions = toOptions([
["RSA-SHA256", SignatureAlgorithmEnum._200104XmldsigMorersaSha256, true],
["RSA-SHA384", SignatureAlgorithmEnum._200104XmldsigMorersaSha384],
["RSA-SHA512", SignatureAlgorithmEnum._200104XmldsigMorersaSha512],
["ECDSA-SHA1", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha1],
["ECDSA-SHA256", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha256],
["ECDSA-SHA384", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha384],
["ECDSA-SHA512", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha512],
["DSA-SHA1", SignatureAlgorithmEnum._200009XmldsigdsaSha1],
]);

View File

@ -6,12 +6,7 @@ import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js";
import {
AlgEnum,
CertificateGenerationRequest,
CertificateKeyPair,
CryptoApi,
} from "@goauthentik/api";
import { CertificateGenerationRequest, CertificateKeyPair, CryptoApi } from "@goauthentik/api";
@customElement("ak-crypto-certificate-generate-form")
export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
@ -45,29 +40,6 @@ export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
?required=${true}
>
<input class="pf-c-form-control" type="number" value="365" />
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Private key Algorithm")}
?required=${true}
name="alg"
>
<ak-radio
.options=${[
{
label: msg("RSA"),
value: AlgEnum.Rsa,
default: true,
},
{
label: msg("ECDSA"),
value: AlgEnum.Ecdsa,
},
]}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${msg("Algorithm used to generate the private key.")}
</p>
</ak-form-element-horizontal> `;
</ak-form-element-horizontal>`;
}
}

View File

@ -12,7 +12,13 @@ import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { ExpressionPolicy, PoliciesApi } from "@goauthentik/api";
import {
CoreApi,
CoreUsersListRequest,
ExpressionPolicy,
PoliciesApi,
User,
} from "@goauthentik/api";
@customElement("ak-policy-expression-form")
export class ExpressionPolicyForm extends BasePolicyForm<ExpressionPolicy> {
@ -92,6 +98,39 @@ export class ExpressionPolicyForm extends BasePolicyForm<ExpressionPolicy> {
</a>
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Execution user")} name="executionUser">
<ak-search-select
.fetchObjects=${async (query?: string): Promise<User[]> => {
const args: CoreUsersListRequest = {
ordering: "username",
};
if (query !== undefined) {
args.search = query;
}
const users = await new CoreApi(DEFAULT_CONFIG).coreUsersList(args);
return users.results;
}}
.renderElement=${(user: User): string => {
return user.username;
}}
.renderDescription=${(user: User): TemplateResult => {
return html`${user.name}`;
}}
.value=${(user: User | undefined): number | undefined => {
return user?.pk;
}}
.selected=${(user: User): boolean => {
return this.instance?.executionUser === user.pk;
}}
blankable
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${msg(
"Configure which user the bundled API client authenticates as. When left empty, the API client will inherit the permissions of the user triggering the policy execution.",
)}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>`;
}

View File

@ -44,7 +44,7 @@ export function docLink(path: string): string {
const ak = globalAK();
// Default case or beta build which should always point to latest
if (!ak || ak.build !== "") {
return `https://goauthentik.io${path}`;
return `https://docs.goauthentik.io${path}`;
}
return `https://${ak.versionSubdomain}.goauthentik.io${path}`;
}

View File

@ -12,8 +12,4 @@ export const authentikEnterpriseContext = createContext<LicenseSummary>(
export const authentikBrandContext = createContext<CurrentBrand>(Symbol("authentik-brand-context"));
export const authentikLocalStoreContext = createContext<unknown>(
Symbol("authentik-local-store-context"),
);
export default authentikConfigContext;

View File

@ -1,31 +0,0 @@
type TryFn<T> = () => T;
type CatchFn<T> = (error: unknown) => T;
type TryCatchArgs<T> = {
tryFn: TryFn<T>;
catchFn?: CatchFn<T>;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isTryCatchArgs = <T>(t: any): t is TryCatchArgs<T> =>
typeof t === "object" && "tryFn" in t && "catchFn" in t;
export function tryCatch<T>({ tryFn, catchFn }: TryCatchArgs<T>): T;
export function tryCatch<T>(tryFn: TryFn<T>): T;
export function tryCatch<T>(tryFn: TryFn<T>, catchFn: CatchFn<T>): T;
export function tryCatch<T>(tryFn: TryFn<T> | TryCatchArgs<T>, catchFn?: CatchFn<T>): T {
if (isTryCatchArgs(tryFn)) {
catchFn = tryFn.catchFn;
tryFn = tryFn.tryFn;
}
if (catchFn === undefined) {
catchFn = () => null as T;
}
try {
return tryFn();
} catch (error) {
return catchFn(error);
}
}

View File

@ -8,7 +8,7 @@ import "@goauthentik/elements/EmptyState";
import { BaseStage } from "@goauthentik/flow/stages/base";
import { msg, str } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, css, html, nothing } from "lit";
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@ -115,16 +115,14 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
});
}
updated(changedProperties: PropertyValues<this>) {
if (changedProperties.has("challenge") && this.challenge !== undefined) {
// convert certain members of the PublicKeyCredentialCreateOptions into
// byte arrays as expected by the spec.
this.publicKeyCredentialCreateOptions = transformCredentialCreateOptions(
this.challenge?.registration as PublicKeyCredentialCreationOptions,
this.challenge?.registration.user.id,
);
this.registerWrapper();
}
firstUpdated(): void {
// convert certain members of the PublicKeyCredentialCreateOptions into
// byte arrays as expected by the spec.
this.publicKeyCredentialCreateOptions = transformCredentialCreateOptions(
this.challenge?.registration as PublicKeyCredentialCreationOptions,
this.challenge?.registration.user.id,
);
this.registerWrapper();
}
render(): TemplateResult {

View File

@ -1,95 +0,0 @@
import { LayoutType } from "@goauthentik/common/ui/config";
import { AKElement } from "@goauthentik/elements/Base";
import { css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import type { Application } from "@goauthentik/api";
import type { AppGroupEntry, AppGroupList } from "./types";
type Pair = [string, string];
// prettier-ignore
const LAYOUTS = new Map<string, [string, string]>([
[
"row",
["pf-m-12-col", "pf-m-all-6-col-on-sm pf-m-all-4-col-on-md pf-m-all-5-col-on-lg pf-m-all-2-col-on-xl"]],
[
"2-column",
["pf-m-6-col", "pf-m-all-12-col-on-sm pf-m-all-12-col-on-md pf-m-all-4-col-on-lg pf-m-all-4-col-on-xl"],
],
[
"3-column",
["pf-m-4-col", "pf-m-all-12-col-on-sm pf-m-all-12-col-on-md pf-m-all-6-col-on-lg pf-m-all-6-col-on-xl"],
],
]);
@customElement("ak-library-application-cards")
export class LibraryPageApplicationCards extends AKElement {
static get styles() {
return [
PFBase,
PFEmptyState,
PFContent,
PFGrid,
css`
.app-group-header {
margin-bottom: 1em;
margin-top: 1.2em;
}
`,
];
}
@property({ attribute: true })
layout = "row" as LayoutType;
@property({ attribute: true })
background: string | undefined = undefined;
@property({ attribute: true })
selected = "";
@property({ attribute: false })
apps: AppGroupList = [];
get currentLayout(): Pair {
const layout = LAYOUTS.get(this.layout);
if (!layout) {
console.warn(`Unrecognized layout: ${this.layout || "-undefined-"}`);
return LAYOUTS.get("row") as Pair;
}
return layout;
}
render() {
const [groupClass, groupGrid] = this.currentLayout;
return html`<div class="pf-l-grid pf-m-gutter">
${this.apps.map(([group, apps]: AppGroupEntry) => {
return html`<div class="pf-l-grid__item ${groupClass}">
<div class="pf-c-content app-group-header">
<h2>${group}</h2>
</div>
<div class="pf-l-grid pf-m-gutter ${groupGrid}">
${apps.map((app: Application) => {
return html`<ak-library-app
class="pf-l-grid__item"
.application=${app}
background=${ifDefined(this.background)}
?selected=${app.slug === this.selected}
></ak-library-app>`;
})}
</div>
</div> `;
})}
</div>`;
}
}

View File

@ -1,34 +1,48 @@
import { PFSize } from "@goauthentik/common/enums.js";
import { LayoutType } from "@goauthentik/common/ui/config";
import { AKElement, rootInterface } from "@goauthentik/elements/Base";
import { UserInterface } from "@goauthentik/user/UserInterface";
import { AKElement } from "@goauthentik/elements/Base";
import { msg } from "@lit/localize";
import { css, html, nothing } from "lit";
import { css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";
import PFTable from "@patternfly/patternfly/components/Table/table.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import type { Application } from "@goauthentik/api";
import type { AppGroupEntry, AppGroupList } from "./types";
type Pair = [string, string];
// prettier-ignore
const LAYOUTS = new Map<string, [string, string]>([
[
"row",
["pf-m-12-col", "pf-m-all-6-col-on-sm pf-m-all-4-col-on-md pf-m-all-5-col-on-lg pf-m-all-2-col-on-xl"]],
[
"2-column",
["pf-m-6-col", "pf-m-all-12-col-on-sm pf-m-all-12-col-on-md pf-m-all-4-col-on-lg pf-m-all-4-col-on-xl"],
],
[
"3-column",
["pf-m-4-col", "pf-m-all-12-col-on-sm pf-m-all-12-col-on-md pf-m-all-6-col-on-lg pf-m-all-6-col-on-xl"],
],
]);
@customElement("ak-library-application-list")
export class LibraryPageApplicationList extends AKElement {
static get styles() {
return [
PFBase,
PFTable,
PFButton,
PFEmptyState,
PFContent,
PFGrid,
css`
.app-row a {
font-weight: bold;
.app-group-header {
margin-bottom: 1em;
margin-top: 1.2em;
}
`,
];
@ -46,110 +60,36 @@ export class LibraryPageApplicationList extends AKElement {
@property({ attribute: false })
apps: AppGroupList = [];
expanded = new Set<string>();
get currentLayout(): Pair {
const layout = LAYOUTS.get(this.layout);
if (!layout) {
console.warn(`Unrecognized layout: ${this.layout || "-undefined-"}`);
return LAYOUTS.get("row") as Pair;
}
return layout;
}
render() {
const me = rootInterface<UserInterface>()?.me;
const canEdit =
rootInterface()?.uiConfig?.enabledFeatures.applicationEdit && me?.user.isSuperuser;
const [groupClass, groupGrid] = this.currentLayout;
const toggleExpansion = (pk: string) => {
if (this.expanded.has(pk)) {
this.expanded.delete(pk);
} else {
this.expanded.add(pk);
}
this.requestUpdate();
};
const expandedClass = (pk: string) => ({
"pf-m-expanded": this.expanded.has(pk),
});
const renderExpansionCell = (app: Application) =>
app.metaDescription
? html`<td class="pf-c-table__toggle" role="cell">
<button
class="pf-c-button pf-m-plain ${classMap(expandedClass(app.pk))}"
@click=${() => toggleExpansion(app.pk)}
>
<div class="pf-c-table__toggle-icon">
&nbsp;<i class="fas fa-angle-down" aria-hidden="true"></i>&nbsp;
</div>
</button>
</td>`
: nothing;
const renderAppIcon = (app: Application) =>
html`<a
href="${ifDefined(app.launchUrl ?? "")}"
target="${ifDefined(app.openInNewTab ? "_blank" : undefined)}"
>
<ak-app-icon size=${PFSize.Small} .app=${app}></ak-app-icon>
</a>`;
const renderAppUrl = (app: Application) =>
app.launchUrl === "goauthentik.io://providers/rac/launch"
? html`<ak-library-rac-endpoint-launch .app=${app}>
<a slot="trigger"> ${app.name} </a>
</ak-library-rac-endpoint-launch>`
: html`<a
href="${ifDefined(app.launchUrl ?? "")}"
target="${ifDefined(app.openInNewTab ? "_blank" : undefined)}"
>${app.name}</a
>`;
const renderAppDescription = (app: Application) =>
app.metaDescription
? html` <tr
class="pf-c-table__expandable-row ${classMap(expandedClass(app.pk))}"
role="row"
>
<td></td>
<td></td>
<td colspan="3">${app.metaDescription}</td>
</tr>`
: nothing;
const renderGroup = ([group, apps]: AppGroupEntry) => html`
${group
? html`<tr>
<td colspan="5"><h2>${group}</h2></td>
</tr>`
: nothing}
${apps.map(
(app: Application) =>
html`<tr>
<td>${renderExpansionCell(app)}</td>
<td>${renderAppIcon(app)}</td>
<td class="app-row">${renderAppUrl(app)}</td>
<td>${app.metaPublisher ?? ""}</td>
<td>
<a
class="pf-c-button pf-m-control pf-m-small pf-m-block"
href="/if/admin/#/core/applications/${app?.slug}"
>
<i class="fas fa-edit"></i>&nbsp;${msg("Edit")}
</a>
</td>
</tr>
${this.expanded.has(app.pk) ? renderAppDescription(app) : nothing} `,
)}
`;
return html`<table class="pf-c-table pf-m-compact pf-m-grid-sm pf-m-expandable">
<thead>
<tr role="row">
<th></th>
<th></th>
<th>${msg("Application")}</th>
<th>${msg("Publisher")}</th>
${canEdit ? html`<th>${msg("Edit")}</th>` : nothing}
</tr>
</thead>
<tbody>
${this.apps.map(renderGroup)}
</tbody>
</table> `;
return html`<div class="pf-l-grid pf-m-gutter">
${this.apps.map(([group, apps]: AppGroupEntry) => {
return html`<div class="pf-l-grid__item ${groupClass}">
<div class="pf-c-content app-group-header">
<h2>${group}</h2>
</div>
<div class="pf-l-grid pf-m-gutter ${groupGrid}">
${apps.map((app: Application) => {
return html`<ak-library-app
class="pf-l-grid__item"
.application=${app}
background=${ifDefined(this.background)}
?selected=${app.slug === this.selected}
></ak-library-app>`;
})}
</div>
</div> `;
})}
</div>`;
}
}

View File

@ -34,30 +34,6 @@ export const styles = [PFBase, PFDisplay, PFEmptyState, PFPage, PFContent].conca
.pf-c-page__main-section {
background-color: transparent;
}
#library-page-title {
display: flex;
flex-direction: row;
gap: 0.5rem;
}
#library-page-title h1 {
padding-right: 0.5rem;
}
#library-page-title i {
display: inline-block;
padding: 0.25rem;
}
#library-page-title i[checked] {
border: 3px solid var(--pf-global--BorderColor--100);
}
#library-page-title a,
#library-page-title i {
vertical-align: bottom;
}
`);
export default styles;

View File

@ -1,7 +1,6 @@
import { groupBy } from "@goauthentik/common/utils";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/EmptyState";
import { tryCatch } from "@goauthentik/elements/utils/tryCatch.js";
import "@goauthentik/user/LibraryApplication";
import { msg } from "@lit/localize";
@ -13,7 +12,6 @@ import styles from "./LibraryPageImpl.css";
import type { Application } from "@goauthentik/api";
import "./ApplicationCards";
import "./ApplicationEmptyState";
import "./ApplicationList";
import "./ApplicationSearch";
@ -22,8 +20,6 @@ import { SEARCH_ITEM_SELECTED, SEARCH_UPDATED } from "./constants";
import { isCustomEvent, loading } from "./helpers";
import type { AppGroupList, PageUIConfig } from "./types";
const VIEW_KEY = "ak-library-page-view-preference";
/**
* List of Applications available
*
@ -57,9 +53,6 @@ export class LibraryPage extends AKElement {
@state()
filteredApps: Application[] = [];
@property()
viewPreference?: string;
constructor() {
super();
this.searchUpdated = this.searchUpdated.bind(this);
@ -73,12 +66,6 @@ export class LibraryPage extends AKElement {
connectedCallback() {
super.connectedCallback();
this.filteredApps = this.apps;
this.viewPreference =
this.viewPreference ??
tryCatch(
() => window.localStorage.getItem(VIEW_KEY) ?? undefined,
(e) => "card",
);
if (this.filteredApps === undefined) {
throw new Error(
"Application.results should never be undefined when passed to the Library Page.",
@ -123,13 +110,6 @@ export class LibraryPage extends AKElement {
return groupBy(this.filteredApps.filter(appHasLaunchUrl), (app) => app.group || "");
}
setView(view: string) {
this.viewPreference = view;
tryCatch(() => {
window.localStorage.setItem(VIEW_KEY, view);
});
}
renderEmptyState() {
return html`<ak-library-application-empty-list
?isadmin=${this.isAdmin}
@ -142,17 +122,12 @@ export class LibraryPage extends AKElement {
const layout = this.uiConfig.layout as string;
const background = this.uiConfig.background;
return this.viewPreference === "list"
? html`<ak-library-application-list
selected="${ifDefined(selected)}"
.apps=${apps}
></ak-library-application-list>`
: html`<ak-library-application-cards
layout="${layout}"
background="${ifDefined(background)}"
selected="${ifDefined(selected)}"
.apps=${apps}
></ak-library-application-cards>`;
return html`<ak-library-application-list
layout="${layout}"
background="${ifDefined(background)}"
selected="${ifDefined(selected)}"
.apps=${apps}
></ak-library-application-list>`;
}
renderSearch() {
@ -162,15 +137,9 @@ export class LibraryPage extends AKElement {
render() {
return html`<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
<div class="pf-c-content header">
<div id="library-page-title">
<h1 role="heading" aria-level="1">${msg("My applications")}</h1>
<a id="card-view" @click=${() => this.setView("card")}
><i ?checked=${this.viewPreference === "card"} class="fas fa-th-large"></i
></a>
<a id="list-view" @click=${() => this.setView("list")}
><i ?checked=${this.viewPreference === "list"} class="fas fa-list"></i
></a>
</div>
<h1 role="heading" aria-level="1" id="library-page-title">
${msg("My applications")}
</h1>
${this.uiConfig.searchEnabled ? this.renderSearch() : html``}
</div>
<section class="pf-c-page__main-section">

View File

@ -6543,18 +6543,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -6812,18 +6812,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -6460,18 +6460,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -8608,18 +8608,6 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -8398,18 +8398,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -8242,18 +8242,6 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -6664,18 +6664,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -8514,16 +8514,4 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body></file></xliff>

View File

@ -6453,18 +6453,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -5371,18 +5371,6 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -8613,18 +8613,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -6501,18 +6501,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -8359,18 +8359,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s7bfbf84a8ad5883f">
<source>Internal Service accounts are created and managed by authentik and cannot be created manually.</source>
</trans-unit>
<trans-unit id="sb0680e5f8782db1e">
<source>Private key Algorithm</source>
</trans-unit>
<trans-unit id="sa03cbf19feebd249">
<source>RSA</source>
</trans-unit>
<trans-unit id="sfbfccbd3e395c147">
<source>ECDSA</source>
</trans-unit>
<trans-unit id="sebea299e52db4242">
<source>Algorithm used to generate the private key.</source>
</trans-unit>
</body>
</file>

View File

@ -1,26 +1,5 @@
# YAML Tags
To use the custom tags with your preferred editor, you must make the editor aware of the custom tags.
For VS Code, for example, add these entries to your `settings.json`:
```
{
"yaml.customTags": [
"!KeyOf scalar",
"!Env scalar",
"!Find sequence",
"!Context scalar",
"!Format sequence",
"!If sequence",
"!Condition sequence",
"!Enumerate sequence",
"!Index scalar",
"!Value scalar"
]
}
```
#### `!KeyOf`
Example:

View File

@ -26,6 +26,10 @@ If you use locally installed databases, the PostgreSQL credentials given to auth
Depending on your platform, some native dependencies might be required. On macOS, run `brew install libxmlsec1 libpq`, and for the CLI tools `brew install postgresql redis node@20`
:::
:::info
As long as [this issue](https://github.com/xmlsec/python-xmlsec/issues/252) about `libxmlsec-1.3.0` is open, a workaround is required to install a compatible version of `libxmlsec1` with brew, see [this comment](https://github.com/xmlsec/python-xmlsec/issues/254#issuecomment-1612005910).
:::
1. Create an isolated Python environment. To create the environment and install dependencies, run the following commands in the same directory as your local authentik git repository:
```shell

View File

@ -13,14 +13,12 @@ Depending on what kind of device you want to require the user to have:
#### WebAuthn
```python
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
return WebAuthnDevice.objects.filter(user=request.context['pending_user'], confirmed=True).exists()
```
#### Duo
```python
from authentik.stages.authenticator_duo.models import DuoDevice
return DuoDevice.objects.filter(user=request.context['pending_user'], confirmed=True).exists()
```

View File

@ -11,7 +11,6 @@ Newly created users can be created as inactive and can be assigned to a selected
Starting with authentik 2022.5, users can be added to dynamic groups. To do so, simply set `groups` in the flow plan context before this stage is run, for example
```python
from authentik.core.models import Group
group, _ = Group.objects.get_or_create(name="some-group")
# ["groups"] *must* be set to an array of Group objects, names alone are not enough.
request.context["flow_plan"].context["groups"] = [group]

View File

@ -50,8 +50,8 @@ Run the following commands to generate a password and secret key and write them
{/* prettier-ignore */}
```shell
echo "PG_PASS=$(openssl rand 36 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 60 | base64)" >> .env
echo "PG_PASS=$(openssl rand -base64 36)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60)" >> .env
```
:::info

View File

@ -23,7 +23,7 @@ Start by generating passwords for the database and cache. You can use either of
```shell
pwgen -s 50 1
openssl rand 60 | base64
openssl rand -base64 36
```
### Set Values

View File

@ -51,7 +51,7 @@ authentik already provides some default _scopes_ with _claims_ inside them, such
##### Custom profile scope
If you do not need storage quota, group information, or to manage already existing users in Nextcloud [skip to the next step](#provider-and-application).
If you do not need storage quota or group information in Nextcloud [skip to the next step](#provider-and-application).
However, if you want to be able to control how much storage users in Nextcloud can use, as well as which users are recognized as Nextcloud administrators, you would need to make this information available in Nextcloud. To achieve this you would need to create a custom `profile` scope. To do so, go to _Customization_ -> _Property mappings_. Create a _Scope mapping_ with the following parameters:
@ -74,10 +74,7 @@ return {
"name": request.user.name,
"groups": groups,
# To set a quota set the "nextcloud_quota" property in the user's attributes
"quota": user.group_attributes().get("nextcloud_quota", None),
# To connect an already existing user, set the "nextcloud_user_id" property in the
# user's attributes to the username of the corresponding user on Nextcloud.
"user_id": user.attributes.get("nextcloud_user_id", user.uuid),
"quota": user.group_attributes().get("nextcloud_quota", None)
}
```
@ -87,13 +84,6 @@ To set a quota set the "nextcloud_quota" property in the user's attributes. This
If set to a value, for example `1 GB`, user(s) will have 1GB storage quota. If the attribute is not set, user(s) will have unlimited storage.
:::
:::note
To connect to an already existing Nextcloud user, set the "nextcloud_user_id" property in the user's attributes. This must be set for each individual user.
The value of `nextcloud_user_id` must match the field `username` of the user on the Nextcloud instance. On Nextcloud, go to _Users_ to see the username of the user you are trying to connect to (Under user's `Display name`).
If set to a value, for example `goauthentik`, it will try to connect to the `goauthentik` user on the Nextcloud instance. Otherwise, the user's UUID will be used.
:::
##### Provider and Application
Create a provider for Nextcloud. In the Admin Interface, go to _Applications_ -> _Providers_. Create an _OAuth2/OpenID Provider_ with the following parameters:
@ -139,7 +129,7 @@ Add a new provider using the `+` button and set the following values:
:::
- Scope: `email`, `profile` (you can safely omit `openid` if you prefer)
- Attribute mappings:
- User ID mapping: sub (or `user_id` if you need to connect to an already existing Nextcloud user)
- User ID mapping: sub
- Display name mapping: name
- Email mapping: email
- Quota mapping: quota (leave empty if you have skipped the [custom profile scope](#custom-profile-scope) section)
@ -147,9 +137,9 @@ Add a new provider using the `+` button and set the following values:
:::tip
You need to enable the "Use group provisioning" checkmark to be able to write to this field
:::
- Use unique user ID: If you only have one provider you can deselect this if you prefer. This will affect your Federated Cloud ID, which you can check under _Personal settings_ -> _Sharing_ -> _Federated Cloud_. If the box is selected, nextcloud will pick a hashed value here (`437218904321784903214789023@nextcloud.instance` for example). Otherwise, it will use the mapped user ID (`<authentik's sub or user_id>@nextcloud.instance`).
- Use unique user ID: If you only have one provider you can uncheck this if you prefer.
:::tip
To avoid your federated cloud id being a hash value, deselect **Use unique user ID** and use `user_id` in the **User ID mapping** field.
To avoid your group assignment being a hash value, deselect **Use unique user ID**.
:::
At this stage you should be able to login with SSO.

View File

@ -19,7 +19,7 @@ The following placeholders will be used:
![](./01_user_create.png)
3. Give the User a password, generated using for example `pwgen 64 1` or `openssl rand 36 | base64`.
3. Give the User a password, generated using for example `pwgen 64 1` or `openssl rand -base64 36`.
4. Open the Delegation of Control Wizard by right-clicking the domain and selecting "All Tasks".

View File

@ -16,7 +16,7 @@ The following placeholders will be used:
1. Log into FreeIPA.
2. Create a user in FreeIPA, matching your naming scheme. Provide a strong password, example generation methods: `pwgen 64 1` or `openssl rand 36 | base64`. After you are done click **Add and Edit**.
2. Create a user in FreeIPA, matching your naming scheme. Provide a strong password, example generation methods: `pwgen 64 1` or `openssl rand -base64 36`. Once done click `Add and Edit`.
![](./01_user_create.png)