From b93ad8615cb3bee1d281bd6bcf2898a227664046 Mon Sep 17 00:00:00 2001 From: Jens L Date: Wed, 3 Jan 2024 14:47:17 +0100 Subject: [PATCH 01/37] enterprise/providers/rac: create authorize_application event when creating token (#8050) * events: don't log creation of creation token Signed-off-by: Jens Langhammer * enterprise/providers/rac: create authorize_application event when creating token Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/enterprise/providers/rac/views.py | 9 +++++++++ authentik/events/middleware.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/authentik/enterprise/providers/rac/views.py b/authentik/enterprise/providers/rac/views.py index 31a25c721..e50f6ee5b 100644 --- a/authentik/enterprise/providers/rac/views.py +++ b/authentik/enterprise/providers/rac/views.py @@ -10,6 +10,7 @@ from authentik.core.models import Application, AuthenticatedSession from authentik.core.views.interface import InterfaceView from authentik.enterprise.policy import EnterprisePolicyAccessView from authentik.enterprise.providers.rac.models import ConnectionToken, Endpoint, RACProvider +from authentik.events.models import Event, EventAction from authentik.flows.challenge import RedirectChallenge from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.models import in_memory_stage @@ -43,6 +44,7 @@ class RACStartView(EnterprisePolicyAccessView): plan.insert_stage( in_memory_stage( RACFinalStage, + application=self.application, endpoint=self.endpoint, provider=self.provider, ) @@ -90,6 +92,7 @@ class RACFinalStage(RedirectStage): def get_challenge(self, *args, **kwargs) -> RedirectChallenge: endpoint: Endpoint = self.executor.current_stage.endpoint provider: RACProvider = self.executor.current_stage.provider + application: Application = self.executor.current_stage.application token = ConnectionToken.objects.create( provider=provider, endpoint=endpoint, @@ -100,6 +103,12 @@ class RACFinalStage(RedirectStage): expires=now() + timedelta_from_string(provider.connection_expiry), expiring=True, ) + Event.new( + EventAction.AUTHORIZE_APPLICATION, + authorized_application=application, + flow=self.executor.plan.flow_pk, + endpoint=endpoint.name, + ).from_http(self.request) setattr( self.executor.current_stage, "destination", diff --git a/authentik/events/middleware.py b/authentik/events/middleware.py index 7834bae5e..ea7e6001f 100644 --- a/authentik/events/middleware.py +++ b/authentik/events/middleware.py @@ -20,6 +20,7 @@ from authentik.core.models import ( User, UserSourceConnection, ) +from authentik.enterprise.providers.rac.models import ConnectionToken from authentik.events.models import Event, EventAction, Notification from authentik.events.utils import model_to_dict from authentik.flows.models import FlowToken, Stage @@ -54,6 +55,7 @@ IGNORED_MODELS = ( SCIMUser, SCIMGroup, Reputation, + ConnectionToken, ) From 116ac30c7275aa9e97cea8d96bf91a788146f3cc Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 4 Jan 2024 16:18:12 +0100 Subject: [PATCH 02/37] enterprise/providers/rac: add alert that enterprise is required for RAC (#8057) add alert that enterprise is required for RAC Signed-off-by: Jens Langhammer --- authentik/core/api/propertymappings.py | 2 + authentik/core/api/providers.py | 2 + authentik/core/api/utils.py | 3 +- authentik/enterprise/api.py | 14 ++++ authentik/enterprise/apps.py | 6 +- .../enterprise/providers/rac/api/endpoints.py | 3 +- .../providers/rac/api/property_mappings.py | 3 +- .../enterprise/providers/rac/api/providers.py | 3 +- authentik/enterprise/providers/rac/apps.py | 4 +- authentik/enterprise/providers/rac/models.py | 2 +- schema.yml | 4 ++ .../PropertyMappingWizard.ts | 32 +++++++-- web/src/admin/providers/ProviderWizard.ts | 37 +++++++--- .../enterprise/EnterpriseStatusBanner.ts | 6 +- web/xliff/de.xlf | 6 ++ web/xliff/en.xlf | 6 ++ web/xliff/es.xlf | 6 ++ web/xliff/fr.xlf | 72 ++++++++++--------- web/xliff/pl.xlf | 6 ++ web/xliff/pseudo-LOCALE.xlf | 6 ++ web/xliff/tr.xlf | 6 ++ web/xliff/zh-Hans.xlf | 54 +++++++------- web/xliff/zh-Hant.xlf | 6 ++ web/xliff/zh_TW.xlf | 6 ++ 24 files changed, 211 insertions(+), 84 deletions(-) diff --git a/authentik/core/api/propertymappings.py b/authentik/core/api/propertymappings.py index 1e7436be9..d0fa7267b 100644 --- a/authentik/core/api/propertymappings.py +++ b/authentik/core/api/propertymappings.py @@ -19,6 +19,7 @@ from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import MetaNameSerializer, PassiveSerializer, TypeCreateSerializer from authentik.core.expression.evaluator import PropertyMappingEvaluator from authentik.core.models import PropertyMapping +from authentik.enterprise.apps import EnterpriseConfig from authentik.events.utils import sanitize_item from authentik.lib.utils.reflection import all_subclasses from authentik.policies.api.exec import PolicyTestSerializer @@ -95,6 +96,7 @@ class PropertyMappingViewSet( "description": subclass.__doc__, "component": subclass().component, "model_name": subclass._meta.model_name, + "requires_enterprise": isinstance(subclass._meta.app_config, EnterpriseConfig), } ) return Response(TypeCreateSerializer(data, many=True).data) diff --git a/authentik/core/api/providers.py b/authentik/core/api/providers.py index a5095dcde..6c0f4db06 100644 --- a/authentik/core/api/providers.py +++ b/authentik/core/api/providers.py @@ -16,6 +16,7 @@ from rest_framework.viewsets import GenericViewSet from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer from authentik.core.models import Provider +from authentik.enterprise.apps import EnterpriseConfig from authentik.lib.utils.reflection import all_subclasses @@ -113,6 +114,7 @@ class ProviderViewSet( "description": subclass.__doc__, "component": subclass().component, "model_name": subclass._meta.model_name, + "requires_enterprise": isinstance(subclass._meta.app_config, EnterpriseConfig), } ) data.append( diff --git a/authentik/core/api/utils.py b/authentik/core/api/utils.py index c7a188f5c..c79fec22e 100644 --- a/authentik/core/api/utils.py +++ b/authentik/core/api/utils.py @@ -5,7 +5,7 @@ from django.db.models import Model from drf_spectacular.extensions import OpenApiSerializerFieldExtension from drf_spectacular.plumbing import build_basic_type from drf_spectacular.types import OpenApiTypes -from rest_framework.fields import CharField, IntegerField, JSONField +from rest_framework.fields import BooleanField, CharField, IntegerField, JSONField from rest_framework.serializers import Serializer, SerializerMethodField, ValidationError @@ -74,6 +74,7 @@ class TypeCreateSerializer(PassiveSerializer): description = CharField(required=True) component = CharField(required=True) model_name = CharField(required=True) + requires_enterprise = BooleanField(default=False) class CacheSerializer(PassiveSerializer): diff --git a/authentik/enterprise/api.py b/authentik/enterprise/api.py index fdf0a11fc..c13e34b6d 100644 --- a/authentik/enterprise/api.py +++ b/authentik/enterprise/api.py @@ -2,9 +2,11 @@ from datetime import datetime, timedelta from django.utils.timezone import now +from django.utils.translation import gettext as _ from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import extend_schema, inline_serializer from rest_framework.decorators import action +from rest_framework.exceptions import ValidationError from rest_framework.fields import BooleanField, CharField, DateTimeField, IntegerField from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request @@ -20,6 +22,18 @@ from authentik.enterprise.models import License, LicenseKey from authentik.root.install_id import get_install_id +class EnterpriseRequiredMixin: + """Mixin to validate that a valid enterprise license + exists before allowing to safe the object""" + + def validate(self, attrs: dict) -> dict: + """Check that a valid license exists""" + total = LicenseKey.get_total() + if not total.is_valid(): + raise ValidationError(_("Enterprise is required to create/update this object.")) + return super().validate(attrs) + + class LicenseSerializer(ModelSerializer): """License Serializer""" diff --git a/authentik/enterprise/apps.py b/authentik/enterprise/apps.py index 2d918da17..a0b9bed6d 100644 --- a/authentik/enterprise/apps.py +++ b/authentik/enterprise/apps.py @@ -2,7 +2,11 @@ from authentik.blueprints.apps import ManagedAppConfig -class AuthentikEnterpriseConfig(ManagedAppConfig): +class EnterpriseConfig(ManagedAppConfig): + """Base app config for all enterprise apps""" + + +class AuthentikEnterpriseConfig(EnterpriseConfig): """Enterprise app config""" name = "authentik.enterprise" diff --git a/authentik/enterprise/providers/rac/api/endpoints.py b/authentik/enterprise/providers/rac/api/endpoints.py index b0b0239c5..e1c6c5dd8 100644 --- a/authentik/enterprise/providers/rac/api/endpoints.py +++ b/authentik/enterprise/providers/rac/api/endpoints.py @@ -15,6 +15,7 @@ from structlog.stdlib import get_logger from authentik.core.api.used_by import UsedByMixin from authentik.core.models import Provider +from authentik.enterprise.api import EnterpriseRequiredMixin from authentik.enterprise.providers.rac.api.providers import RACProviderSerializer from authentik.enterprise.providers.rac.models import Endpoint from authentik.policies.engine import PolicyEngine @@ -28,7 +29,7 @@ def user_endpoint_cache_key(user_pk: str) -> str: return f"goauthentik.io/providers/rac/endpoint_access/{user_pk}" -class EndpointSerializer(ModelSerializer): +class EndpointSerializer(EnterpriseRequiredMixin, ModelSerializer): """Endpoint Serializer""" provider_obj = RACProviderSerializer(source="provider", read_only=True) diff --git a/authentik/enterprise/providers/rac/api/property_mappings.py b/authentik/enterprise/providers/rac/api/property_mappings.py index 35daec95c..4afef68bb 100644 --- a/authentik/enterprise/providers/rac/api/property_mappings.py +++ b/authentik/enterprise/providers/rac/api/property_mappings.py @@ -5,10 +5,11 @@ from rest_framework.viewsets import ModelViewSet from authentik.core.api.propertymappings import PropertyMappingSerializer from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import JSONDictField +from authentik.enterprise.api import EnterpriseRequiredMixin from authentik.enterprise.providers.rac.models import RACPropertyMapping -class RACPropertyMappingSerializer(PropertyMappingSerializer): +class RACPropertyMappingSerializer(EnterpriseRequiredMixin, PropertyMappingSerializer): """RACPropertyMapping Serializer""" static_settings = JSONDictField() diff --git a/authentik/enterprise/providers/rac/api/providers.py b/authentik/enterprise/providers/rac/api/providers.py index 6dd4f9f82..cda6c2af3 100644 --- a/authentik/enterprise/providers/rac/api/providers.py +++ b/authentik/enterprise/providers/rac/api/providers.py @@ -4,10 +4,11 @@ from rest_framework.viewsets import ModelViewSet from authentik.core.api.providers import ProviderSerializer from authentik.core.api.used_by import UsedByMixin +from authentik.enterprise.api import EnterpriseRequiredMixin from authentik.enterprise.providers.rac.models import RACProvider -class RACProviderSerializer(ProviderSerializer): +class RACProviderSerializer(EnterpriseRequiredMixin, ProviderSerializer): """RACProvider Serializer""" outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all") diff --git a/authentik/enterprise/providers/rac/apps.py b/authentik/enterprise/providers/rac/apps.py index 973159bb9..13930faae 100644 --- a/authentik/enterprise/providers/rac/apps.py +++ b/authentik/enterprise/providers/rac/apps.py @@ -1,8 +1,8 @@ """RAC app config""" -from authentik.blueprints.apps import ManagedAppConfig +from authentik.enterprise.apps import EnterpriseConfig -class AuthentikEnterpriseProviderRAC(ManagedAppConfig): +class AuthentikEnterpriseProviderRAC(EnterpriseConfig): """authentik enterprise rac app config""" name = "authentik.enterprise.providers.rac" diff --git a/authentik/enterprise/providers/rac/models.py b/authentik/enterprise/providers/rac/models.py index d79bbd54c..f2806f32b 100644 --- a/authentik/enterprise/providers/rac/models.py +++ b/authentik/enterprise/providers/rac/models.py @@ -35,7 +35,7 @@ class AuthenticationMode(models.TextChoices): class RACProvider(Provider): - """Remotely access computers/servers""" + """Remotely access computers/servers via RDP/SSH/VNC.""" settings = models.JSONField(default=dict) auth_mode = models.TextField( diff --git a/schema.yml b/schema.yml index 0ea6e8ee0..09b351707 100644 --- a/schema.yml +++ b/schema.yml @@ -19158,6 +19158,7 @@ paths: - tr - tt - udm + - ug - uk - ur - uz @@ -42957,6 +42958,9 @@ components: type: string model_name: type: string + requires_enterprise: + type: boolean + default: false required: - component - description diff --git a/web/src/admin/property-mappings/PropertyMappingWizard.ts b/web/src/admin/property-mappings/PropertyMappingWizard.ts index 4773dd93a..4f0ab6122 100644 --- a/web/src/admin/property-mappings/PropertyMappingWizard.ts +++ b/web/src/admin/property-mappings/PropertyMappingWizard.ts @@ -13,21 +13,24 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage"; import { msg, str } from "@lit/localize"; import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; -import { CSSResult, TemplateResult, html } from "lit"; -import { property } from "lit/decorators.js"; +import { CSSResult, TemplateResult, html, nothing } from "lit"; +import { property, state } from "lit/decorators.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFRadio from "@patternfly/patternfly/components/Radio/radio.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; -import { PropertymappingsApi, TypeCreate } from "@goauthentik/api"; +import { EnterpriseApi, LicenseSummary, PropertymappingsApi, TypeCreate } from "@goauthentik/api"; @customElement("ak-property-mapping-wizard-initial") export class InitialPropertyMappingWizardPage extends WizardPage { @property({ attribute: false }) mappingTypes: TypeCreate[] = []; + @property({ attribute: false }) + enterprise?: LicenseSummary; + static get styles(): CSSResult[] { return [PFBase, PFForm, PFButton, PFRadio]; } @@ -60,11 +63,20 @@ export class InitialPropertyMappingWizardPage extends WizardPage { ]; this.host.isValid = true; }} + ?disabled=${type.requiresEnterprise ? !this.enterprise?.hasLicense : false} /> ${type.description} + ${type.requiresEnterprise && !this.enterprise?.hasLicense + ? html` + + ${msg("Provider require enterprise.")} + ${msg("Learn more")} + + ` + : nothing} `; })} `; @@ -80,10 +92,16 @@ export class PropertyMappingWizard extends AKElement { @property({ attribute: false }) mappingTypes: TypeCreate[] = []; - firstUpdated(): void { - new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTypesList().then((types) => { - this.mappingTypes = types; - }); + @state() + enterprise?: LicenseSummary; + + async firstUpdated(): Promise { + this.mappingTypes = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsAllTypesList(); + this.enterprise = await new EnterpriseApi( + DEFAULT_CONFIG, + ).enterpriseLicenseSummaryRetrieve(); } render(): TemplateResult { diff --git a/web/src/admin/providers/ProviderWizard.ts b/web/src/admin/providers/ProviderWizard.ts index a65945354..7f19b4d02 100644 --- a/web/src/admin/providers/ProviderWizard.ts +++ b/web/src/admin/providers/ProviderWizard.ts @@ -4,6 +4,7 @@ import "@goauthentik/admin/providers/proxy/ProxyProviderForm"; import "@goauthentik/admin/providers/saml/SAMLProviderForm"; import "@goauthentik/admin/providers/saml/SAMLProviderImportForm"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import "@goauthentik/elements/Alert"; import { AKElement } from "@goauthentik/elements/Base"; import "@goauthentik/elements/forms/ProxyForm"; import { paramURL } from "@goauthentik/elements/router/RouterOutlet"; @@ -13,8 +14,8 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage"; import { msg, str } from "@lit/localize"; import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; -import { CSSResult, TemplateResult, html } from "lit"; -import { property } from "lit/decorators.js"; +import { CSSResult, TemplateResult, html, nothing } from "lit"; +import { property, state } from "lit/decorators.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css"; @@ -22,13 +23,16 @@ import PFHint from "@patternfly/patternfly/components/Hint/hint.css"; import PFRadio from "@patternfly/patternfly/components/Radio/radio.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; -import { ProvidersApi, TypeCreate } from "@goauthentik/api"; +import { EnterpriseApi, LicenseSummary, ProvidersApi, TypeCreate } from "@goauthentik/api"; @customElement("ak-provider-wizard-initial") export class InitialProviderWizardPage extends WizardPage { @property({ attribute: false }) providerTypes: TypeCreate[] = []; + @property({ attribute: false }) + enterprise?: LicenseSummary; + static get styles(): CSSResult[] { return [PFBase, PFForm, PFHint, PFButton, PFRadio]; } @@ -79,9 +83,18 @@ export class InitialProviderWizardPage extends WizardPage { this.host.steps = ["initial", `type-${type.component}`]; this.host.isValid = true; }} + ?disabled=${type.requiresEnterprise ? !this.enterprise?.hasLicense : false} /> ${type.description} + ${type.requiresEnterprise && !this.enterprise?.hasLicense + ? html` + + ${msg("Provider require enterprise.")} + ${msg("Learn more")} + + ` + : nothing} `; })} `; @@ -100,15 +113,19 @@ export class ProviderWizard extends AKElement { @property({ attribute: false }) providerTypes: TypeCreate[] = []; + @state() + enterprise?: LicenseSummary; + @property({ attribute: false }) finalHandler: () => Promise = () => { return Promise.resolve(); }; - firstUpdated(): void { - new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList().then((types) => { - this.providerTypes = types; - }); + async firstUpdated(): Promise { + this.providerTypes = await new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList(); + this.enterprise = await new EnterpriseApi( + DEFAULT_CONFIG, + ).enterpriseLicenseSummaryRetrieve(); } render(): TemplateResult { @@ -121,7 +138,11 @@ export class ProviderWizard extends AKElement { return this.finalHandler(); }} > - + ${this.providerTypes.map((type) => { return html` diff --git a/web/src/elements/enterprise/EnterpriseStatusBanner.ts b/web/src/elements/enterprise/EnterpriseStatusBanner.ts index 0ac115457..09d376759 100644 --- a/web/src/elements/enterprise/EnterpriseStatusBanner.ts +++ b/web/src/elements/enterprise/EnterpriseStatusBanner.ts @@ -21,10 +21,8 @@ export class EnterpriseStatusBanner extends AKElement { return [PFBanner]; } - firstUpdated(): void { - new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve().then((b) => { - this.summary = b; - }); + async firstUpdated(): Promise { + this.summary = await new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve(); } renderBanner(): TemplateResult { diff --git a/web/xliff/de.xlf b/web/xliff/de.xlf index 8cac9d9de..403d08256 100644 --- a/web/xliff/de.xlf +++ b/web/xliff/de.xlf @@ -6237,6 +6237,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index aa28b7c6a..a8c3a759b 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -6513,6 +6513,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index cbe16ba84..ece851727 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -6153,6 +6153,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index 407618e65..3bac1b49b 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ Il y a jour(s) - The URL "" was not found. - L'URL " - " n'a pas été trouvée. + The URL "" was not found. + L'URL " + " n'a pas été trouvée. @@ -1057,8 +1057,8 @@ Il y a jour(s) - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. @@ -1630,7 +1630,7 @@ Il y a jour(s) Token to authenticate with. Currently only bearer authentication is supported. - Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. + Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. @@ -1798,8 +1798,8 @@ Il y a jour(s) - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". @@ -2892,7 +2892,7 @@ doesn't pass when either or both of the selected options are equal or above the To use SSL instead, use 'ldaps://' and disable this option. - Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. + Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. @@ -2981,8 +2981,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' @@ -3277,7 +3277,7 @@ doesn't pass when either or both of the selected options are equal or above the Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. - Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. + Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. @@ -3445,7 +3445,7 @@ doesn't pass when either or both of the selected options are equal or above the Optionally set the 'FriendlyName' value of the Assertion attribute. - Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) + Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) @@ -3774,8 +3774,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". + When using an external logging solution for archiving, this can be set to "minutes=5". + En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". @@ -3784,8 +3784,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - Format : "weeks=3;days=2;hours=3,seconds=2". + Format: "weeks=3;days=2;hours=3,seconds=2". + Format : "weeks=3;days=2;hours=3,seconds=2". @@ -3981,10 +3981,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? Êtes-vous sûr de vouloir mettre à jour - " - " ? + " + " ? @@ -5070,8 +5070,8 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey - Un authentificateur "itinérant", comme une YubiKey + A "roaming" authenticator, like a YubiKey + Un authentificateur "itinérant", comme une YubiKey @@ -5396,7 +5396,7 @@ doesn't pass when either or both of the selected options are equal or above the Show arbitrary input fields to the user, for example during enrollment. Data is saved in the flow context under the 'prompt_data' variable. - Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". + Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". @@ -5405,10 +5405,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ", de type + (" + ", de type ) @@ -5457,8 +5457,8 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. - Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. @@ -6242,7 +6242,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Can be in the format of 'unix://' when connecting to a local docker daemon, using 'ssh://' to connect via SSH, or 'https://:2376' when connecting to a remote system. - Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. + Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. @@ -7549,7 +7549,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). - Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). + Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). Default relay state @@ -7963,7 +7963,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Utilisateur créé et ajouté au groupe avec succès - This user will be added to the group "". + This user will be added to the group "". Cet utilisateur sera ajouté au groupe &quot;&quot;. @@ -8201,7 +8201,13 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Determines how long a session lasts before being disconnected and requiring re-authorization. Détermine combien de temps une session dure avant déconnexion et ré-authorisation. + + + Provider require enterprise. + + + Learn more - \ No newline at end of file + diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index b52ea863c..a0e16c3be 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -6361,6 +6361,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index bc883faa7..217082220 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -8099,4 +8099,10 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + Provider require enterprise. + + + Learn more + diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index 7b03127c0..f2cd5d161 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -6146,6 +6146,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 1ef89db75..d1572b445 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8203,7 +8203,13 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. 设置会话在被断开连接并需要重新授权之前持续的时间。 + + + Provider require enterprise. + + + Learn more - \ No newline at end of file + diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index 65794b706..35b356efa 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -6194,6 +6194,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index 9a9b690bd..8ec2bf521 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -8083,6 +8083,12 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. + + + Provider require enterprise. + + + Learn more From 519062bc39d80e0d2d1f73446d2804ac52feb510 Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:26:58 +0100 Subject: [PATCH 03/37] web: bump API Client version (#8058) Signed-off-by: GitHub Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index d6305b661..945ad5ee2 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.5-1703968412", + "@goauthentik/api": "^2023.10.5-1704381512", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", @@ -2913,9 +2913,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.10.5-1703968412", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.5-1703968412.tgz", - "integrity": "sha512-/2QDgGkWGXOYDqH49/2hNs+U8TqdE94hkMrJc8A6L+NAy8x/zKAY39eUHs85jmwt013N5duD/jKiJsRftHsDig==" + "version": "2023.10.5-1704381512", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.5-1704381512.tgz", + "integrity": "sha512-kB7OZCwNEKvlVzzEkiA3bx9qIJ4OA44qmQZQ03iI05DKIJWqU+CssDyHeMUGv5Vdma04xdf+3+BOzrc+ZJWX+A==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", diff --git a/web/package.json b/web/package.json index 92cb66ec9..78a4f32ef 100644 --- a/web/package.json +++ b/web/package.json @@ -42,7 +42,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.5-1703968412", + "@goauthentik/api": "^2023.10.5-1704381512", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", From 20643954348fbda587b235c74d7bdbaa2bf25e28 Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 4 Jan 2024 16:27:16 +0100 Subject: [PATCH 04/37] enterprise/providers/rac: add option to limit concurrent connections to endpoint (#8053) * enterprise/providers/rac: add option to limit concurrent connections to endpoint Signed-off-by: Jens Langhammer * unrelated: put outpost settings in group Signed-off-by: Jens Langhammer * fix Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- .../enterprise/providers/rac/api/endpoints.py | 1 + .../0002_endpoint_maximum_connections.py | 17 ++++++++ authentik/enterprise/providers/rac/models.py | 1 + .../providers/rac/tests/test_endpoints_api.py | 3 ++ authentik/enterprise/providers/rac/views.py | 36 +++++++++++----- blueprints/schema.json | 6 +++ schema.yml | 12 ++++++ web/src/admin/outposts/OutpostForm.ts | 42 ++++++++++--------- web/src/admin/providers/rac/EndpointForm.ts | 17 ++++++++ 9 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 authentik/enterprise/providers/rac/migrations/0002_endpoint_maximum_connections.py diff --git a/authentik/enterprise/providers/rac/api/endpoints.py b/authentik/enterprise/providers/rac/api/endpoints.py index e1c6c5dd8..1af281ef8 100644 --- a/authentik/enterprise/providers/rac/api/endpoints.py +++ b/authentik/enterprise/providers/rac/api/endpoints.py @@ -60,6 +60,7 @@ class EndpointSerializer(EnterpriseRequiredMixin, ModelSerializer): "property_mappings", "auth_mode", "launch_url", + "maximum_connections", ] diff --git a/authentik/enterprise/providers/rac/migrations/0002_endpoint_maximum_connections.py b/authentik/enterprise/providers/rac/migrations/0002_endpoint_maximum_connections.py new file mode 100644 index 000000000..0760f2313 --- /dev/null +++ b/authentik/enterprise/providers/rac/migrations/0002_endpoint_maximum_connections.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0 on 2024-01-03 23:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_providers_rac", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="endpoint", + name="maximum_connections", + field=models.IntegerField(default=1), + ), + ] diff --git a/authentik/enterprise/providers/rac/models.py b/authentik/enterprise/providers/rac/models.py index f2806f32b..927bd23fe 100644 --- a/authentik/enterprise/providers/rac/models.py +++ b/authentik/enterprise/providers/rac/models.py @@ -81,6 +81,7 @@ class Endpoint(SerializerModel, PolicyBindingModel): settings = models.JSONField(default=dict) auth_mode = models.TextField(choices=AuthenticationMode.choices) provider = models.ForeignKey("RACProvider", on_delete=models.CASCADE) + maximum_connections = models.IntegerField(default=1) property_mappings = models.ManyToManyField( "authentik_core.PropertyMapping", default=None, blank=True diff --git a/authentik/enterprise/providers/rac/tests/test_endpoints_api.py b/authentik/enterprise/providers/rac/tests/test_endpoints_api.py index 0a659bccd..3000b345c 100644 --- a/authentik/enterprise/providers/rac/tests/test_endpoints_api.py +++ b/authentik/enterprise/providers/rac/tests/test_endpoints_api.py @@ -81,6 +81,7 @@ class TestEndpointsAPI(APITestCase): }, "protocol": "rdp", "host": self.allowed.host, + "maximum_connections": 1, "settings": {}, "property_mappings": [], "auth_mode": "", @@ -131,6 +132,7 @@ class TestEndpointsAPI(APITestCase): }, "protocol": "rdp", "host": self.allowed.host, + "maximum_connections": 1, "settings": {}, "property_mappings": [], "auth_mode": "", @@ -158,6 +160,7 @@ class TestEndpointsAPI(APITestCase): }, "protocol": "rdp", "host": self.denied.host, + "maximum_connections": 1, "settings": {}, "property_mappings": [], "auth_mode": "", diff --git a/authentik/enterprise/providers/rac/views.py b/authentik/enterprise/providers/rac/views.py index e50f6ee5b..4b93aee76 100644 --- a/authentik/enterprise/providers/rac/views.py +++ b/authentik/enterprise/providers/rac/views.py @@ -5,6 +5,7 @@ from django.http import Http404, HttpRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect from django.urls import reverse from django.utils.timezone import now +from django.utils.translation import gettext as _ from authentik.core.models import Application, AuthenticatedSession from authentik.core.views.interface import InterfaceView @@ -79,35 +80,50 @@ class RACInterface(InterfaceView): class RACFinalStage(RedirectStage): """RAC Connection final stage, set the connection token in the stage""" + endpoint: Endpoint + provider: RACProvider + application: Application + def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: - endpoint: Endpoint = self.executor.current_stage.endpoint - engine = PolicyEngine(endpoint, self.request.user, self.request) + self.endpoint = self.executor.current_stage.endpoint + self.provider = self.executor.current_stage.provider + self.application = self.executor.current_stage.application + # Check policies bound to endpoint directly + engine = PolicyEngine(self.endpoint, self.request.user, self.request) engine.use_cache = False engine.build() passing = engine.result if not passing.passing: return self.executor.stage_invalid(", ".join(passing.messages)) + # Check if we're already at the maximum connection limit + all_tokens = ConnectionToken.filter_not_expired( + endpoint=self.endpoint, + ).exclude(endpoint__maximum_connections__lte=-1) + if all_tokens.count() >= self.endpoint.maximum_connections: + msg = [_("Maximum connection limit reached.")] + # Check if any other tokens exist for the current user, and inform them + # they are already connected + if all_tokens.filter(session__user=self.request.user).exists(): + msg.append(_("(You are already connected in another tab/window)")) + return self.executor.stage_invalid(" ".join(msg)) return super().dispatch(request, *args, **kwargs) def get_challenge(self, *args, **kwargs) -> RedirectChallenge: - endpoint: Endpoint = self.executor.current_stage.endpoint - provider: RACProvider = self.executor.current_stage.provider - application: Application = self.executor.current_stage.application token = ConnectionToken.objects.create( - provider=provider, - endpoint=endpoint, + provider=self.provider, + endpoint=self.endpoint, settings=self.executor.plan.context.get("connection_settings", {}), session=AuthenticatedSession.objects.filter( session_key=self.request.session.session_key ).first(), - expires=now() + timedelta_from_string(provider.connection_expiry), + expires=now() + timedelta_from_string(self.provider.connection_expiry), expiring=True, ) Event.new( EventAction.AUTHORIZE_APPLICATION, - authorized_application=application, + authorized_application=self.application, flow=self.executor.plan.flow_pk, - endpoint=endpoint.name, + endpoint=self.endpoint.name, ).from_http(self.request) setattr( self.executor.current_stage, diff --git a/blueprints/schema.json b/blueprints/schema.json index 07d9cd227..213cb1673 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -8958,6 +8958,12 @@ "prompt" ], "title": "Auth mode" + }, + "maximum_connections": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647, + "title": "Maximum connections" } }, "required": [] diff --git a/schema.yml b/schema.yml index 09b351707..ed6a46fed 100644 --- a/schema.yml +++ b/schema.yml @@ -31381,6 +31381,10 @@ components: Build actual launch URL (the provider itself does not have one, just individual endpoints) readOnly: true + maximum_connections: + type: integer + maximum: 2147483647 + minimum: -2147483648 required: - auth_mode - host @@ -31412,6 +31416,10 @@ components: format: uuid auth_mode: $ref: '#/components/schemas/AuthModeEnum' + maximum_connections: + type: integer + maximum: 2147483647 + minimum: -2147483648 required: - auth_mode - host @@ -37298,6 +37306,10 @@ components: format: uuid auth_mode: $ref: '#/components/schemas/AuthModeEnum' + maximum_connections: + type: integer + maximum: 2147483647 + minimum: -2147483648 PatchedEventMatcherPolicyRequest: type: object description: Event Matcher Policy Serializer diff --git a/web/src/admin/outposts/OutpostForm.ts b/web/src/admin/outposts/OutpostForm.ts index 2c5ac9722..7c6c9dda5 100644 --- a/web/src/admin/outposts/OutpostForm.ts +++ b/web/src/admin/outposts/OutpostForm.ts @@ -3,6 +3,7 @@ import { docLink } from "@goauthentik/common/global"; import { groupBy } from "@goauthentik/common/utils"; import "@goauthentik/elements/CodeMirror"; import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; +import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import "@goauthentik/elements/forms/SearchSelect"; @@ -220,24 +221,27 @@ export class OutpostForm extends ModelForm { ${msg("Hold control/command to select multiple items.")}

- - -

- ${msg("Set custom attributes using YAML or JSON.")} -

-

- ${msg("See more here:")}  - ${msg("Documentation")} -

-
`; + + ${msg("Advanced settings")} + + +

+ ${msg("Set custom attributes using YAML or JSON.")} +

+

+ ${msg("See more here:")}  + ${msg("Documentation")} +

+
+
`; } } diff --git a/web/src/admin/providers/rac/EndpointForm.ts b/web/src/admin/providers/rac/EndpointForm.ts index af83af23f..0f23f4fca 100644 --- a/web/src/admin/providers/rac/EndpointForm.ts +++ b/web/src/admin/providers/rac/EndpointForm.ts @@ -106,6 +106,23 @@ export class EndpointForm extends ModelForm { />

${msg("Hostname/IP to connect to.")}

+ + +

+ ${msg( + "Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.", + )} +

+
Date: Thu, 4 Jan 2024 10:27:57 -0500 Subject: [PATCH 05/37] Update index.md (#8056) Signed-off-by: Bryan J. <132493975+chkpwd@users.noreply.github.com> --- .../integrations/services/jellyfin/index.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/website/integrations/services/jellyfin/index.md b/website/integrations/services/jellyfin/index.md index 5de18d3b4..ef66efd27 100644 --- a/website/integrations/services/jellyfin/index.md +++ b/website/integrations/services/jellyfin/index.md @@ -15,7 +15,7 @@ Jellyfin does not have any native external authentication support as of the writ ::: :::note -Currently there are two plugins for Jelyfin that provide external authenticaion, an OIDC plugin and an LDAP plugin. This guide focuses on the use of the LDAP plugin. +Currently, there are two plugins for Jellyfin that provide external authentication, an OIDC plugin and an LDAP plugin. This guide focuses on the use of the LDAP plugin. ::: :::caution @@ -34,49 +34,49 @@ The following placeholders will be used: ## Jellyfin configuration -1. If you don't have one already create an LDAP bind user before starting these steps. +1. If you don't have one already, create an LDAP bind user before starting these steps. - Ideally, this user doesn't have any permissions other than the ability to view other users. However, some functions do require an account with permissions. - This user must be part of the group that is specified in the "Search group" in the LDAP outpost. 2. Navigate to your Jellyfin installation and log in with the admin account or currently configured local admin. 3. Open the administrator dashboard and go to the "Plugins" section. 4. Click "Catalog" at the top of the page, and locate the "LDAP Authentication Plugin" 5. Install the plugin. You may need to restart Jellyfin to finish installation. -6. Once finished navigate back to the plugins section of the admin dashboard, click the 3 dots on the "LDAP-Auth Plugin" card, and click settings. +6. Once finished, navigate back to the plugins section of the admin dashboard, click the 3 dots on the "LDAP-Auth Plugin" card, and click settings. 7. Configure the LDAP Settings as follows: - `LDAP Server`: `ldap.company.com` - `LDAP Port`: 636 - `Secure LDAP`: **Checked** - `StartTLS`: Unchecked - `Skip SSL/TLS Verification`: - - If using a certificate issued by a certificate authority Jellyfin trusts, leave this unchecked. - - If you're using a self signed certificate, check this box. + - If using a certificate issued by a certificate authority, Jellyfin trusts, leave this unchecked. + - If you're using a self-signed certificate, check this box. - `Allow password change`: Unchecked - - Since authentik already has a frontend for password resets, its not necessary to include this in Jellyfin, especially since it requires bind user to have privileges. + - Since authentik already has a frontend for password resets, it's not necessary to include this in Jellyfin, especially since it requires bind user to have privileges. - `Password Reset URL`: Empty - - `LDAP Bind User`: Set this to a the user you want to bind to in authentik. By default the path will be `ou=users,dc=company,dc=com` so the LDAP Bind user will be `cn=ldap_bind_user,ou=users,dc=company,dc=com`. + - `LDAP Bind User`: Set this to a user you want to bind to in authentik. By default, the path will be `ou=users,dc=company,dc=com` so the LDAP Bind user will be `cn=ldap_bind_user,ou=users,dc=company,dc=com`. - `LDAP Bind User Password`: The Password of the user. If using a Service account, this is the token. - - `LDAP Base DN for Searches`: the base DN for LDAP queries. To query all users set this to `dc=company,dc=com`. + - `LDAP Base DN for Searches`: the base DN for LDAP queries. To query all users, set this to `dc=company,dc=com`. - You can specify an OU if you divide your users up into different OUs and only want to query a specific OU. -At this point click `Save and Test LDAP Server Settings`. If the settings are correct you will see: +At this point, click `Save and Test LDAP Server Settings`. If the settings are correct, you will see: `Connect(Success); Bind(Success); Base Search (Found XY Entities)` - `LDAP User Filter`: This is used to a user filter on what users are allowed to login. **This must be set** - To allow all users: `(objectClass=user)` - To only allow users in a specific group: `(memberOf=cn=jellyfin_users,ou=groups,dc=company,dc=com)` - Good Docs on LDAP Filters: [atlassian.com](https://confluence.atlassian.com/kb/how-to-write-ldap-search-filters-792496933.html) -- `LDAP Admin Base DN`: All of the users in this DN are automatically set as admins. - - This can be left blank. Admins can be set manually outside of this filter +- `LDAP Admin Base DN`: All the users in this DN are automatically set as admins. + - This can be left blank. Admins can be set manually outside this filter - `LDAP Admin Filter`: Similar to the user filter, but every matched user is set as admin. - - This can be left blank. Admins can be set manually outside of this filter + - This can be left blank. Admins can be set manually outside this filter -At this point click `Save and Test LDAP Filter Settings`. If the settings are correct you will see: +At this point, click `Save and Test LDAP Filter Settings`. If the settings are correct, you will see: `Found X user(s), Y admin(s)` - `LDAP Attributes`: `uid, cn, mail, displayName` - `Enable case Insensitive Username`: **Checked** -At this point, enter in a username and click "Save Search Attribute Settings and Query User". If the settings are correct you will see: +At this point, enter a username and click "Save Search Attribute Settings and Query User". If the settings are correct, you will see: `Found User: cn=test,ou=users,dc=company,dc=com` - `Enabled User Creation`: **Checked** From 1b36cb833118e58808fcd69bb44eb1ca462b5fd4 Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:29:57 +0100 Subject: [PATCH 06/37] web: bump API Client version (#8059) Signed-off-by: GitHub Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 945ad5ee2..7cf43ae96 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.5-1704381512", + "@goauthentik/api": "^2023.10.5-1704382057", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", @@ -2913,9 +2913,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.10.5-1704381512", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.5-1704381512.tgz", - "integrity": "sha512-kB7OZCwNEKvlVzzEkiA3bx9qIJ4OA44qmQZQ03iI05DKIJWqU+CssDyHeMUGv5Vdma04xdf+3+BOzrc+ZJWX+A==" + "version": "2023.10.5-1704382057", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.5-1704382057.tgz", + "integrity": "sha512-nzmAQgTrFXiOwKDeHhq1gAfIMRilAcDPmNvjhqoQc3GQfWs5GG2lAGzIewWyxsfxNABsg+I0BYTPxN7ffD6tXw==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", diff --git a/web/package.json b/web/package.json index 78a4f32ef..0a27a1c86 100644 --- a/web/package.json +++ b/web/package.json @@ -42,7 +42,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.5-1704381512", + "@goauthentik/api": "^2023.10.5-1704382057", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", From 509b502d3c4abafbb9df7f6a106849f8e1b948e6 Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 4 Jan 2024 19:57:11 +0100 Subject: [PATCH 07/37] providers/oauth2: offline access (#8026) * improve scope check (log when application requests non-configured scopes) Signed-off-by: Jens Langhammer * add offline_access special scope Signed-off-by: Jens Langhammer * ensure scope is set Signed-off-by: Jens Langhammer * update tests for refresh tokens Signed-off-by: Jens Langhammer * special handling of scopes for github compat Signed-off-by: Jens Langhammer * fix spec Signed-off-by: Jens Langhammer * attempt to fix oidc tests Signed-off-by: Jens Langhammer * remove hardcoded slug Signed-off-by: Jens Langhammer * check scope from authorization code instead of request Signed-off-by: Jens Langhammer * fix injection for consent stage checking incorrectly Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/providers/oauth2/constants.py | 12 +- authentik/providers/oauth2/errors.py | 2 +- .../providers/oauth2/tests/test_authorize.py | 35 +++++- .../providers/oauth2/tests/test_token.py | 42 ++++++- authentik/providers/oauth2/urls_root.py | 2 +- authentik/providers/oauth2/views/authorize.py | 73 +++++++++---- authentik/providers/oauth2/views/token.py | 103 ++++++++++-------- blueprints/system/providers-oauth2.yaml | 11 ++ tests/e2e/test_provider_oauth2_github.py | 18 +-- tests/e2e/test_provider_oauth2_grafana.py | 88 ++++++++------- tests/e2e/test_provider_oidc.py | 77 ++++++++----- tests/e2e/test_provider_oidc_implicit.py | 53 +++++---- .../providers/oauth2/OAuth2ProviderForm.ts | 8 +- website/docs/providers/oauth2/index.md | 10 +- website/docs/releases/2024/v2024.1.md | 6 + 15 files changed, 369 insertions(+), 171 deletions(-) diff --git a/authentik/providers/oauth2/constants.py b/authentik/providers/oauth2/constants.py index 81460b707..baaebbd60 100644 --- a/authentik/providers/oauth2/constants.py +++ b/authentik/providers/oauth2/constants.py @@ -7,8 +7,8 @@ GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials" GRANT_TYPE_PASSWORD = "password" # nosec GRANT_TYPE_DEVICE_CODE = "urn:ietf:params:oauth:grant-type:device_code" -CLIENT_ASSERTION_TYPE = "client_assertion_type" CLIENT_ASSERTION = "client_assertion" +CLIENT_ASSERTION_TYPE = "client_assertion_type" CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" PROMPT_NONE = "none" @@ -18,9 +18,9 @@ PROMPT_LOGIN = "login" SCOPE_OPENID = "openid" SCOPE_OPENID_PROFILE = "profile" SCOPE_OPENID_EMAIL = "email" +SCOPE_OFFLINE_ACCESS = "offline_access" -# https://www.iana.org/assignments/oauth-parameters/\ -# oauth-parameters.xhtml#pkce-code-challenge-method +# https://www.iana.org/assignments/oauth-parameters/auth-parameters.xhtml#pkce-code-challenge-method PKCE_METHOD_PLAIN = "plain" PKCE_METHOD_S256 = "S256" @@ -36,6 +36,12 @@ SCOPE_GITHUB_USER_READ = "read:user" SCOPE_GITHUB_USER_EMAIL = "user:email" # Read info about teams SCOPE_GITHUB_ORG_READ = "read:org" +SCOPE_GITHUB = { + SCOPE_GITHUB_USER, + SCOPE_GITHUB_USER_READ, + SCOPE_GITHUB_USER_EMAIL, + SCOPE_GITHUB_ORG_READ, +} ACR_AUTHENTIK_DEFAULT = "goauthentik.io/providers/oauth2/default" diff --git a/authentik/providers/oauth2/errors.py b/authentik/providers/oauth2/errors.py index 1788c9370..fd124cb91 100644 --- a/authentik/providers/oauth2/errors.py +++ b/authentik/providers/oauth2/errors.py @@ -127,7 +127,7 @@ class AuthorizeError(OAuth2Error): "account_selection_required": ( "The End-User is required to select a session at the Authorization Server" ), - "consent_required": "The Authorization Server requires End-Userconsent", + "consent_required": "The Authorization Server requires End-User consent", "invalid_request_uri": ( "The request_uri in the Authorization Request returns an error or contains invalid data" ), diff --git a/authentik/providers/oauth2/tests/test_authorize.py b/authentik/providers/oauth2/tests/test_authorize.py index 91cdc330a..7903c685c 100644 --- a/authentik/providers/oauth2/tests/test_authorize.py +++ b/authentik/providers/oauth2/tests/test_authorize.py @@ -5,6 +5,7 @@ from django.test import RequestFactory from django.urls import reverse from django.utils.timezone import now +from authentik.blueprints.tests import apply_blueprint from authentik.core.models import Application from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.events.models import Event, EventAction @@ -18,6 +19,7 @@ from authentik.providers.oauth2.models import ( AuthorizationCode, GrantTypes, OAuth2Provider, + ScopeMapping, ) from authentik.providers.oauth2.tests.utils import OAuthTestCase from authentik.providers.oauth2.views.authorize import OAuthAuthorizationParams @@ -172,14 +174,24 @@ class TestAuthorize(OAuthTestCase): ) OAuthAuthorizationParams.from_request(request) + @apply_blueprint("system/providers-oauth2.yaml") def test_response_type(self): """test response_type""" - OAuth2Provider.objects.create( + provider = OAuth2Provider.objects.create( name=generate_id(), client_id="test", authorization_flow=create_test_flow(), redirect_uris="http://local.invalid/Foo", ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + managed__in=[ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + ] + ) + ) request = self.factory.get( "/", data={ @@ -292,6 +304,7 @@ class TestAuthorize(OAuthTestCase): delta=5, ) + @apply_blueprint("system/providers-oauth2.yaml") def test_full_implicit(self): """Test full authorization""" flow = create_test_flow() @@ -302,6 +315,15 @@ class TestAuthorize(OAuthTestCase): redirect_uris="http://localhost", signing_key=self.keypair, ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + managed__in=[ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + ] + ) + ) Application.objects.create(name="app", slug="app", provider=provider) state = generate_id() user = create_test_admin_user() @@ -409,6 +431,7 @@ class TestAuthorize(OAuthTestCase): delta=5, ) + @apply_blueprint("system/providers-oauth2.yaml") def test_full_form_post_id_token(self): """Test full authorization (form_post response)""" flow = create_test_flow() @@ -419,6 +442,15 @@ class TestAuthorize(OAuthTestCase): redirect_uris="http://localhost", signing_key=self.keypair, ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + managed__in=[ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + ] + ) + ) app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider) state = generate_id() user = create_test_admin_user() @@ -440,6 +472,7 @@ class TestAuthorize(OAuthTestCase): reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}), ) token: AccessToken = AccessToken.objects.filter(user=user).first() + self.assertIsNotNone(token) self.assertJSONEqual( response.content.decode(), { diff --git a/authentik/providers/oauth2/tests/test_token.py b/authentik/providers/oauth2/tests/test_token.py index 79b3b13fe..5904d38be 100644 --- a/authentik/providers/oauth2/tests/test_token.py +++ b/authentik/providers/oauth2/tests/test_token.py @@ -6,6 +6,7 @@ from django.test import RequestFactory from django.urls import reverse from django.utils import timezone +from authentik.blueprints.tests import apply_blueprint from authentik.core.models import Application from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.events.models import Event, EventAction @@ -21,6 +22,7 @@ from authentik.providers.oauth2.models import ( AuthorizationCode, OAuth2Provider, RefreshToken, + ScopeMapping, ) from authentik.providers.oauth2.tests.utils import OAuthTestCase from authentik.providers.oauth2.views.token import TokenParams @@ -136,21 +138,20 @@ class TestToken(OAuthTestCase): HTTP_AUTHORIZATION=f"Basic {header}", ) access: AccessToken = AccessToken.objects.filter(user=user, provider=provider).first() - refresh: RefreshToken = RefreshToken.objects.filter(user=user, provider=provider).first() self.assertJSONEqual( response.content.decode(), { "access_token": access.token, - "refresh_token": refresh.token, "token_type": TOKEN_TYPE, "expires_in": 3600, "id_token": provider.encode( - refresh.id_token.to_dict(), + access.id_token.to_dict(), ), }, ) self.validate_jwt(access, provider) + @apply_blueprint("system/providers-oauth2.yaml") def test_refresh_token_view(self): """test request param""" provider = OAuth2Provider.objects.create( @@ -159,6 +160,16 @@ class TestToken(OAuthTestCase): redirect_uris="http://local.invalid", signing_key=self.keypair, ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + managed__in=[ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + "goauthentik.io/providers/oauth2/scope-offline_access", + ] + ) + ) # Needs to be assigned to an application for iss to be set self.app.provider = provider self.app.save() @@ -170,6 +181,7 @@ class TestToken(OAuthTestCase): token=generate_id(), _id_token=dumps({}), auth_time=timezone.now(), + _scope="offline_access", ) response = self.client.post( reverse("authentik_providers_oauth2:token"), @@ -201,6 +213,7 @@ class TestToken(OAuthTestCase): ) self.validate_jwt(access, provider) + @apply_blueprint("system/providers-oauth2.yaml") def test_refresh_token_view_invalid_origin(self): """test request param""" provider = OAuth2Provider.objects.create( @@ -209,6 +222,16 @@ class TestToken(OAuthTestCase): redirect_uris="http://local.invalid", signing_key=self.keypair, ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + managed__in=[ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + "goauthentik.io/providers/oauth2/scope-offline_access", + ] + ) + ) header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode() user = create_test_admin_user() token: RefreshToken = RefreshToken.objects.create( @@ -217,6 +240,7 @@ class TestToken(OAuthTestCase): token=generate_id(), _id_token=dumps({}), auth_time=timezone.now(), + _scope="offline_access", ) response = self.client.post( reverse("authentik_providers_oauth2:token"), @@ -247,6 +271,7 @@ class TestToken(OAuthTestCase): }, ) + @apply_blueprint("system/providers-oauth2.yaml") def test_refresh_token_revoke(self): """test request param""" provider = OAuth2Provider.objects.create( @@ -255,6 +280,16 @@ class TestToken(OAuthTestCase): redirect_uris="http://testserver", signing_key=self.keypair, ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + managed__in=[ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", + "goauthentik.io/providers/oauth2/scope-offline_access", + ] + ) + ) # Needs to be assigned to an application for iss to be set self.app.provider = provider self.app.save() @@ -266,6 +301,7 @@ class TestToken(OAuthTestCase): token=generate_id(), _id_token=dumps({}), auth_time=timezone.now(), + _scope="offline_access", ) # Create initial refresh token response = self.client.post( diff --git a/authentik/providers/oauth2/urls_root.py b/authentik/providers/oauth2/urls_root.py index b00a90de4..9f7fe05ac 100644 --- a/authentik/providers/oauth2/urls_root.py +++ b/authentik/providers/oauth2/urls_root.py @@ -10,7 +10,7 @@ from authentik.providers.oauth2.views.token import TokenView github_urlpatterns = [ path( "login/oauth/authorize", - AuthorizationFlowInitView.as_view(), + AuthorizationFlowInitView.as_view(github_compat=True), name="github-authorize", ), path( diff --git a/authentik/providers/oauth2/views/authorize.py b/authentik/providers/oauth2/views/authorize.py index 520f02d65..7ad76a642 100644 --- a/authentik/providers/oauth2/views/authorize.py +++ b/authentik/providers/oauth2/views/authorize.py @@ -1,5 +1,5 @@ """authentik OAuth2 Authorization views""" -from dataclasses import dataclass, field +from dataclasses import InitVar, dataclass, field from datetime import timedelta from hashlib import sha256 from json import dumps @@ -41,6 +41,8 @@ from authentik.providers.oauth2.constants import ( PROMPT_CONSENT, PROMPT_LOGIN, PROMPT_NONE, + SCOPE_GITHUB, + SCOPE_OFFLINE_ACCESS, SCOPE_OPENID, TOKEN_TYPE, ) @@ -66,7 +68,6 @@ from authentik.stages.consent.models import ConsentMode, ConsentStage from authentik.stages.consent.stage import ( PLAN_CONTEXT_CONSENT_HEADER, PLAN_CONTEXT_CONSENT_PERMISSIONS, - ConsentStageView, ) LOGGER = get_logger() @@ -86,7 +87,7 @@ class OAuthAuthorizationParams: redirect_uri: str response_type: str response_mode: Optional[str] - scope: list[str] + scope: set[str] state: str nonce: Optional[str] prompt: set[str] @@ -101,8 +102,10 @@ class OAuthAuthorizationParams: code_challenge: Optional[str] = None code_challenge_method: Optional[str] = None + github_compat: InitVar[bool] = False + @staticmethod - def from_request(request: HttpRequest) -> "OAuthAuthorizationParams": + def from_request(request: HttpRequest, github_compat=False) -> "OAuthAuthorizationParams": """ Get all the params used by the Authorization Code Flow (and also for the Implicit and Hybrid). @@ -154,7 +157,7 @@ class OAuthAuthorizationParams: response_type=response_type, response_mode=response_mode, grant_type=grant_type, - scope=query_dict.get("scope", "").split(), + scope=set(query_dict.get("scope", "").split()), state=state, nonce=query_dict.get("nonce"), prompt=ALLOWED_PROMPT_PARAMS.intersection(set(query_dict.get("prompt", "").split())), @@ -162,9 +165,10 @@ class OAuthAuthorizationParams: max_age=int(max_age) if max_age else None, code_challenge=query_dict.get("code_challenge"), code_challenge_method=query_dict.get("code_challenge_method", "plain"), + github_compat=github_compat, ) - def __post_init__(self): + def __post_init__(self, github_compat=False): self.provider: OAuth2Provider = OAuth2Provider.objects.filter( client_id=self.client_id ).first() @@ -172,7 +176,7 @@ class OAuthAuthorizationParams: LOGGER.warning("Invalid client identifier", client_id=self.client_id) raise ClientIdError(client_id=self.client_id) self.check_redirect_uri() - self.check_scope() + self.check_scope(github_compat) self.check_nonce() self.check_code_challenge() @@ -199,8 +203,8 @@ class OAuthAuthorizationParams: if not any(fullmatch(x, self.redirect_uri) for x in allowed_redirect_urls): LOGGER.warning( "Invalid redirect uri (regex comparison)", - redirect_uri=self.redirect_uri, - expected=allowed_redirect_urls, + redirect_uri_given=self.redirect_uri, + redirect_uri_expected=allowed_redirect_urls, ) raise RedirectUriError(self.redirect_uri, allowed_redirect_urls) except RegexError as exc: @@ -208,8 +212,8 @@ class OAuthAuthorizationParams: if not any(x == self.redirect_uri for x in allowed_redirect_urls): LOGGER.warning( "Invalid redirect uri (strict comparison)", - redirect_uri=self.redirect_uri, - expected=allowed_redirect_urls, + redirect_uri_given=self.redirect_uri, + redirect_uri_expected=allowed_redirect_urls, ) raise RedirectUriError(self.redirect_uri, allowed_redirect_urls) if self.request: @@ -217,24 +221,50 @@ class OAuthAuthorizationParams: self.redirect_uri, "request_not_supported", self.grant_type, self.state ) - def check_scope(self): + def check_scope(self, github_compat=False): """Ensure openid scope is set in Hybrid flows, or when requesting an id_token""" - if len(self.scope) == 0: - default_scope_names = set( - ScopeMapping.objects.filter(provider__in=[self.provider]).values_list( - "scope_name", flat=True - ) + default_scope_names = set( + ScopeMapping.objects.filter(provider__in=[self.provider]).values_list( + "scope_name", flat=True ) + ) + if len(self.scope) == 0: self.scope = default_scope_names LOGGER.info( "No scopes requested, defaulting to all configured scopes", scopes=self.scope ) + scopes_to_check = self.scope + if github_compat: + scopes_to_check = self.scope - SCOPE_GITHUB + if not scopes_to_check.issubset(default_scope_names): + LOGGER.info( + "Application requested scopes not configured, setting to overlap", + scope_allowed=default_scope_names, + scope_given=self.scope, + ) + self.scope = self.scope.intersection(default_scope_names) if SCOPE_OPENID not in self.scope and ( self.grant_type == GrantTypes.HYBRID or self.response_type in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN] ): LOGGER.warning("Missing 'openid' scope.") raise AuthorizeError(self.redirect_uri, "invalid_scope", self.grant_type, self.state) + if SCOPE_OFFLINE_ACCESS in self.scope: + # https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess + if PROMPT_CONSENT not in self.prompt: + raise AuthorizeError( + self.redirect_uri, "consent_required", self.grant_type, self.state + ) + if self.response_type not in [ + ResponseTypes.CODE, + ResponseTypes.CODE_TOKEN, + ResponseTypes.CODE_ID_TOKEN, + ResponseTypes.CODE_ID_TOKEN_TOKEN, + ]: + # offline_access requires a response type that has some sort of token + # Spec says to ignore the scope when the response_type wouldn't result + # in an authorization code being generated + self.scope.remove(SCOPE_OFFLINE_ACCESS) def check_nonce(self): """Nonce parameter validation.""" @@ -297,6 +327,9 @@ class AuthorizationFlowInitView(PolicyAccessView): """OAuth2 Flow initializer, checks access to application and starts flow""" params: OAuthAuthorizationParams + # Enable GitHub compatibility (only allow for scopes which are handled + # differently for github compat) + github_compat = False def pre_permission_check(self): """Check prompt parameter before checking permission/authentication, @@ -305,7 +338,9 @@ class AuthorizationFlowInitView(PolicyAccessView): if len(self.request.GET) < 1: raise Http404 try: - self.params = OAuthAuthorizationParams.from_request(self.request) + self.params = OAuthAuthorizationParams.from_request( + self.request, github_compat=self.github_compat + ) except AuthorizeError as error: LOGGER.warning(error.description, redirect_uri=error.redirect_uri) raise RequestValidationError(error.get_response(self.request)) @@ -402,7 +437,7 @@ class AuthorizationFlowInitView(PolicyAccessView): # OpenID clients can specify a `prompt` parameter, and if its set to consent we # need to inject a consent stage if PROMPT_CONSENT in self.params.prompt: - if not any(isinstance(x.stage, ConsentStageView) for x in plan.bindings): + if not any(isinstance(x.stage, ConsentStage) for x in plan.bindings): # Plan does not have any consent stage, so we add an in-memory one stage = ConsentStage( name="OAuth2 Provider In-memory consent stage", diff --git a/authentik/providers/oauth2/views/token.py b/authentik/providers/oauth2/views/token.py index 93578d6ce..78931b6c8 100644 --- a/authentik/providers/oauth2/views/token.py +++ b/authentik/providers/oauth2/views/token.py @@ -41,6 +41,7 @@ from authentik.providers.oauth2.constants import ( GRANT_TYPE_PASSWORD, GRANT_TYPE_REFRESH_TOKEN, PKCE_METHOD_S256, + SCOPE_OFFLINE_ACCESS, TOKEN_TYPE, ) from authentik.providers.oauth2.errors import DeviceCodeError, TokenError, UserAuthError @@ -459,7 +460,7 @@ class TokenView(View): op="authentik.providers.oauth2.post.response", ): if self.params.grant_type == GRANT_TYPE_AUTHORIZATION_CODE: - LOGGER.debug("Converting authorization code to refresh token") + LOGGER.debug("Converting authorization code to access token") return TokenResponse(self.create_code_response()) if self.params.grant_type == GRANT_TYPE_REFRESH_TOKEN: LOGGER.debug("Refreshing refresh token") @@ -496,42 +497,47 @@ class TokenView(View): ) access_token.save() - refresh_token_expiry = now + timedelta_from_string(self.provider.refresh_token_validity) - refresh_token = RefreshToken( - user=self.params.authorization_code.user, - scope=self.params.authorization_code.scope, - expires=refresh_token_expiry, - provider=self.provider, - auth_time=self.params.authorization_code.auth_time, - session_id=self.params.authorization_code.session_id, - ) - id_token = IDToken.new( - self.provider, - refresh_token, - self.request, - ) - id_token.nonce = self.params.authorization_code.nonce - id_token.at_hash = access_token.at_hash - refresh_token.id_token = id_token - refresh_token.save() - - # Delete old code - self.params.authorization_code.delete() - return { + response = { "access_token": access_token.token, - "refresh_token": refresh_token.token, "token_type": TOKEN_TYPE, "expires_in": int( timedelta_from_string(self.provider.access_token_validity).total_seconds() ), - "id_token": id_token.to_jwt(self.provider), + "id_token": access_token.id_token.to_jwt(self.provider), } + if SCOPE_OFFLINE_ACCESS in self.params.authorization_code.scope: + refresh_token_expiry = now + timedelta_from_string(self.provider.refresh_token_validity) + refresh_token = RefreshToken( + user=self.params.authorization_code.user, + scope=self.params.authorization_code.scope, + expires=refresh_token_expiry, + provider=self.provider, + auth_time=self.params.authorization_code.auth_time, + session_id=self.params.authorization_code.session_id, + ) + id_token = IDToken.new( + self.provider, + refresh_token, + self.request, + ) + id_token.nonce = self.params.authorization_code.nonce + id_token.at_hash = access_token.at_hash + refresh_token.id_token = id_token + refresh_token.save() + response["refresh_token"] = refresh_token.token + + # Delete old code + self.params.authorization_code.delete() + return response + def create_refresh_response(self) -> dict[str, Any]: """See https://datatracker.ietf.org/doc/html/rfc6749#section-6""" unauthorized_scopes = set(self.params.scope) - set(self.params.refresh_token.scope) if unauthorized_scopes: raise TokenError("invalid_scope") + if SCOPE_OFFLINE_ACCESS not in self.params.scope: + raise TokenError("invalid_scope") now = timezone.now() access_token_expiry = now + timedelta_from_string(self.provider.access_token_validity) access_token = AccessToken( @@ -630,31 +636,34 @@ class TokenView(View): ) access_token.save() - refresh_token_expiry = now + timedelta_from_string(self.provider.refresh_token_validity) - refresh_token = RefreshToken( - user=self.params.device_code.user, - scope=self.params.device_code.scope, - expires=refresh_token_expiry, - provider=self.provider, - auth_time=auth_event.created if auth_event else now, - ) - id_token = IDToken.new( - self.provider, - refresh_token, - self.request, - ) - id_token.at_hash = access_token.at_hash - refresh_token.id_token = id_token - refresh_token.save() - - # Delete device code - self.params.device_code.delete() - return { + response = { "access_token": access_token.token, - "refresh_token": refresh_token.token, "token_type": TOKEN_TYPE, "expires_in": int( timedelta_from_string(self.provider.access_token_validity).total_seconds() ), - "id_token": id_token.to_jwt(self.provider), + "id_token": access_token.id_token.to_jwt(self.provider), } + + if SCOPE_OFFLINE_ACCESS in self.params.scope: + refresh_token_expiry = now + timedelta_from_string(self.provider.refresh_token_validity) + refresh_token = RefreshToken( + user=self.params.device_code.user, + scope=self.params.device_code.scope, + expires=refresh_token_expiry, + provider=self.provider, + auth_time=auth_event.created if auth_event else now, + ) + id_token = IDToken.new( + self.provider, + refresh_token, + self.request, + ) + id_token.at_hash = access_token.at_hash + refresh_token.id_token = id_token + refresh_token.save() + response["refresh_token"] = refresh_token.token + + # Delete device code + self.params.device_code.delete() + return response diff --git a/blueprints/system/providers-oauth2.yaml b/blueprints/system/providers-oauth2.yaml index eb4ca5442..0d2448202 100644 --- a/blueprints/system/providers-oauth2.yaml +++ b/blueprints/system/providers-oauth2.yaml @@ -45,3 +45,14 @@ entries: # groups is not part of the official userinfo schema, but is a quasi-standard "groups": [group.name for group in request.user.ak_groups.all()], } + - identifiers: + managed: goauthentik.io/providers/oauth2/scope-offline_access + model: authentik_providers_oauth2.scopemapping + attrs: + name: "authentik default OAuth Mapping: OpenID 'offline_access'" + scope_name: offline_access + description: "Access to request new tokens without interaction" + expression: | + # This scope grants the application a refresh token that can be used to refresh user data + # and let the application access authentik without the users interaction + return {} diff --git a/tests/e2e/test_provider_oauth2_github.py b/tests/e2e/test_provider_oauth2_github.py index 5e19dd146..5095421a8 100644 --- a/tests/e2e/test_provider_oauth2_github.py +++ b/tests/e2e/test_provider_oauth2_github.py @@ -74,7 +74,7 @@ class TestProviderOAuth2Github(SeleniumTestCase): slug="default-provider-authorization-implicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), client_id=self.client_id, client_secret=self.client_secret, client_type=ClientTypes.CONFIDENTIAL, @@ -82,8 +82,8 @@ class TestProviderOAuth2Github(SeleniumTestCase): authorization_flow=authorization_flow, ) Application.objects.create( - name="Grafana", - slug="grafana", + name=generate_id(), + slug=generate_id(), provider=provider, ) @@ -129,7 +129,7 @@ class TestProviderOAuth2Github(SeleniumTestCase): slug="default-provider-authorization-explicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), client_id=self.client_id, client_secret=self.client_secret, client_type=ClientTypes.CONFIDENTIAL, @@ -137,8 +137,8 @@ class TestProviderOAuth2Github(SeleniumTestCase): authorization_flow=authorization_flow, ) app = Application.objects.create( - name="Grafana", - slug="grafana", + name=generate_id(), + slug=generate_id(), provider=provider, ) @@ -200,7 +200,7 @@ class TestProviderOAuth2Github(SeleniumTestCase): slug="default-provider-authorization-explicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), client_id=self.client_id, client_secret=self.client_secret, client_type=ClientTypes.CONFIDENTIAL, @@ -208,8 +208,8 @@ class TestProviderOAuth2Github(SeleniumTestCase): authorization_flow=authorization_flow, ) app = Application.objects.create( - name="Grafana", - slug="grafana", + name=generate_id(), + slug=generate_id(), provider=provider, ) diff --git a/tests/e2e/test_provider_oauth2_grafana.py b/tests/e2e/test_provider_oauth2_grafana.py index 2538fae70..fa8f12d1d 100644 --- a/tests/e2e/test_provider_oauth2_grafana.py +++ b/tests/e2e/test_provider_oauth2_grafana.py @@ -14,6 +14,7 @@ from authentik.lib.generators import generate_id, generate_key from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.models import PolicyBinding from authentik.providers.oauth2.constants import ( + SCOPE_OFFLINE_ACCESS, SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE, @@ -80,7 +81,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): slug="default-provider-authorization-implicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), client_type=ClientTypes.CONFIDENTIAL, client_id=self.client_id, client_secret=self.client_secret, @@ -90,12 +91,17 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() Application.objects.create( - name="Grafana", + name=generate_id(), slug=self.app_slug, provider=provider, ) @@ -113,12 +119,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) - @apply_blueprint( - "system/providers-oauth2.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_authorization_consent_implied(self): """test OpenID Provider flow (default authorization flow with implied consent)""" @@ -128,7 +130,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): slug="default-provider-authorization-implicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), client_type=ClientTypes.CONFIDENTIAL, client_id=self.client_id, client_secret=self.client_secret, @@ -138,11 +140,16 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) Application.objects.create( - name="Grafana", + name=generate_id(), slug=self.app_slug, provider=provider, ) @@ -174,12 +181,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) - @apply_blueprint( - "system/providers-oauth2.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_authorization_logout(self): """test OpenID Provider flow with logout""" @@ -189,7 +192,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): slug="default-provider-authorization-implicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), client_type=ClientTypes.CONFIDENTIAL, client_id=self.client_id, client_secret=self.client_secret, @@ -199,12 +202,17 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() Application.objects.create( - name="Grafana", + name=generate_id(), slug=self.app_slug, provider=provider, ) @@ -244,12 +252,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-explicit-consent.yaml", - ) - @apply_blueprint( - "system/providers-oauth2.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-explicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_authorization_consent_explicit(self): """test OpenID Provider flow (default authorization flow with explicit consent)""" @@ -259,7 +263,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): slug="default-provider-authorization-explicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), authorization_flow=authorization_flow, client_type=ClientTypes.CONFIDENTIAL, client_id=self.client_id, @@ -269,12 +273,17 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() app = Application.objects.create( - name="Grafana", + name=generate_id(), slug=self.app_slug, provider=provider, ) @@ -323,12 +332,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-explicit-consent.yaml", - ) - @apply_blueprint( - "system/providers-oauth2.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-explicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_authorization_denied(self): """test OpenID Provider flow (default authorization with access deny)""" @@ -338,7 +343,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): slug="default-provider-authorization-explicit-consent" ) provider = OAuth2Provider.objects.create( - name="grafana", + name=generate_id(), authorization_flow=authorization_flow, client_type=ClientTypes.CONFIDENTIAL, client_id=self.client_id, @@ -348,12 +353,17 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() app = Application.objects.create( - name="Grafana", + name=generate_id(), slug=self.app_slug, provider=provider, ) diff --git a/tests/e2e/test_provider_oidc.py b/tests/e2e/test_provider_oidc.py index 3180f9534..c14a498a6 100644 --- a/tests/e2e/test_provider_oidc.py +++ b/tests/e2e/test_provider_oidc.py @@ -15,6 +15,7 @@ from authentik.lib.generators import generate_id, generate_key from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.models import PolicyBinding from authentik.providers.oauth2.constants import ( + SCOPE_OFFLINE_ACCESS, SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE, @@ -29,7 +30,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): def setUp(self): self.client_id = generate_id() self.client_secret = generate_key() - self.application_slug = "test" + self.application_slug = generate_id() super().setUp() def setup_client(self) -> Container: @@ -37,7 +38,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): sleep(1) client: DockerClient = from_env() container = client.containers.run( - image="ghcr.io/beryju/oidc-test-client:1.3", + image="ghcr.io/beryju/oidc-test-client:2.1", detach=True, ports={ "9009": "9009", @@ -56,9 +57,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") @reconcile_app("authentik_crypto") def test_redirect_uri_error(self): """test OpenID Provider flow (invalid redirect URI, check error message)""" @@ -78,10 +77,14 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) - provider.save() Application.objects.create( name=self.application_slug, slug=self.application_slug, @@ -101,13 +104,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) - @reconcile_app("authentik_crypto") + @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") @apply_blueprint("system/providers-oauth2.yaml") + @reconcile_app("authentik_crypto") def test_authorization_consent_implied(self): - """test OpenID Provider flow (default authorization flow with implied consent)""" + """test OpenID Provider flow (default authorization flow with implied consent) + (due to offline_access a consent will still be triggered)""" sleep(1) # Bootstrap all needed objects authorization_flow = Flow.objects.get( @@ -124,11 +126,15 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) - provider.save() - Application.objects.create( + app = Application.objects.create( name=self.application_slug, slug=self.application_slug, provider=provider, @@ -137,6 +143,20 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): self.driver.get("http://localhost:9009") self.login() + self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-flow-executor"))) + + flow_executor = self.get_shadow_root("ak-flow-executor") + consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor) + + self.assertIn( + app.name, + consent_stage.find_element(By.CSS_SELECTOR, "#header-text").text, + ) + consent_stage.find_element( + By.CSS_SELECTOR, + "[type=submit]", + ).click() + self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pre"))) self.wait.until(ec.text_to_be_present_in_element((By.CSS_SELECTOR, "pre"), "{")) body = loads(self.driver.find_element(By.CSS_SELECTOR, "pre").text) @@ -155,11 +175,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-explicit-consent.yaml", - ) - @reconcile_app("authentik_crypto") + @apply_blueprint("default/flow-default-provider-authorization-explicit-consent.yaml") @apply_blueprint("system/providers-oauth2.yaml") + @reconcile_app("authentik_crypto") def test_authorization_consent_explicit(self): """test OpenID Provider flow (default authorization flow with explicit consent)""" sleep(1) @@ -178,10 +196,14 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) - provider.save() app = Application.objects.create( name=self.application_slug, slug=self.application_slug, @@ -224,9 +246,8 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-explicit-consent.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-explicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_authorization_denied(self): """test OpenID Provider flow (default authorization with access deny)""" @@ -246,10 +267,14 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) - provider.save() app = Application.objects.create( name=self.application_slug, slug=self.application_slug, diff --git a/tests/e2e/test_provider_oidc_implicit.py b/tests/e2e/test_provider_oidc_implicit.py index c5d9d37d0..37dff0aa3 100644 --- a/tests/e2e/test_provider_oidc_implicit.py +++ b/tests/e2e/test_provider_oidc_implicit.py @@ -15,6 +15,7 @@ from authentik.lib.generators import generate_id, generate_key from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.models import PolicyBinding from authentik.providers.oauth2.constants import ( + SCOPE_OFFLINE_ACCESS, SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE, @@ -37,7 +38,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): sleep(1) client: DockerClient = from_env() container = client.containers.run( - image="ghcr.io/beryju/oidc-test-client:1.3", + image="ghcr.io/beryju/oidc-test-client:2.1", detach=True, ports={ "9009": "9009", @@ -56,9 +57,8 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_redirect_uri_error(self): """test OpenID Provider flow (invalid redirect URI, check error message)""" @@ -78,7 +78,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() @@ -101,11 +106,9 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) - @reconcile_app("authentik_crypto") + @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") @apply_blueprint("system/providers-oauth2.yaml") + @reconcile_app("authentik_crypto") def test_authorization_consent_implied(self): """test OpenID Provider flow (default authorization flow with implied consent)""" sleep(1) @@ -124,7 +127,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() @@ -150,11 +158,9 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-explicit-consent.yaml", - ) - @reconcile_app("authentik_crypto") + @apply_blueprint("default/flow-default-provider-authorization-explicit-consent.yaml") @apply_blueprint("system/providers-oauth2.yaml") + @reconcile_app("authentik_crypto") def test_authorization_consent_explicit(self): """test OpenID Provider flow (default authorization flow with explicit consent)""" sleep(1) @@ -173,7 +179,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() @@ -215,9 +226,8 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): "default/flow-default-authentication-flow.yaml", "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint( - "default/flow-default-provider-authorization-explicit-consent.yaml", - ) + @apply_blueprint("default/flow-default-provider-authorization-explicit-consent.yaml") + @apply_blueprint("system/providers-oauth2.yaml") @reconcile_app("authentik_crypto") def test_authorization_denied(self): """test OpenID Provider flow (default authorization with access deny)""" @@ -237,7 +247,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): ) provider.property_mappings.set( ScopeMapping.objects.filter( - scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + scope_name__in=[ + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, + SCOPE_OFFLINE_ACCESS, + ] ) ) provider.save() diff --git a/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts b/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts index 000df8cad..74f3acbeb 100644 --- a/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts +++ b/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts @@ -290,9 +290,13 @@ export class OAuth2ProviderFormPage extends BaseProviderForm { let selected = false; if (!provider?.propertyMappings) { selected = - scope.managed?.startsWith( + // By default select all managed scope mappings, except offline_access + (scope.managed?.startsWith( "goauthentik.io/providers/oauth2/scope-", - ) || false; + ) && + scope.managed !== + "goauthentik.io/providers/oauth2/scope-offline_access") || + false; } else { selected = Array.from(provider?.propertyMappings).some((su) => { return su == scope.pk; diff --git a/website/docs/providers/oauth2/index.md b/website/docs/providers/oauth2/index.md index 0eba63765..90ce75778 100644 --- a/website/docs/providers/oauth2/index.md +++ b/website/docs/providers/oauth2/index.md @@ -35,12 +35,20 @@ To access the user's email address, a scope of `user:email` is required. To acce ### `authorization_code`: -This grant is used to convert an authorization code to a refresh token. The authorization code is retrieved through the Authorization flow, and can only be used once, and expires quickly. +This grant is used to convert an authorization code to an access token (and optionally refresh token). The authorization code is retrieved through the Authorization flow, and can only be used once, and expires quickly. + +:::info +Starting with authentik 2024.1, applications only receive an access token. To receive a refresh token, applications must be allowed to request the `offline_access` scope in authentik and also be configured to request the scope. +::: ### `refresh_token`: Refresh tokens can be used as long-lived tokens to access user data, and further renew the refresh token down the road. +:::info +Starting with authentik 2024.1, this grant requires the `offline_access` scope. +::: + ### `client_credentials`: See [Machine-to-machine authentication](./client_credentials) diff --git a/website/docs/releases/2024/v2024.1.md b/website/docs/releases/2024/v2024.1.md index c6ffd0f28..e9f31fc55 100644 --- a/website/docs/releases/2024/v2024.1.md +++ b/website/docs/releases/2024/v2024.1.md @@ -17,6 +17,12 @@ slug: "/releases/2024.1" - `authentik_outpost_radius_requests_rejected` -> `authentik_outpost_radius_requests_rejected_total` - `authentik_main_requests` -> `authentik_main_request_duration_seconds` +- Required `offline_access` scope for Refresh tokens + + The OAuth2 provider ships with a new default scope called `offline_access`, which must be requested by applications that need a refresh token. Previously, authentik would always issue a refresh token for the _Authorization code_ and _Device code_ OAuth grants. + + Applications which require will need their configuration update to include the `offline_access` scope mapping. + ## New features - "Pretend user exists" option for Identification stage From 827591d3763f90b92328a3def3b14555ac5a4227 Mon Sep 17 00:00:00 2001 From: Tana M Berry Date: Thu, 4 Jan 2024 13:32:44 -0600 Subject: [PATCH 08/37] website/docs: add link to our example flows (#8052) add link to our example flows Co-authored-by: Tana Berry --- website/docs/flow/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/flow/index.md b/website/docs/flow/index.md index d13ea1e5e..0fd0c510c 100644 --- a/website/docs/flow/index.md +++ b/website/docs/flow/index.md @@ -65,4 +65,6 @@ This designates a flow for general setup. This designation doesn't have any cons Flows can be imported and exported to share with other people, the community and for troubleshooting. Flows can be imported to apply new functionality and apply existing workflows. +Download our [Example flows](./examples/flows.md) and then import them into your authentik instance. + Starting with authentik 2022.8, flows will be exported as YAML, but JSON-based flows can still be imported. From 053062f60643633f016fbe5581d227167477870b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:54:24 +0100 Subject: [PATCH 09/37] core: bump golang.org/x/sync from 0.5.0 to 0.6.0 (#8065) Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.5.0 to 0.6.0. - [Commits](https://github.com/golang/sync/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ed9759796..744bd9b38 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( goauthentik.io/api/v3 v3.2023105.3 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 - golang.org/x/sync v0.5.0 + golang.org/x/sync v0.6.0 gopkg.in/yaml.v2 v2.4.0 layeh.com/radius v0.0.0-20210819152912-ad72663a72ab ) diff --git a/go.sum b/go.sum index 3000d744b..78106579a 100644 --- a/go.sum +++ b/go.sum @@ -415,8 +415,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 268fb840fd97bff4ca5064c06fa3b2fc4a46c272 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:54:40 +0100 Subject: [PATCH 10/37] web: bump the sentry group in /web with 2 updates (#8064) Bumps the sentry group in /web with 2 updates: [@sentry/browser](https://github.com/getsentry/sentry-javascript) and [@sentry/tracing](https://github.com/getsentry/sentry-javascript). Updates `@sentry/browser` from 7.91.0 to 7.92.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.91.0...7.92.0) Updates `@sentry/tracing` from 7.91.0 to 7.92.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/7.91.0...7.92.0) --- updated-dependencies: - dependency-name: "@sentry/browser" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sentry - dependency-name: "@sentry/tracing" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sentry ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 92 +++++++++++++++++++++---------------------- web/package.json | 4 +- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 7cf43ae96..c1d00d83d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -24,8 +24,8 @@ "@open-wc/lit-helpers": "^0.6.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", - "@sentry/browser": "^7.91.0", - "@sentry/tracing": "^7.91.0", + "@sentry/browser": "^7.92.0", + "@sentry/tracing": "^7.92.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", @@ -4751,98 +4751,98 @@ ] }, "node_modules/@sentry-internal/feedback": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.91.0.tgz", - "integrity": "sha512-SJKTSaz68F5YIwF79EttBm915M2LnacgZMYRnRumyTmMKnebGhYQLwWbZdpaDvOa1U18dgRajDX8Qed/8A3tXw==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.92.0.tgz", + "integrity": "sha512-/jEALRtVqboxB9kcK2tag8QCO6XANTlGBb9RV3oeGXJe0DDNJXRq6wVZbfgztXJRrfgx4XVDcNt1pRVoGGG++g==", "dependencies": { - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/core": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.91.0.tgz", - "integrity": "sha512-JH5y6gs6BS0its7WF2DhySu7nkhPDfZcdpAXldxzIlJpqFkuwQKLU5nkYJpiIyZz1NHYYtW5aum2bV2oCOdDRA==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.92.0.tgz", + "integrity": "sha512-ur55vPcUUUWFUX4eVLNP71ohswK7ZZpleNZw9Y1GfLqyI+0ILQUwjtzqItJrdClvVsdRZJMRmDV40Hp9Lbb9mA==", "dependencies": { - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/core": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.91.0.tgz", - "integrity": "sha512-lJv3x/xekzC/biiyAsVCioq2XnKNOZhI6jY3ZzLJZClYV8eKRi7D3KCsHRvMiCdGak1d/6sVp8F4NYY+YiWy1Q==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.92.0.tgz", + "integrity": "sha512-loMr02/zQ38u8aQhYLtIBg0i5n3ps2e3GUXrt3CdsJQdkRYfa62gcrE7SzvoEpMVHTk7VOI4fWGht8cWw/1k3A==", "dependencies": { - "@sentry-internal/feedback": "7.91.0", - "@sentry-internal/tracing": "7.91.0", - "@sentry/core": "7.91.0", - "@sentry/replay": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry-internal/feedback": "7.92.0", + "@sentry-internal/tracing": "7.92.0", + "@sentry/core": "7.92.0", + "@sentry/replay": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.91.0.tgz", - "integrity": "sha512-tu+gYq4JrTdrR+YSh5IVHF0fJi/Pi9y0HZ5H9HnYy+UMcXIotxf6hIEaC6ZKGeLWkGXffz2gKpQLe/g6vy/lPA==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.92.0.tgz", + "integrity": "sha512-1Tly7YB2I1byI5xb0Cwrxs56Rhww+6mQ7m9P7rTmdC3/ijOzbEoohtYIUPwcooCEarpbEJe/tAayRx6BrH2UbQ==", "dependencies": { - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.91.0.tgz", - "integrity": "sha512-XwbesnLLNtaVXKtDoyBB96GxJuhGi9zy3a662Ba/McmumCnkXrMQYpQPh08U7MgkTyDRgjDwm7PXDhiKpcb03g==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.92.0.tgz", + "integrity": "sha512-G1t9Uvc9cR8VpNkElwvHIMGzykjIKikb10n0tfVd3e+rBPMCCjCPWOduwG6jZYxcvCjTpqmJh6NSLXxL/Mt4JA==", "dependencies": { - "@sentry-internal/tracing": "7.91.0", - "@sentry/core": "7.91.0", - "@sentry/types": "7.91.0", - "@sentry/utils": "7.91.0" + "@sentry-internal/tracing": "7.92.0", + "@sentry/core": "7.92.0", + "@sentry/types": "7.92.0", + "@sentry/utils": "7.92.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/tracing": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.91.0.tgz", - "integrity": "sha512-IlSAMvqfCL/2TwwN4Tmk6bGMgilGruv5oIJ1GMenVZk53bHwjpjzMbd0ms8+S5zJwAgTQXoCbRhaFFrNmptteQ==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.92.0.tgz", + "integrity": "sha512-1+TFFPVEdax4dNi68gin6MENiyGe9mOuNXfjulrP5eCzUEByus5HAxeDI/LLQ1hArfn048AzwSwKUsS2fO5sbg==", "dependencies": { - "@sentry-internal/tracing": "7.91.0" + "@sentry-internal/tracing": "7.92.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.91.0.tgz", - "integrity": "sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.92.0.tgz", + "integrity": "sha512-APmSOuZuoRGpbPpPeYIbMSplPjiWNLZRQa73QiXuTflW4Tu/ItDlU8hOa2+A6JKVkJCuD2EN6yUrxDGSMyNXeg==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.91.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.91.0.tgz", - "integrity": "sha512-fvxjrEbk6T6Otu++Ax9ntlQ0sGRiwSC179w68aC3u26Wr30FAIRKqHTCCdc2jyWk7Gd9uWRT/cq+g8NG/8BfSg==", + "version": "7.92.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.92.0.tgz", + "integrity": "sha512-3nEfrQ1z28b/2zgFGANPh5yMVtgwXmrasZxTvKbrAj+KWJpjrJHrIR84r9W277J44NMeZ5RhRW2uoDmuBslPnA==", "dependencies": { - "@sentry/types": "7.91.0" + "@sentry/types": "7.92.0" }, "engines": { "node": ">=8" diff --git a/web/package.json b/web/package.json index 0a27a1c86..18ee93b7f 100644 --- a/web/package.json +++ b/web/package.json @@ -49,8 +49,8 @@ "@open-wc/lit-helpers": "^0.6.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", - "@sentry/browser": "^7.91.0", - "@sentry/tracing": "^7.91.0", + "@sentry/browser": "^7.92.0", + "@sentry/tracing": "^7.92.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.1", From 018cda43b75b766c9f6e003ed958b4e8f6002fc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:55:25 +0100 Subject: [PATCH 11/37] website: bump postcss from 8.4.32 to 8.4.33 in /website (#8063) Bumps [postcss](https://github.com/postcss/postcss) from 8.4.32 to 8.4.33. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.32...8.4.33) --- updated-dependencies: - dependency-name: postcss dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 8 ++++---- website/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 743f24714..1a9e56e78 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -18,7 +18,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^2.1.0", "disqus-react": "^1.1.5", - "postcss": "^8.4.32", + "postcss": "^8.4.33", "prism-react-renderer": "^2.3.1", "rapidoc": "^9.3.4", "react": "^18.2.0", @@ -13137,9 +13137,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "funding": [ { "type": "opencollective", diff --git a/website/package.json b/website/package.json index 7773daee1..dcd3cb350 100644 --- a/website/package.json +++ b/website/package.json @@ -25,7 +25,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^2.1.0", "disqus-react": "^1.1.5", - "postcss": "^8.4.32", + "postcss": "^8.4.33", "prism-react-renderer": "^2.3.1", "rapidoc": "^9.3.4", "react-before-after-slider-component": "^1.1.8", From ffb78484dabf4f503040db1b5872f9c0da09aec4 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:55:42 +0100 Subject: [PATCH 12/37] translate: Updates for file web/xliff/en.xlf in zh-Hans (#8062) Translate web/xliff/en.xlf in zh-Hans 100% translated source file: 'web/xliff/en.xlf' on 'zh-Hans'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh-Hans.xlf | 50 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index d1572b445..1ab18589c 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8206,10 +8206,12 @@ Bindings to groups/users are checked against the user of the event. Provider require enterprise. + 提供程序需要企业版。 Learn more + 了解更多 - + \ No newline at end of file From 67c130302dcfee77399f316a737d0322dd0e542a Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:55:58 +0100 Subject: [PATCH 13/37] translate: Updates for file web/xliff/en.xlf in zh_CN (#8061) Translate web/xliff/en.xlf in zh_CN 100% translated source file: 'web/xliff/en.xlf' on 'zh_CN'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh_CN.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web/xliff/zh_CN.xlf b/web/xliff/zh_CN.xlf index ea9939a67..3bbeaddb9 100644 --- a/web/xliff/zh_CN.xlf +++ b/web/xliff/zh_CN.xlf @@ -8203,6 +8203,14 @@ Bindings to groups/users are checked against the user of the event. Determines how long a session lasts before being disconnected and requiring re-authorization. 设置会话在被断开连接并需要重新授权之前持续的时间。 + + + Provider require enterprise. + 提供程序需要企业版。 + + + Learn more + 了解更多 From 259d5e6181301f147fd80ec889b465e9f2274dd9 Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 5 Jan 2024 13:13:21 +0100 Subject: [PATCH 14/37] web/flows: fix device picker incorrect foreground color (#8067) Signed-off-by: Jens Langhammer --- .../authenticator_validate/AuthenticatorValidateStage.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts b/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts index 351b890d6..403a80756 100644 --- a/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts +++ b/web/src/flow/stages/authenticator_validate/AuthenticatorValidateStage.ts @@ -89,6 +89,9 @@ export class AuthenticatorValidateStage display: flex; align-items: center; } + :host([theme="dark"]) .authenticator-button { + color: var(--ak-dark-foreground) !important; + } i { font-size: 1.5rem; padding: 1rem 0; From cd61cb38478110e71ecc49af44a82692fe66abdd Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 5 Jan 2024 13:13:32 +0100 Subject: [PATCH 15/37] rbac: fix error when looking up permissions for now uninstalled apps (#8068) Signed-off-by: Jens Langhammer --- authentik/rbac/api/rbac_roles.py | 5 ++++- authentik/rbac/api/rbac_users.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/authentik/rbac/api/rbac_roles.py b/authentik/rbac/api/rbac_roles.py index 1c48169a2..1ef13c115 100644 --- a/authentik/rbac/api/rbac_roles.py +++ b/authentik/rbac/api/rbac_roles.py @@ -24,7 +24,10 @@ class ExtraRoleObjectPermissionSerializer(RoleObjectPermissionSerializer): def get_app_label_verbose(self, instance: GroupObjectPermission) -> str: """Get app label from permission's model""" - return apps.get_app_config(instance.content_type.app_label).verbose_name + try: + return apps.get_app_config(instance.content_type.app_label).verbose_name + except LookupError: + return instance.content_type.app_label def get_model_verbose(self, instance: GroupObjectPermission) -> str: """Get model label from permission's model""" diff --git a/authentik/rbac/api/rbac_users.py b/authentik/rbac/api/rbac_users.py index 636b327f3..6de2e8bce 100644 --- a/authentik/rbac/api/rbac_users.py +++ b/authentik/rbac/api/rbac_users.py @@ -24,7 +24,10 @@ class ExtraUserObjectPermissionSerializer(UserObjectPermissionSerializer): def get_app_label_verbose(self, instance: UserObjectPermission) -> str: """Get app label from permission's model""" - return apps.get_app_config(instance.content_type.app_label).verbose_name + try: + return apps.get_app_config(instance.content_type.app_label).verbose_name + except LookupError: + return instance.content_type.app_label def get_model_verbose(self, instance: UserObjectPermission) -> str: """Get model label from permission's model""" From 78396717fec7b6b95d6d799f75c9073d5b42170c Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 5 Jan 2024 17:27:53 +0100 Subject: [PATCH 16/37] providers/oauth2: fix missing nonce in id_token (#8072) Signed-off-by: Jens Langhammer --- authentik/providers/oauth2/views/token.py | 1 + 1 file changed, 1 insertion(+) diff --git a/authentik/providers/oauth2/views/token.py b/authentik/providers/oauth2/views/token.py index 78931b6c8..b5aaf6b0d 100644 --- a/authentik/providers/oauth2/views/token.py +++ b/authentik/providers/oauth2/views/token.py @@ -495,6 +495,7 @@ class TokenView(View): access_token, self.request, ) + access_token.id_token.nonce = self.params.authorization_code.nonce access_token.save() response = { From c8b35b9b21b47034c55e1e4e886c067093c7031a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 18:58:03 +0100 Subject: [PATCH 17/37] core: bump goauthentik.io/api/v3 from 3.2023105.3 to 3.2023105.5 (#8066) Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023105.3 to 3.2023105.5. - [Release notes](https://github.com/goauthentik/client-go/releases) - [Commits](https://github.com/goauthentik/client-go/compare/v3.2023105.3...v3.2023105.5) --- updated-dependencies: - dependency-name: goauthentik.io/api/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 744bd9b38..5d56f4030 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/wwt/guac v1.3.2 - goauthentik.io/api/v3 v3.2023105.3 + goauthentik.io/api/v3 v3.2023105.5 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 golang.org/x/sync v0.6.0 diff --git a/go.sum b/go.sum index 78106579a..ae7dc3b6f 100644 --- a/go.sum +++ b/go.sum @@ -316,8 +316,8 @@ go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYO go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= 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.2023105.3 h1:x0pMJIKkbN198OOssqA94h8bO6ft9gwG8bpZqZL7WVg= -goauthentik.io/api/v3 v3.2023105.3/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= +goauthentik.io/api/v3 v3.2023105.5 h1:wIL3Q0jry1g4kRWpH/Dv1sQqhzuL4BLC+uP/Tar1P/g= +goauthentik.io/api/v3 v3.2023105.5/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= From c77ea41af0bf1ab7d63d46b04e2f5f64eaa9d6d3 Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 5 Jan 2024 19:03:15 +0100 Subject: [PATCH 18/37] providers/oauth2: fix missing nonce in token endpoint not being saved (#8073) Signed-off-by: Jens Langhammer --- authentik/providers/oauth2/views/token.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/authentik/providers/oauth2/views/token.py b/authentik/providers/oauth2/views/token.py index b5aaf6b0d..3bf134b09 100644 --- a/authentik/providers/oauth2/views/token.py +++ b/authentik/providers/oauth2/views/token.py @@ -490,12 +490,13 @@ class TokenView(View): auth_time=self.params.authorization_code.auth_time, session_id=self.params.authorization_code.session_id, ) - access_token.id_token = IDToken.new( + access_id_token = IDToken.new( self.provider, access_token, self.request, ) - access_token.id_token.nonce = self.params.authorization_code.nonce + access_id_token.nonce = self.params.authorization_code.nonce + access_token.id_token = access_id_token access_token.save() response = { From 3e44e9d3f66eea26500cf0ed58c64f6861167404 Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 5 Jan 2024 19:10:27 +0100 Subject: [PATCH 19/37] stages/user_login: only set last_ip in session if a binding is given (#8074) --- authentik/stages/user_login/middleware.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/authentik/stages/user_login/middleware.py b/authentik/stages/user_login/middleware.py index 8fea4c408..73e42e1ac 100644 --- a/authentik/stages/user_login/middleware.py +++ b/authentik/stages/user_login/middleware.py @@ -109,7 +109,10 @@ class BoundSessionMiddleware(SessionMiddleware): self.recheck_session_geo(configured_binding_geo, last_ip, new_ip) # If we got to this point without any error being raised, we need to # update the last saved IP to the current one - request.session[SESSION_KEY_LAST_IP] = new_ip + if SESSION_KEY_BINDING_NET in request.session or SESSION_KEY_BINDING_GEO in request.session: + # Only set the last IP in the session if there's a binding specified + # (== basically requires the user to be logged in) + request.session[SESSION_KEY_LAST_IP] = new_ip AuthenticatedSession.objects.filter(session_key=request.session.session_key).update( last_ip=new_ip, last_user_agent=request.META.get("HTTP_USER_AGENT", "") ) From 058dda5d0a4f2b17fa715b055472b976b5f671e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:13:31 +0100 Subject: [PATCH 20/37] website: bump @types/react from 18.2.46 to 18.2.47 in /website (#8088) Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.46 to 18.2.47. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 8 ++++---- website/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 1a9e56e78..e03cb069b 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -33,7 +33,7 @@ "@docusaurus/module-type-aliases": "3.0.1", "@docusaurus/tsconfig": "3.0.1", "@docusaurus/types": "3.0.1", - "@types/react": "^18.2.46", + "@types/react": "^18.2.47", "prettier": "3.1.1", "typescript": "~5.3.3" }, @@ -4373,9 +4373,9 @@ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" }, "node_modules/@types/react": { - "version": "18.2.46", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.46.tgz", - "integrity": "sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==", + "version": "18.2.47", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", + "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", diff --git a/website/package.json b/website/package.json index dcd3cb350..37ba114a8 100644 --- a/website/package.json +++ b/website/package.json @@ -52,7 +52,7 @@ "@docusaurus/module-type-aliases": "3.0.1", "@docusaurus/tsconfig": "3.0.1", "@docusaurus/types": "3.0.1", - "@types/react": "^18.2.46", + "@types/react": "^18.2.47", "prettier": "3.1.1", "typescript": "~5.3.3" }, From e5815154f9d3bda2a728efa388c668d88d063858 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:13:40 +0100 Subject: [PATCH 21/37] web: bump the eslint group in /tests/wdio with 2 updates (#8086) Bumps the eslint group in /tests/wdio with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 6.17.0 to 6.18.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.17.0 to 6.18.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 88 ++++++++++++++++++------------------ tests/wdio/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 3d56efbe1..25720ba07 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -7,8 +7,8 @@ "name": "@goauthentik/web-tests", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", @@ -946,16 +946,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", - "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", + "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/type-utils": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/type-utils": "6.18.0", + "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -981,15 +981,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", - "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", + "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4" }, "engines": { @@ -1009,13 +1009,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", - "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", + "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0" + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1026,13 +1026,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", - "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", + "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/utils": "6.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1053,9 +1053,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", - "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", + "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1066,13 +1066,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", - "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", + "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1118,17 +1118,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", - "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", + "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", "semver": "^7.5.4" }, "engines": { @@ -1143,12 +1143,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", - "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", + "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/types": "6.18.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 768dabac3..477652a15 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -4,8 +4,8 @@ "type": "module", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", From cd0adfcfaa4ebbae2494282af132b999f6ee8ef9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:13:49 +0100 Subject: [PATCH 22/37] core: bump github.com/redis/go-redis/v9 from 9.3.1 to 9.4.0 (#8085) Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.3.1 to 9.4.0. - [Release notes](https://github.com/redis/go-redis/releases) - [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md) - [Commits](https://github.com/redis/go-redis/compare/v9.3.1...v9.4.0) --- updated-dependencies: - dependency-name: github.com/redis/go-redis/v9 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5d56f4030..aadc18f18 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/pires/go-proxyproto v0.7.0 github.com/prometheus/client_golang v1.18.0 - github.com/redis/go-redis/v9 v9.3.1 + github.com/redis/go-redis/v9 v9.4.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index ae7dc3b6f..fcbdc7618 100644 --- a/go.sum +++ b/go.sum @@ -258,8 +258,8 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/redis/go-redis/v9 v9.3.1 h1:KqdY8U+3X6z+iACvumCNxnoluToB+9Me+TvyFa21Mds= -github.com/redis/go-redis/v9 v9.3.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk= +github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= From c2433689cb2e2b03b47deb59b3615b137228d890 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:13:57 +0100 Subject: [PATCH 23/37] web: bump rollup from 4.9.2 to 4.9.4 in /web (#8083) Bumps [rollup](https://github.com/rollup/rollup) from 4.9.2 to 4.9.4. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.9.2...v4.9.4) --- updated-dependencies: - dependency-name: rollup dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 121 ++++++++++++++++++++++-------------------- web/package.json | 2 +- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index c1d00d83d..3386a9b0f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -92,7 +92,7 @@ "pyright": "=1.1.338", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.9.2", + "rollup": "^4.9.4", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", @@ -4582,9 +4582,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz", - "integrity": "sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.4.tgz", + "integrity": "sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==", "cpu": [ "arm" ], @@ -4595,9 +4595,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz", - "integrity": "sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.4.tgz", + "integrity": "sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==", "cpu": [ "arm64" ], @@ -4608,9 +4608,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz", - "integrity": "sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.4.tgz", + "integrity": "sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==", "cpu": [ "arm64" ], @@ -4621,9 +4621,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz", - "integrity": "sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.4.tgz", + "integrity": "sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==", "cpu": [ "x64" ], @@ -4634,9 +4634,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz", - "integrity": "sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.4.tgz", + "integrity": "sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==", "cpu": [ "arm" ], @@ -4647,9 +4647,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz", - "integrity": "sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.4.tgz", + "integrity": "sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==", "cpu": [ "arm64" ], @@ -4660,9 +4660,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz", - "integrity": "sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.4.tgz", + "integrity": "sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==", "cpu": [ "arm64" ], @@ -4673,9 +4673,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz", - "integrity": "sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.4.tgz", + "integrity": "sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==", "cpu": [ "riscv64" ], @@ -4686,9 +4686,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz", - "integrity": "sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.4.tgz", + "integrity": "sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==", "cpu": [ "x64" ], @@ -4699,9 +4699,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz", - "integrity": "sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.4.tgz", + "integrity": "sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==", "cpu": [ "x64" ], @@ -4712,9 +4712,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz", - "integrity": "sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.4.tgz", + "integrity": "sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==", "cpu": [ "arm64" ], @@ -4725,9 +4725,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz", - "integrity": "sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.4.tgz", + "integrity": "sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==", "cpu": [ "ia32" ], @@ -4738,9 +4738,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz", - "integrity": "sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.4.tgz", + "integrity": "sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==", "cpu": [ "x64" ], @@ -7265,9 +7265,9 @@ "dev": true }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/express": { @@ -16419,10 +16419,13 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/rollup": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.2.tgz", - "integrity": "sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.4.tgz", + "integrity": "sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -16431,19 +16434,19 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.2", - "@rollup/rollup-android-arm64": "4.9.2", - "@rollup/rollup-darwin-arm64": "4.9.2", - "@rollup/rollup-darwin-x64": "4.9.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.2", - "@rollup/rollup-linux-arm64-gnu": "4.9.2", - "@rollup/rollup-linux-arm64-musl": "4.9.2", - "@rollup/rollup-linux-riscv64-gnu": "4.9.2", - "@rollup/rollup-linux-x64-gnu": "4.9.2", - "@rollup/rollup-linux-x64-musl": "4.9.2", - "@rollup/rollup-win32-arm64-msvc": "4.9.2", - "@rollup/rollup-win32-ia32-msvc": "4.9.2", - "@rollup/rollup-win32-x64-msvc": "4.9.2", + "@rollup/rollup-android-arm-eabi": "4.9.4", + "@rollup/rollup-android-arm64": "4.9.4", + "@rollup/rollup-darwin-arm64": "4.9.4", + "@rollup/rollup-darwin-x64": "4.9.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.4", + "@rollup/rollup-linux-arm64-gnu": "4.9.4", + "@rollup/rollup-linux-arm64-musl": "4.9.4", + "@rollup/rollup-linux-riscv64-gnu": "4.9.4", + "@rollup/rollup-linux-x64-gnu": "4.9.4", + "@rollup/rollup-linux-x64-musl": "4.9.4", + "@rollup/rollup-win32-arm64-msvc": "4.9.4", + "@rollup/rollup-win32-ia32-msvc": "4.9.4", + "@rollup/rollup-win32-x64-msvc": "4.9.4", "fsevents": "~2.3.2" } }, diff --git a/web/package.json b/web/package.json index 18ee93b7f..56ce778e6 100644 --- a/web/package.json +++ b/web/package.json @@ -117,7 +117,7 @@ "pyright": "=1.1.338", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.9.2", + "rollup": "^4.9.4", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", From 7dff30357278ca81c28512f669883071b37caf80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:14:05 +0100 Subject: [PATCH 24/37] web: bump the eslint group in /web with 2 updates (#8082) Bumps the eslint group in /web with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 6.17.0 to 6.18.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.17.0 to 6.18.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 88 +++++++++++++++++++++---------------------- web/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 3386a9b0f..64006c368 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -74,8 +74,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", @@ -7576,16 +7576,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", - "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", + "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/type-utils": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/type-utils": "6.18.0", + "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -7644,15 +7644,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", - "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", + "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4" }, "engines": { @@ -7672,13 +7672,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", - "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", + "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0" + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7689,13 +7689,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", - "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", + "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/utils": "6.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -7716,9 +7716,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", - "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", + "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7729,13 +7729,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", - "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", + "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7814,17 +7814,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", - "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", + "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", "semver": "^7.5.4" }, "engines": { @@ -7872,12 +7872,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", - "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", + "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/types": "6.18.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/web/package.json b/web/package.json index 56ce778e6..5f50add27 100644 --- a/web/package.json +++ b/web/package.json @@ -99,8 +99,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.17.0", - "@typescript-eslint/parser": "^6.17.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", From c9dc500a2b2ed37bc0e04a29d7e0eb47dc5203b9 Mon Sep 17 00:00:00 2001 From: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:27:09 -0800 Subject: [PATCH 25/37] web: update some locale details (#8090) This commit adds "Polish" and "Korean" to the list of languages recognized by the web-UI, and updates the XLIFF files to include a few new strings from the RAC project. --- web/lit-localize.json | 13 +++-- .../elements/ak-locale-context/definitions.ts | 2 + web/src/locale-codes.ts | 6 +++ web/xliff/de.xlf | 6 +++ web/xliff/en.xlf | 6 +++ web/xliff/es.xlf | 6 +++ web/xliff/fr.xlf | 6 +++ web/xliff/pl.xlf | 6 +++ web/xliff/pseudo-LOCALE.xlf | 6 +++ web/xliff/tr.xlf | 6 +++ web/xliff/zh-Hans.xlf | 54 ++++++++++--------- web/xliff/zh-Hant.xlf | 6 +++ web/xliff/zh_TW.xlf | 6 +++ 13 files changed, 100 insertions(+), 29 deletions(-) diff --git a/web/lit-localize.json b/web/lit-localize.json index 19a901a91..3c9564de8 100644 --- a/web/lit-localize.json +++ b/web/lit-localize.json @@ -3,15 +3,18 @@ "sourceLocale": "en", "targetLocales": [ "en", - "pseudo-LOCALE", - "fr", - "tr", + "de", "es", + "fr", + "ko", + "nl", "pl", - "zh_TW", + "tr", "zh-Hans", "zh-Hant", - "de" + "zh-CN", + "zh_TW", + "pseudo-LOCALE" ], "tsConfig": "./tsconfig.json", "output": { diff --git a/web/src/elements/ak-locale-context/definitions.ts b/web/src/elements/ak-locale-context/definitions.ts index e920e85b1..018c9e2a1 100644 --- a/web/src/elements/ak-locale-context/definitions.ts +++ b/web/src/elements/ak-locale-context/definitions.ts @@ -46,6 +46,8 @@ const LOCALE_TABLE: LocaleRow[] = [ ["es", /^es([_-]|$)/i, () => msg("Spanish"), async () => await import("@goauthentik/locales/es")], ["de", /^de([_-]|$)/i, () => msg("German"), async () => await import("@goauthentik/locales/de")], ["fr", /^fr([_-]|$)/i, () => msg("French"), async () => await import("@goauthentik/locales/fr")], + ["ko", /^ko([_-]|$)/i, () => msg("Korean"), async () => await import("@goauthentik/locales/ko")], + ["nl", /^nl([_-]|$)/i, () => msg("Dutch"), async () => await import("@goauthentik/locales/nl")], ["pl", /^pl([_-]|$)/i, () => msg("Polish"), async () => await import("@goauthentik/locales/pl")], ["tr", /^tr([_-]|$)/i, () => msg("Turkish"), async () => await import("@goauthentik/locales/tr")], ["zh-Hant", /^zh[_-](HK|Hant)/i, () => msg("Chinese (traditional)"), async () => await import("@goauthentik/locales/zh-Hant")], diff --git a/web/src/locale-codes.ts b/web/src/locale-codes.ts index 86337dc8d..8b7a36ac1 100644 --- a/web/src/locale-codes.ts +++ b/web/src/locale-codes.ts @@ -15,10 +15,13 @@ export const targetLocales = [ `en`, `es`, `fr`, + `ko`, + `nl`, `pl`, `pseudo-LOCALE`, `tr`, `zh_TW`, + `zh-CN`, `zh-Hans`, `zh-Hant`, ] as const; @@ -32,10 +35,13 @@ export const allLocales = [ `en`, `es`, `fr`, + `ko`, + `nl`, `pl`, `pseudo-LOCALE`, `tr`, `zh_TW`, + `zh-CN`, `zh-Hans`, `zh-Hant`, ] as const; diff --git a/web/xliff/de.xlf b/web/xliff/de.xlf index 403d08256..a28d3a09a 100644 --- a/web/xliff/de.xlf +++ b/web/xliff/de.xlf @@ -6243,6 +6243,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index a8c3a759b..aa3e928a1 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -6519,6 +6519,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index ece851727..a4758ca1e 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -6159,6 +6159,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index 3bac1b49b..10d1a6d1d 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -8207,6 +8207,12 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index a0e16c3be..664ee86ff 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -6367,6 +6367,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index 217082220..7fd1fd51f 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -8105,4 +8105,10 @@ Bindings to groups/users are checked against the user of the event. Learn more + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. + diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index f2cd5d161..d1d4dcd55 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -6152,6 +6152,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 1ab18589c..387f668c8 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8211,7 +8211,13 @@ Bindings to groups/users are checked against the user of the event. Learn more 了解更多 + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. - \ No newline at end of file + diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index 35b356efa..4895e7c21 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -6200,6 +6200,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index 8ec2bf521..c9cb3fb1e 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -8089,6 +8089,12 @@ Bindings to groups/users are checked against the user of the event. Learn more + + + Maximum concurrent connections + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. From d555c0db41cf20b4b1d427a65a4f10f24ce6500c Mon Sep 17 00:00:00 2001 From: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> Date: Mon, 8 Jan 2024 10:22:52 -0800 Subject: [PATCH 26/37] web: abstract `rootInterface()?.config?.capabilities.includes()` into `.can()` (#7737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This commit abstracts access to the object `rootInterface()?.config?` into a single accessor, `authentikConfig`, that can be mixed into any AKElement object that requires access to it. Since access to `rootInterface()?.config?` is _universally_ used for a single (and repetitive) boolean check, a separate accessor has been provided that converts all calls of the form: ``` javascript rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) ``` into: ``` javascript this.can(CapabilitiesEnum.CanImpersonate) ``` It does this via a Mixin, `WithCapabilitiesConfig`, which understands that these calls only make sense in the context of a running, fully configured authentik instance, and that their purpose is to inform authentik components of a user’s capabilities. The latter is why I don’t feel uncomfortable turning a function call into a method; we should make it explicit that this is a relationship between components. The mixin has a single single field, `[WCC.capabilitiesConfig]`, where its association with the upper-level configuration is made. If that syntax looks peculiar to you, good! I’ve used an explict unique symbol as the field name; it is inaccessable an innumerable in the object list. The debugger shows it only as: Symbol(): { cacheTimeout: 300 cacheTimeoutFlows: 300 cacheTimeoutPolicies: 300 cacheTimeoutReputation: 300 capabilities: (5) ['can_save_media', 'can_geo_ip', 'can_impersonate', 'can_debug', 'is_enterprise'] } Since you can’t reference it by identity, you can’t write to it. Until every browser supports actual private fields, this is the best we can do; it does guarantee that field name collisions are impossible, which is a win. The mixin takes a second optional boolean; setting this to true will cause any web component using the mixin to automatically schedule a re-render if the capabilities list changes. The mixin is also generic; despite the "...into a Lit-Context" in the title, the internals of the Mixin can be replaced with anything so long as the signature of `.can()` is preserved. Because this work builds off the work I did to give the Sidebar access to the configuration without ad-hoc retrieval or prop-drilling, it wasn’t necessary to create a new context for it. That will be necessary for the following: TODO: ``` javascript rootInterface()?.uiConfig; rootInterface()?.tenant; me(); ``` * web: Added a README with a description of the applications' "mental model," essentially an architectural description. * web: prettier had opinions about the README * web: Jens requested that subscription be by default, and it's the right call. * This commit abstracts access to the object `rootInterface()?.config?` into a single accessor, `authentikConfig`, that can be mixed into any AKElement object that requires access to it. Since access to `rootInterface()?.config?` is _universally_ used for a single (and repetitive) boolean check, a separate accessor has been provided that converts all calls of the form: ``` javascript rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) ``` into: ``` javascript this.can(CapabilitiesEnum.CanImpersonate) ``` It does this via a Mixin, `WithCapabilitiesConfig`, which understands that these calls only make sense in the context of a running, fully configured authentik instance, and that their purpose is to inform authentik components of a user’s capabilities. The latter is why I don’t feel uncomfortable turning a function call into a method; we should make it explicit that this is a relationship between components. The mixin has a single single field, `[WCC.capabilitiesConfig]`, where its association with the upper-level configuration is made. If that syntax looks peculiar to you, good! I’ve used an explict unique symbol as the field name; it is inaccessable an innumerable in the object list. The debugger shows it only as: Symbol(): { cacheTimeout: 300 cacheTimeoutFlows: 300 cacheTimeoutPolicies: 300 cacheTimeoutReputation: 300 capabilities: (5) ['can_save_media', 'can_geo_ip', 'can_impersonate', 'can_debug', 'is_enterprise'] } Since you can’t reference it by identity, you can’t write to it. Until every browser supports actual private fields, this is the best we can do; it does guarantee that field name collisions are impossible, which is a win. The mixin takes a second optional boolean; setting this to true will cause any web component using the mixin to automatically schedule a re-render if the capabilities list changes. The mixin is also generic; despite the "...into a Lit-Context" in the title, the internals of the Mixin can be replaced with anything so long as the signature of `.can()` is preserved. Because this work builds off the work I did to give the Sidebar access to the configuration without ad-hoc retrieval or prop-drilling, it wasn’t necessary to create a new context for it. That will be necessary for the following: TODO: ``` javascript rootInterface()?.uiConfig; rootInterface()?.tenant; me(); ``` * web: Added a README with a description of the applications' "mental model," essentially an architectural description. * web: prettier had opinions about the README * web: Jens requested that subscription be by default, and it's the right call. * web: adjust RAC to point to the (now independent) Interface. - Also, removed redundant check. --- web/README.md | 86 +++++++++++++++++++ .../admin/AdminInterface/AdminInterface.ts | 2 +- web/src/admin/AdminInterface/AdminSidebar.ts | 17 ++-- .../admin/admin-overview/AdminOverviewPage.ts | 5 +- web/src/admin/applications/ApplicationForm.ts | 32 +++---- web/src/admin/flows/FlowForm.ts | 16 ++-- web/src/admin/groups/GroupViewPage.ts | 2 +- web/src/admin/groups/RelatedUserList.ts | 10 ++- .../admin/sources/oauth/OAuthSourceForm.ts | 10 ++- web/src/admin/sources/plex/PlexSourceForm.ts | 15 ++-- web/src/admin/sources/saml/SAMLSourceForm.ts | 10 ++- web/src/admin/users/UserListPage.ts | 18 ++-- web/src/admin/users/UserViewPage.ts | 8 +- web/src/elements/Base.ts | 69 ++------------- web/src/elements/Interface/Interface.ts | 67 +++++++++++++++ .../Interface/authentikConfigProvider.ts | 20 +++++ .../Interface/capabilitiesProvider.ts | 69 +++++++++++++++ web/src/elements/Interface/index.ts | 4 + web/src/elements/types.ts | 3 + web/src/elements/utils/ensureCSSStyleSheet.ts | 4 + web/src/enterprise/rac/index.ts | 2 +- web/src/flow/FlowExecutor.ts | 2 +- web/src/flow/stages/prompt/PromptStage.ts | 15 ++-- web/src/standalone/api-browser/index.ts | 2 +- web/src/standalone/loading/index.ts | 2 +- web/src/stories/interface.ts | 2 +- web/src/user/UserInterface.ts | 2 +- 27 files changed, 343 insertions(+), 151 deletions(-) create mode 100644 web/src/elements/Interface/Interface.ts create mode 100644 web/src/elements/Interface/authentikConfigProvider.ts create mode 100644 web/src/elements/Interface/capabilitiesProvider.ts create mode 100644 web/src/elements/Interface/index.ts create mode 100644 web/src/elements/types.ts create mode 100644 web/src/elements/utils/ensureCSSStyleSheet.ts diff --git a/web/README.md b/web/README.md index 24cc5c622..9a8c1c846 100644 --- a/web/README.md +++ b/web/README.md @@ -3,6 +3,92 @@ This is the default UI for the authentik server. The documentation is going to be a little sparse for awhile, but at least let's get started. +# The Theory of the authentik UI + +In Peter Naur's 1985 essay [Programming as Theory +Building](https://pages.cs.wisc.edu/~remzi/Naur.pdf), programming is described as creating a mental +model of how a program _should_ run, then writing the code to test if the program _can_ run that +way. + +The mental model for the authentik UI is straightforward. There are five "applications" within the +UI, each with its own base URL, router, and responsibilities, and each application needs as many as +three contexts in which to run. + +The three contexts corresponds to objects in the API's `model` section, so let's use those names. + +- The root `Config`. The root configuration object of the server, containing mostly caching and + error reporting information. This is misleading, however; the `Config` object contains some user + information, specifically a list of permissions the current user (or "no user") has. +- The root `CurrentTenant`. This describes the `Brand` information UIs should use, such as themes, + logos, favicon, and specific default flows for logging in, logging out, and recovering a user + password. +- The current `SessionUser`, the person logged in: username, display name, and various states. + (Note: the authentik server permits administrators to "impersonate" any other user in order to + debug their authentikation experience. If impersonation is active, the `user` field reflects that + user, but it also includes a field, `original`, with the administrator's information.) + +(There is a fourth context object, Version, but its use is limited to displaying version information +and checking for upgrades. Just be aware that you will see it, but you will probably never interact +with it.) + +There are five applications. Two (`loading` and `api-browser`) are trivial applications whose +insides are provided by third-party libraries (Patternfly and Rapidoc, respectively). The other +three are actual applications. The descriptions below are wholly from the view of the user's +experience: + +- `Flow`: From a given URL, displays a form that requests information from the user to accomplish a + task. Some tasks require the user to be logged in, but many (such as logging in itself!) + obviously do not. +- `User`: Provides the user with access to the applications they can access, plus a few user + settings. +- `Admin`: Provides someone with super-user permissions access to the administrative functions of + the authentik server. + +**Mental Model** + +- Upon initialization, _every_ authentik UI application fetches `Config` and `CurrentTenant`. `User` + and `Admin` will also attempt to load the `SessionUser`; if there is none, the user is kicked out + to the `Flow` for logging into authentik itself. +- `Config`, `CurrentTenant`, and `SessionUser`, are provided by the `@goauthentik/api` application, + not by the codebase under `./web`. (Where you are now). +- `Flow`, `User`, and `Admin` are all called `Interfaces` and are found in + `./web/src/flow/FlowInterface`, `./web/src/user/UserInterface`, `./web/src/admin/AdminInterface`, + respectively. + +Inside each of these you will find, in a hierarchal order: + +- The context layer described above + - A theme managing layer + - The orchestration layer: + - web socket handler for server-generated events + - The router + - Individual routes for each vertical slice and its relationship to other objects: + +Each slice corresponds to an object table on the server, and each slice _usually_ consists of the +following: + +- A paginated collection display, usually using the `Table` foundation (found in + `./web/src/elements/Table`) +- The ability to view an individual object from the collection, which you may be able to: + - Edit + - Delete +- A form for creating a new object +- Tabs showing that object's relationship to other objects + - Interactive elements for changing or deleting those relationships, or creating new ones. + - The ability to create new objects with which to have that relationship, if they're not part of + the core objects (such as User->MFA authenticator apps, since the latter is not a "core" object + and has no tab of its own). + +We are still a bit "all over the place" with respect to sub-units and common units; there are +folders `common`, `elements`, and `components`, and ideally they would be: + +- `common`: non-UI related libraries all of our applications need +- `elements`: UI elements shared among multiple applications that do not need context +- `components`: UI elements shared among multiple that use one or more context + +... but at the moment there are some context-sensitive elements, and some UI-related stuff in +`common`. + # Comments **NOTE:** The comments in this section are for specific changes to this repository that cannot be diff --git a/web/src/admin/AdminInterface/AdminInterface.ts b/web/src/admin/AdminInterface/AdminInterface.ts index 834c98f37..0f1a59ccd 100644 --- a/web/src/admin/AdminInterface/AdminInterface.ts +++ b/web/src/admin/AdminInterface/AdminInterface.ts @@ -7,7 +7,7 @@ import { import { configureSentry } from "@goauthentik/common/sentry"; import { me } from "@goauthentik/common/users"; import { WebsocketClient } from "@goauthentik/common/ws"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/elements/enterprise/EnterpriseStatusBanner"; import "@goauthentik/elements/messages/MessageContainer"; diff --git a/web/src/admin/AdminInterface/AdminSidebar.ts b/web/src/admin/AdminInterface/AdminSidebar.ts index 2f973ca7e..dcced7304 100644 --- a/web/src/admin/AdminInterface/AdminSidebar.ts +++ b/web/src/admin/AdminInterface/AdminSidebar.ts @@ -1,23 +1,25 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EVENT_SIDEBAR_TOGGLE, VERSION } from "@goauthentik/common/constants"; import { me } from "@goauthentik/common/users"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; import { AKElement } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route"; import { getRootStyle } from "@goauthentik/elements/utils/getRootStyle"; import { spread } from "@open-wc/lit-helpers"; -import { consume } from "@lit-labs/context"; import { msg, str } from "@lit/localize"; import { TemplateResult, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { map } from "lit/directives/map.js"; -import { AdminApi, CapabilitiesEnum, CoreApi, UiThemeEnum, Version } from "@goauthentik/api"; -import type { Config, SessionUser, UserSelf } from "@goauthentik/api"; +import { AdminApi, CoreApi, UiThemeEnum, Version } from "@goauthentik/api"; +import type { SessionUser, UserSelf } from "@goauthentik/api"; @customElement("ak-admin-sidebar") -export class AkAdminSidebar extends AKElement { +export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) { @property({ type: Boolean, reflect: true }) open = true; @@ -27,9 +29,6 @@ export class AkAdminSidebar extends AKElement { @state() impersonation: UserSelf["username"] | null = null; - @consume({ context: authentikConfigContext }) - public config!: Config; - constructor() { super(); new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then((version) => { @@ -200,7 +199,7 @@ export class AkAdminSidebar extends AKElement { } renderEnterpriseMessage() { - return this.config?.capabilities.includes(CapabilitiesEnum.IsEnterprise) + return this.can(CapabilitiesEnum.IsEnterprise) ? html` ${msg("Enterprise")} diff --git a/web/src/admin/admin-overview/AdminOverviewPage.ts b/web/src/admin/admin-overview/AdminOverviewPage.ts index a7e210a7c..9b79f5334 100644 --- a/web/src/admin/admin-overview/AdminOverviewPage.ts +++ b/web/src/admin/admin-overview/AdminOverviewPage.ts @@ -74,10 +74,7 @@ export class AdminOverviewPage extends AKElement { } render(): TemplateResult { - let name = this.user?.user.username; - if (this.user?.user.name) { - name = this.user.user.name; - } + const name = this.user?.user.name ?? this.user?.user.username; return html` ${msg(str`Welcome, ${name}.`)} diff --git a/web/src/admin/applications/ApplicationForm.ts b/web/src/admin/applications/ApplicationForm.ts index 970b3638e..ead17e9b2 100644 --- a/web/src/admin/applications/ApplicationForm.ts +++ b/web/src/admin/applications/ApplicationForm.ts @@ -1,13 +1,16 @@ import "@goauthentik/admin/applications/ProviderSelectModal"; import { iconHelperText } from "@goauthentik/admin/helperText"; -import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-file-input"; import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; import "@goauthentik/components/ak-textarea-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/ModalForm"; @@ -22,13 +25,7 @@ import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { - Application, - CapabilitiesEnum, - CoreApi, - PolicyEngineMode, - Provider, -} from "@goauthentik/api"; +import { Application, CoreApi, PolicyEngineMode, Provider } from "@goauthentik/api"; import "./components/ak-backchannel-input"; import "./components/ak-provider-search-input"; @@ -48,7 +45,7 @@ export const policyOptions = [ ]; @customElement("ak-application-form") -export class ApplicationForm extends ModelForm { +export class ApplicationForm extends WithCapabilitiesConfig(ModelForm) { constructor() { super(); this.handleConfirmBackchannelProviders = this.handleConfirmBackchannelProviders.bind(this); @@ -93,8 +90,7 @@ export class ApplicationForm extends ModelForm { applicationRequest: data, }); } - const c = await config(); - if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) { + if (this.can(CapabilitiesEnum.CanSaveMedia)) { const icon = this.getFormFiles()["metaIcon"]; if (icon || this.clearIcon) { await new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({ @@ -140,21 +136,21 @@ export class ApplicationForm extends ModelForm { return html`
{ @@ -209,11 +205,11 @@ export class ApplicationForm extends ModelForm { )} > - ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.metaIcon diff --git a/web/src/admin/flows/FlowForm.ts b/web/src/admin/flows/FlowForm.ts index 1d279070f..3925f6db9 100644 --- a/web/src/admin/flows/FlowForm.ts +++ b/web/src/admin/flows/FlowForm.ts @@ -1,8 +1,11 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/utils"; import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum"; -import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; @@ -14,7 +17,6 @@ import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { - CapabilitiesEnum, DeniedActionEnum, Flow, FlowDesignationEnum, @@ -24,7 +26,7 @@ import { } from "@goauthentik/api"; @customElement("ak-flow-form") -export class FlowForm extends ModelForm { +export class FlowForm extends WithCapabilitiesConfig(ModelForm) { async loadInstance(pk: string): Promise { const flow = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesRetrieve({ slug: pk, @@ -54,8 +56,8 @@ export class FlowForm extends ModelForm { flowRequest: data, }); } - const c = await config(); - if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) { + + if (this.can(CapabilitiesEnum.CanSaveMedia)) { const icon = this.getFormFiles()["background"]; if (icon || this.clearBackground) { await new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({ @@ -340,7 +342,7 @@ export class FlowForm extends ModelForm { - ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` diff --git a/web/src/admin/groups/RelatedUserList.ts b/web/src/admin/groups/RelatedUserList.ts index 2474ee2fe..27450fb82 100644 --- a/web/src/admin/groups/RelatedUserList.ts +++ b/web/src/admin/groups/RelatedUserList.ts @@ -10,6 +10,10 @@ import { uiConfig } from "@goauthentik/common/ui/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-status-label"; import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/Dropdown"; import "@goauthentik/elements/forms/DeleteBulkForm"; @@ -33,7 +37,6 @@ import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; import { - CapabilitiesEnum, CoreApi, CoreUsersListTypeEnum, Group, @@ -107,7 +110,7 @@ export class RelatedUserAdd extends Form<{ users: number[] }> { } @customElement("ak-user-related-list") -export class RelatedUserList extends Table { +export class RelatedUserList extends WithCapabilitiesConfig(Table) { expandable = true; checkbox = true; @@ -188,8 +191,7 @@ export class RelatedUserList extends Table { row(item: User): TemplateResult[] { const canImpersonate = - rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) && - item.pk !== this.me?.user.pk; + this.can(CapabilitiesEnum.CanImpersonate) && item.pk !== this.me?.user.pk; return [ html`
${item.username}
diff --git a/web/src/admin/sources/oauth/OAuthSourceForm.ts b/web/src/admin/sources/oauth/OAuthSourceForm.ts index cf0209fcb..92763bf7b 100644 --- a/web/src/admin/sources/oauth/OAuthSourceForm.ts +++ b/web/src/admin/sources/oauth/OAuthSourceForm.ts @@ -4,9 +4,12 @@ import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/CodeMirror"; import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -17,7 +20,6 @@ import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { - CapabilitiesEnum, FlowsInstancesListDesignationEnum, OAuthSource, OAuthSourceRequest, @@ -28,7 +30,7 @@ import { } from "@goauthentik/api"; @customElement("ak-source-oauth-form") -export class OAuthSourceForm extends BaseSourceForm { +export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { async loadInstance(pk: string): Promise { const source = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthRetrieve({ slug: pk, @@ -318,7 +320,7 @@ export class OAuthSourceForm extends BaseSourceForm { />

${placeholderHelperText}

- ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon diff --git a/web/src/admin/sources/plex/PlexSourceForm.ts b/web/src/admin/sources/plex/PlexSourceForm.ts index 8091067ff..8444e1112 100644 --- a/web/src/admin/sources/plex/PlexSourceForm.ts +++ b/web/src/admin/sources/plex/PlexSourceForm.ts @@ -2,10 +2,13 @@ import "@goauthentik/admin/common/ak-flow-search/ak-source-flow-search"; import { iconHelperText, placeholderHelperText } from "@goauthentik/admin/helperText"; import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; -import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -16,7 +19,6 @@ import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { - CapabilitiesEnum, FlowsInstancesListDesignationEnum, PlexSource, SourcesApi, @@ -24,7 +26,7 @@ import { } from "@goauthentik/api"; @customElement("ak-source-plex-form") -export class PlexSourceForm extends BaseSourceForm { +export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { async loadInstance(pk: string): Promise { const source = await new SourcesApi(DEFAULT_CONFIG).sourcesPlexRetrieve({ slug: pk, @@ -63,8 +65,7 @@ export class PlexSourceForm extends BaseSourceForm { plexSourceRequest: data, }); } - const c = await config(); - if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) { + if (this.can(CapabilitiesEnum.CanSaveMedia)) { const icon = this.getFormFiles()["icon"]; if (icon || this.clearIcon) { await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconCreate({ @@ -255,7 +256,7 @@ export class PlexSourceForm extends BaseSourceForm { />

${placeholderHelperText}

- ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon diff --git a/web/src/admin/sources/saml/SAMLSourceForm.ts b/web/src/admin/sources/saml/SAMLSourceForm.ts index 76e996322..c969411fb 100644 --- a/web/src/admin/sources/saml/SAMLSourceForm.ts +++ b/web/src/admin/sources/saml/SAMLSourceForm.ts @@ -5,7 +5,10 @@ import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/Radio"; @@ -18,7 +21,6 @@ import { ifDefined } from "lit/directives/if-defined.js"; import { BindingTypeEnum, - CapabilitiesEnum, DigestAlgorithmEnum, FlowsInstancesListDesignationEnum, NameIdPolicyEnum, @@ -29,7 +31,7 @@ import { } from "@goauthentik/api"; @customElement("ak-source-saml-form") -export class SAMLSourceForm extends BaseSourceForm { +export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { @state() clearIcon = false; @@ -149,7 +151,7 @@ export class SAMLSourceForm extends BaseSourceForm { - ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia) + ${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon diff --git a/web/src/admin/users/UserListPage.ts b/web/src/admin/users/UserListPage.ts index 1d861b568..e9d0c6f09 100644 --- a/web/src/admin/users/UserListPage.ts +++ b/web/src/admin/users/UserListPage.ts @@ -12,6 +12,10 @@ import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-status-label"; import { rootInterface } from "@goauthentik/elements/Base"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import { PFSize } from "@goauthentik/elements/Spinner"; import "@goauthentik/elements/TreeView"; import "@goauthentik/elements/buttons/ActionButton"; @@ -33,14 +37,7 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css"; import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; -import { - CapabilitiesEnum, - CoreApi, - ResponseError, - SessionUser, - User, - UserPath, -} from "@goauthentik/api"; +import { CoreApi, ResponseError, SessionUser, User, UserPath } from "@goauthentik/api"; export const requestRecoveryLink = (user: User) => new CoreApi(DEFAULT_CONFIG) @@ -93,7 +90,7 @@ const recoveryButtonStyles = css` `; @customElement("ak-user-list") -export class UserListPage extends TablePage { +export class UserListPage extends WithCapabilitiesConfig(TablePage) { expandable = true; checkbox = true; @@ -244,8 +241,7 @@ export class UserListPage extends TablePage { row(item: User): TemplateResult[] { const canImpersonate = - rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) && - item.pk !== this.me?.user.pk; + this.can(CapabilitiesEnum.CanImpersonate) && item.pk !== this.me?.user.pk; return [ html`
${item.username}
diff --git a/web/src/admin/users/UserViewPage.ts b/web/src/admin/users/UserViewPage.ts index 6ef77aa51..ddc9e92ba 100644 --- a/web/src/admin/users/UserViewPage.ts +++ b/web/src/admin/users/UserViewPage.ts @@ -22,8 +22,9 @@ import { import "@goauthentik/components/ak-status-label"; import "@goauthentik/components/events/ObjectChangelog"; import "@goauthentik/components/events/UserEvents"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; import "@goauthentik/elements/CodeMirror"; +import { WithCapabilitiesConfig } from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/PageHeader"; import { PFSize } from "@goauthentik/elements/Spinner"; import "@goauthentik/elements/Tabs"; @@ -60,7 +61,7 @@ import { import "./UserDevicesTable"; @customElement("ak-user-view") -export class UserViewPage extends AKElement { +export class UserViewPage extends WithCapabilitiesConfig(AKElement) { @property({ type: Number }) set userId(id: number) { me().then((me) => { @@ -163,8 +164,7 @@ export class UserViewPage extends AKElement { renderActionButtons(user: User) { const canImpersonate = - rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) && - user.pk !== this.me?.user.pk; + this.can(CapabilitiesEnum.CanImpersonate) && user.pk !== this.me?.user.pk; return html`
diff --git a/web/src/elements/Base.ts b/web/src/elements/Base.ts index 46c983aad..09a2d2858 100644 --- a/web/src/elements/Base.ts +++ b/web/src/elements/Base.ts @@ -1,20 +1,18 @@ -import { config, tenant } from "@goauthentik/common/api/config"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; -import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; +import { UIConfig } from "@goauthentik/common/ui/config"; import { adaptCSS } from "@goauthentik/common/utils"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; +import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; -import { ContextProvider } from "@lit-labs/context"; import { localized } from "@lit/localize"; -import { CSSResult, LitElement } from "lit"; -import { state } from "lit/decorators.js"; +import { LitElement } from "lit"; import AKGlobal from "@goauthentik/common/styles/authentik.css"; import ThemeDark from "@goauthentik/common/styles/theme-dark.css"; -import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api"; +import { AdoptedStyleSheetsElement } from "./types"; + type AkInterface = HTMLElement & { getTheme: () => Promise; tenant?: CurrentTenant; @@ -25,13 +23,6 @@ type AkInterface = HTMLElement & { export const rootInterface = (): T | undefined => (document.body.querySelector("[data-ak-interface-root]") as T) ?? undefined; -export function ensureCSSStyleSheet(css: CSSStyleSheet | CSSResult): CSSStyleSheet { - if (css instanceof CSSResult) { - return css.styleSheet!; - } - return css; -} - let css: Promise | undefined; function fetchCustomCSS(): Promise { if (!css) { @@ -52,10 +43,6 @@ function fetchCustomCSS(): Promise { return css; } -export interface AdoptedStyleSheetsElement { - adoptedStyleSheets: readonly CSSStyleSheet[]; -} - const QUERY_MEDIA_COLOR_LIGHT = "(prefers-color-scheme: light)"; @localized() @@ -175,49 +162,3 @@ export class AKElement extends LitElement { this.requestUpdate(); } } - -export class Interface extends AKElement implements AkInterface { - @state() - tenant?: CurrentTenant; - - @state() - uiConfig?: UIConfig; - - _configContext = new ContextProvider(this, { - context: authentikConfigContext, - initialValue: undefined, - }); - - _config?: Config; - - @state() - set config(c: Config) { - this._config = c; - this._configContext.setValue(c); - this.requestUpdate(); - } - - get config(): Config | undefined { - return this._config; - } - - constructor() { - super(); - document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; - tenant().then((tenant) => (this.tenant = tenant)); - config().then((config) => (this.config = config)); - this.dataset.akInterfaceRoot = "true"; - } - - _activateTheme(root: AdoptedStyleSheetsElement, theme: UiThemeEnum): void { - super._activateTheme(root, theme); - super._activateTheme(document, theme); - } - - async getTheme(): Promise { - if (!this.uiConfig) { - this.uiConfig = await uiConfig(); - } - return this.uiConfig.theme?.base || UiThemeEnum.Automatic; - } -} diff --git a/web/src/elements/Interface/Interface.ts b/web/src/elements/Interface/Interface.ts new file mode 100644 index 000000000..744a16095 --- /dev/null +++ b/web/src/elements/Interface/Interface.ts @@ -0,0 +1,67 @@ +import { config, tenant } from "@goauthentik/common/api/config"; +import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; +import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; +import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types"; +import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; + +import { ContextProvider } from "@lit-labs/context"; +import { state } from "lit/decorators.js"; + +import PFBase from "@patternfly/patternfly/patternfly-base.css"; + +import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api"; + +import { AKElement } from "../Base"; + +type AkInterface = HTMLElement & { + getTheme: () => Promise; + tenant?: CurrentTenant; + uiConfig?: UIConfig; + config?: Config; +}; + +export class Interface extends AKElement implements AkInterface { + @state() + tenant?: CurrentTenant; + + @state() + uiConfig?: UIConfig; + + _configContext = new ContextProvider(this, { + context: authentikConfigContext, + initialValue: undefined, + }); + + _config?: Config; + + @state() + set config(c: Config) { + this._config = c; + this._configContext.setValue(c); + this.requestUpdate(); + } + + get config(): Config | undefined { + return this._config; + } + + constructor() { + super(); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; + tenant().then((tenant) => (this.tenant = tenant)); + config().then((config) => (this.config = config)); + this.dataset.akInterfaceRoot = "true"; + } + + _activateTheme(root: AdoptedStyleSheetsElement, theme: UiThemeEnum): void { + super._activateTheme(root, theme); + super._activateTheme(document, theme); + } + + async getTheme(): Promise { + if (!this.uiConfig) { + this.uiConfig = await uiConfig(); + } + return this.uiConfig.theme?.base || UiThemeEnum.Automatic; + } +} diff --git a/web/src/elements/Interface/authentikConfigProvider.ts b/web/src/elements/Interface/authentikConfigProvider.ts new file mode 100644 index 000000000..2f2bbcf43 --- /dev/null +++ b/web/src/elements/Interface/authentikConfigProvider.ts @@ -0,0 +1,20 @@ +import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import type { Config } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = new (...args: any[]) => T; + +export function WithAuthentikConfig>( + superclass: T, + subscribe = true, +) { + class WithAkConfigProvider extends superclass { + @consume({ context: authentikConfigContext, subscribe }) + public authentikConfig!: Config; + } + return WithAkConfigProvider; +} diff --git a/web/src/elements/Interface/capabilitiesProvider.ts b/web/src/elements/Interface/capabilitiesProvider.ts new file mode 100644 index 000000000..402653880 --- /dev/null +++ b/web/src/elements/Interface/capabilitiesProvider.ts @@ -0,0 +1,69 @@ +import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import { CapabilitiesEnum } from "@goauthentik/api"; +import { Config } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = abstract new (...args: any[]) => T; + +// Using a unique, lexically scoped, and locally static symbol as the field name for the context +// means that it's inaccessible to any child class looking for it. It's one of the strongest privacy +// guarantees in JavaScript. + +class WCC { + public static readonly capabilitiesConfig: unique symbol = Symbol(); +} + +/** + * withCapabilitiesContext mixes in a single method to any LitElement, `can()`, which takes a + * CapabilitiesEnum and returns true or false. + * + * Usage: + * + * After importing, simply mixin this function: + * + * ``` + * export class AkMyNiftyNewFeature extends withCapabilitiesContext(AKElement) { + * ``` + * + * And then if you need to check on a capability: + * + * ``` + * if (this.can(CapabilitiesEnum.IsEnterprise) { ... } + * ``` + * + * This code re-exports CapabilitiesEnum, so you won't have to import it on a separate line if you + * don't need anything else from the API. + * + * Passing `true` as the second mixin argument will cause the inheriting class to subscribe to the + * configuration context. Should the context be explicitly reset, all active web components that are + * currently active and subscribed to the context will automatically have a `requestUpdate()` + * triggered with the new configuration. + * + */ + +export function WithCapabilitiesConfig>( + superclass: T, + subscribe = true, +) { + abstract class CapabilitiesContext extends superclass { + @consume({ context: authentikConfigContext, subscribe }) + private [WCC.capabilitiesConfig]!: Config; + + can(c: CapabilitiesEnum) { + if (!this[WCC.capabilitiesConfig]) { + throw new Error( + "ConfigContext: Attempted to access site configuration before initialization.", + ); + } + return this[WCC.capabilitiesConfig].capabilities.includes(c); + } + } + + return CapabilitiesContext; +} + +export { CapabilitiesEnum }; diff --git a/web/src/elements/Interface/index.ts b/web/src/elements/Interface/index.ts new file mode 100644 index 000000000..e7d946cf6 --- /dev/null +++ b/web/src/elements/Interface/index.ts @@ -0,0 +1,4 @@ +import { Interface } from "./Interface"; + +export { Interface }; +export default Interface; diff --git a/web/src/elements/types.ts b/web/src/elements/types.ts new file mode 100644 index 000000000..4273ab6f9 --- /dev/null +++ b/web/src/elements/types.ts @@ -0,0 +1,3 @@ +export interface AdoptedStyleSheetsElement { + adoptedStyleSheets: readonly CSSStyleSheet[]; +} diff --git a/web/src/elements/utils/ensureCSSStyleSheet.ts b/web/src/elements/utils/ensureCSSStyleSheet.ts new file mode 100644 index 000000000..26f2ff898 --- /dev/null +++ b/web/src/elements/utils/ensureCSSStyleSheet.ts @@ -0,0 +1,4 @@ +import { CSSResult } from "lit"; + +export const ensureCSSStyleSheet = (css: CSSStyleSheet | CSSResult): CSSStyleSheet => + css instanceof CSSResult ? css.styleSheet! : css; diff --git a/web/src/enterprise/rac/index.ts b/web/src/enterprise/rac/index.ts index 272ba2211..e5a9e04e7 100644 --- a/web/src/enterprise/rac/index.ts +++ b/web/src/enterprise/rac/index.ts @@ -1,5 +1,5 @@ import { TITLE_DEFAULT } from "@goauthentik/app/common/constants"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/LoadingOverlay"; import Guacamole from "guacamole-common-js"; diff --git a/web/src/flow/FlowExecutor.ts b/web/src/flow/FlowExecutor.ts index bc1dec3a8..e0d31e421 100644 --- a/web/src/flow/FlowExecutor.ts +++ b/web/src/flow/FlowExecutor.ts @@ -8,7 +8,7 @@ import { globalAK } from "@goauthentik/common/global"; import { configureSentry } from "@goauthentik/common/sentry"; import { first } from "@goauthentik/common/utils"; import { WebsocketClient } from "@goauthentik/common/ws"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/LoadingOverlay"; import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/flow/sources/apple/AppleLoginInit"; diff --git a/web/src/flow/stages/prompt/PromptStage.ts b/web/src/flow/stages/prompt/PromptStage.ts index 877d02119..09cc6959e 100644 --- a/web/src/flow/stages/prompt/PromptStage.ts +++ b/web/src/flow/stages/prompt/PromptStage.ts @@ -1,6 +1,9 @@ -import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/Divider"; import "@goauthentik/elements/EmptyState"; +import { + CapabilitiesEnum, + WithCapabilitiesConfig, +} from "@goauthentik/elements/Interface/capabilitiesProvider"; import { LOCALES } from "@goauthentik/elements/ak-locale-context/definitions"; import "@goauthentik/elements/forms/FormElement"; import { BaseStage } from "@goauthentik/flow/stages/base"; @@ -20,7 +23,6 @@ import PFTitle from "@patternfly/patternfly/components/Title/title.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { - CapabilitiesEnum, PromptChallenge, PromptChallengeResponseRequest, PromptTypeEnum, @@ -28,7 +30,9 @@ import { } from "@goauthentik/api"; @customElement("ak-stage-prompt") -export class PromptStage extends BaseStage { +export class PromptStage extends WithCapabilitiesConfig( + BaseStage, +) { static get styles(): CSSResult[] { return [ PFBase, @@ -193,10 +197,7 @@ ${prompt.initialValue} `; })}`; case PromptTypeEnum.AkLocale: { - const inDebug = rootInterface()?.config?.capabilities.includes( - CapabilitiesEnum.CanDebug, - ); - const locales = inDebug + const locales = this.can(CapabilitiesEnum.CanDebug) ? LOCALES : LOCALES.filter((locale) => locale.code !== "debug"); const options = locales.map( diff --git a/web/src/standalone/api-browser/index.ts b/web/src/standalone/api-browser/index.ts index b0c5849ed..c6a98159c 100644 --- a/web/src/standalone/api-browser/index.ts +++ b/web/src/standalone/api-browser/index.ts @@ -2,7 +2,7 @@ import { CSRFHeaderName } from "@goauthentik/common/api/middleware"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; import { globalAK } from "@goauthentik/common/global"; import { first, getCookie } from "@goauthentik/common/utils"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/ak-locale-context"; import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand"; import "rapidoc"; diff --git a/web/src/standalone/loading/index.ts b/web/src/standalone/loading/index.ts index 907a05140..24e8c47ef 100644 --- a/web/src/standalone/loading/index.ts +++ b/web/src/standalone/loading/index.ts @@ -1,5 +1,5 @@ import { globalAK } from "@goauthentik/common/global"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, css, html } from "lit"; diff --git a/web/src/stories/interface.ts b/web/src/stories/interface.ts index c4e2dc03d..1eafc6204 100644 --- a/web/src/stories/interface.ts +++ b/web/src/stories/interface.ts @@ -1,4 +1,4 @@ -import { Interface } from "@goauthentik/app/elements/Base"; +import { Interface } from "@goauthentik/app/elements/Interface"; import { customElement, property } from "lit/decorators.js"; diff --git a/web/src/user/UserInterface.ts b/web/src/user/UserInterface.ts index 09b10d632..aad94e73d 100644 --- a/web/src/user/UserInterface.ts +++ b/web/src/user/UserInterface.ts @@ -9,7 +9,7 @@ import { UserDisplay } from "@goauthentik/common/ui/config"; import { me } from "@goauthentik/common/users"; import { first } from "@goauthentik/common/utils"; import { WebsocketClient } from "@goauthentik/common/ws"; -import { Interface } from "@goauthentik/elements/Base"; +import { Interface } from "@goauthentik/elements/Interface"; import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/enterprise/EnterpriseStatusBanner"; From a2dce3fb635266c0d2e85673664a41308b542940 Mon Sep 17 00:00:00 2001 From: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:03:00 -0800 Subject: [PATCH 27/37] web: Replace calls to `rootInterface()?.tenant?` with a contextual `this.tenant` object (#7778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This commit abstracts access to the object `rootInterface()?.config?` into a single accessor, `authentikConfig`, that can be mixed into any AKElement object that requires access to it. Since access to `rootInterface()?.config?` is _universally_ used for a single (and repetitive) boolean check, a separate accessor has been provided that converts all calls of the form: ``` javascript rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate) ``` into: ``` javascript this.can(CapabilitiesEnum.CanImpersonate) ``` It does this via a Mixin, `WithCapabilitiesConfig`, which understands that these calls only make sense in the context of a running, fully configured authentik instance, and that their purpose is to inform authentik components of a user’s capabilities. The latter is why I don’t feel uncomfortable turning a function call into a method; we should make it explicit that this is a relationship between components. The mixin has a single single field, `[WCC.capabilitiesConfig]`, where its association with the upper-level configuration is made. If that syntax looks peculiar to you, good! I’ve used an explict unique symbol as the field name; it is inaccessable an innumerable in the object list. The debugger shows it only as: Symbol(): { cacheTimeout: 300 cacheTimeoutFlows: 300 cacheTimeoutPolicies: 300 cacheTimeoutReputation: 300 capabilities: (5) ['can_save_media', 'can_geo_ip', 'can_impersonate', 'can_debug', 'is_enterprise'] } Since you can’t reference it by identity, you can’t write to it. Until every browser supports actual private fields, this is the best we can do; it does guarantee that field name collisions are impossible, which is a win. The mixin takes a second optional boolean; setting this to true will cause any web component using the mixin to automatically schedule a re-render if the capabilities list changes. The mixin is also generic; despite the "...into a Lit-Context" in the title, the internals of the Mixin can be replaced with anything so long as the signature of `.can()` is preserved. Because this work builds off the work I did to give the Sidebar access to the configuration without ad-hoc retrieval or prop-drilling, it wasn’t necessary to create a new context for it. That will be necessary for the following: TODO: ``` javascript rootInterface()?.uiConfig; rootInterface()?.tenant; me(); ``` * This commit abstracts access to the object `rootInterface()?.tenant?` into a single accessor, `tenant`, that can be mixed into any AKElement object that requires access to it. Like `WithCapabilitiesConfig` and `WithAuthentikConfig`, this one is named `WithTenantConfig`. TODO: ``` javascript rootInterface()?.uiConfig; me(); ``` * web: Added a README with a description of the applications' "mental model," essentially an architectural description. * web: prettier did a thing * web: prettier had opinions about the README * web: Jens requested that subscription be by default, and it's the right call. * web: Jens requested that the default subscription state for contexts be , and it's the right call. * web: prettier having opinions after merging with dependent branch * web: prettier still having opinions. --- ...plication-wizard-authentication-by-ldap.ts | 6 ++--- ...ication-wizard-authentication-by-radius.ts | 6 ++--- web/src/admin/groups/RelatedUserList.ts | 6 ++--- .../admin/providers/ldap/LDAPProviderForm.ts | 6 ++--- .../providers/radius/RadiusProviderForm.ts | 6 ++--- web/src/admin/users/UserListPage.ts | 5 ++-- web/src/elements/AuthentikContexts.ts | 6 ++++- web/src/elements/Interface/Interface.ts | 26 ++++++++++++++++--- .../Interface/authentikConfigProvider.ts | 2 +- web/src/elements/Interface/tenantProvider.ts | 20 ++++++++++++++ web/src/elements/PageHeader.ts | 8 +++--- web/src/elements/sidebar/SidebarBrand.ts | 11 +++----- .../details/UserSettingsFlowExecutor.ts | 15 +++++------ 13 files changed, 81 insertions(+), 42 deletions(-) create mode 100644 web/src/elements/Interface/tenantProvider.ts diff --git a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts index a99384171..6e1554196 100644 --- a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts +++ b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts @@ -7,7 +7,7 @@ import "@goauthentik/components/ak-number-input"; import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -32,7 +32,7 @@ import { } from "./LDAPOptionsAndHelp"; @customElement("ak-application-wizard-authentication-by-ldap") -export class ApplicationWizardApplicationDetails extends BaseProviderPanel { +export class ApplicationWizardApplicationDetails extends WithTenantConfig(BaseProviderPanel) { render() { const provider = this.wizard.provider as LDAPProvider | undefined; const errors = this.wizard.errors.provider; @@ -57,7 +57,7 @@ export class ApplicationWizardApplicationDetails extends BaseProviderPanel {

diff --git a/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts b/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts index cadbd94ad..44f452037 100644 --- a/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts +++ b/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts @@ -3,7 +3,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search"; import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-text-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -17,7 +17,7 @@ import { FlowsInstancesListDesignationEnum, RadiusProvider } from "@goauthentik/ import BaseProviderPanel from "../BaseProviderPanel"; @customElement("ak-application-wizard-authentication-by-radius") -export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel { +export class ApplicationWizardAuthenticationByRadius extends WithTenantConfig(BaseProviderPanel) { render() { const provider = this.wizard.provider as RadiusProvider | undefined; const errors = this.wizard.errors.provider; @@ -42,7 +42,7 @@ export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel {

diff --git a/web/src/admin/groups/RelatedUserList.ts b/web/src/admin/groups/RelatedUserList.ts index 27450fb82..5e2c6b952 100644 --- a/web/src/admin/groups/RelatedUserList.ts +++ b/web/src/admin/groups/RelatedUserList.ts @@ -9,11 +9,11 @@ import { MessageLevel } from "@goauthentik/common/messages"; import { uiConfig } from "@goauthentik/common/ui/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-status-label"; -import { rootInterface } from "@goauthentik/elements/Base"; import { CapabilitiesEnum, WithCapabilitiesConfig, } from "@goauthentik/elements/Interface/capabilitiesProvider"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/Dropdown"; import "@goauthentik/elements/forms/DeleteBulkForm"; @@ -110,7 +110,7 @@ export class RelatedUserAdd extends Form<{ users: number[] }> { } @customElement("ak-user-related-list") -export class RelatedUserList extends WithCapabilitiesConfig(Table) { +export class RelatedUserList extends WithTenantConfig(WithCapabilitiesConfig(Table)) { expandable = true; checkbox = true; @@ -295,7 +295,7 @@ export class RelatedUserList extends WithCapabilitiesConfig(Table) { ${msg("Set password")} - ${rootInterface()?.tenant?.flowRecovery + ${this.tenant?.flowRecovery ? html` { +export class LDAPProviderFormPage extends WithTenantConfig(BaseProviderForm) { async loadInstance(pk: number): Promise { return new ProvidersApi(DEFAULT_CONFIG).providersLdapRetrieve({ id: pk, @@ -68,7 +68,7 @@ export class LDAPProviderFormPage extends BaseProviderForm {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/providers/radius/RadiusProviderForm.ts b/web/src/admin/providers/radius/RadiusProviderForm.ts index 269a5ee95..f37c865d5 100644 --- a/web/src/admin/providers/radius/RadiusProviderForm.ts +++ b/web/src/admin/providers/radius/RadiusProviderForm.ts @@ -1,7 +1,7 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -14,7 +14,7 @@ import { customElement } from "lit/decorators.js"; import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api"; @customElement("ak-provider-radius-form") -export class RadiusProviderFormPage extends BaseProviderForm { +export class RadiusProviderFormPage extends WithTenantConfig(BaseProviderForm) { loadInstance(pk: number): Promise { return new ProvidersApi(DEFAULT_CONFIG).providersRadiusRetrieve({ id: pk, @@ -57,7 +57,7 @@ export class RadiusProviderFormPage extends BaseProviderForm {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/users/UserListPage.ts b/web/src/admin/users/UserListPage.ts index e9d0c6f09..afb88f3f6 100644 --- a/web/src/admin/users/UserListPage.ts +++ b/web/src/admin/users/UserListPage.ts @@ -16,6 +16,7 @@ import { CapabilitiesEnum, WithCapabilitiesConfig, } from "@goauthentik/elements/Interface/capabilitiesProvider"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { PFSize } from "@goauthentik/elements/Spinner"; import "@goauthentik/elements/TreeView"; import "@goauthentik/elements/buttons/ActionButton"; @@ -90,7 +91,7 @@ const recoveryButtonStyles = css` `; @customElement("ak-user-list") -export class UserListPage extends WithCapabilitiesConfig(TablePage) { +export class UserListPage extends WithTenantConfig(WithCapabilitiesConfig(TablePage)) { expandable = true; checkbox = true; @@ -351,7 +352,7 @@ export class UserListPage extends WithCapabilitiesConfig(TablePage) { ${msg("Set password")}
- ${rootInterface()?.tenant?.flowRecovery + ${this.tenant.flowRecovery ? html` (Symbol("authentik-config-context")); +export const authentikTenantContext = createContext( + Symbol("authentik-tenant-context"), +); + export default authentikConfigContext; diff --git a/web/src/elements/Interface/Interface.ts b/web/src/elements/Interface/Interface.ts index 744a16095..b2470cfd2 100644 --- a/web/src/elements/Interface/Interface.ts +++ b/web/src/elements/Interface/Interface.ts @@ -1,6 +1,9 @@ import { config, tenant } from "@goauthentik/common/api/config"; import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; +import { + authentikConfigContext, + authentikTenantContext, +} from "@goauthentik/elements/AuthentikContexts"; import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types"; import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; @@ -21,9 +24,6 @@ type AkInterface = HTMLElement & { }; export class Interface extends AKElement implements AkInterface { - @state() - tenant?: CurrentTenant; - @state() uiConfig?: UIConfig; @@ -45,6 +45,24 @@ export class Interface extends AKElement implements AkInterface { return this._config; } + _tenantContext = new ContextProvider(this, { + context: authentikTenantContext, + initialValue: undefined, + }); + + _tenant?: CurrentTenant; + + @state() + set tenant(c: CurrentTenant) { + this._tenant = c; + this._tenantContext.setValue(c); + this.requestUpdate(); + } + + get tenant(): CurrentTenant | undefined { + return this._tenant; + } + constructor() { super(); document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; diff --git a/web/src/elements/Interface/authentikConfigProvider.ts b/web/src/elements/Interface/authentikConfigProvider.ts index 2f2bbcf43..5b2027fd0 100644 --- a/web/src/elements/Interface/authentikConfigProvider.ts +++ b/web/src/elements/Interface/authentikConfigProvider.ts @@ -12,7 +12,7 @@ export function WithAuthentikConfig>( superclass: T, subscribe = true, ) { - class WithAkConfigProvider extends superclass { + abstract class WithAkConfigProvider extends superclass { @consume({ context: authentikConfigContext, subscribe }) public authentikConfig!: Config; } diff --git a/web/src/elements/Interface/tenantProvider.ts b/web/src/elements/Interface/tenantProvider.ts new file mode 100644 index 000000000..63d389048 --- /dev/null +++ b/web/src/elements/Interface/tenantProvider.ts @@ -0,0 +1,20 @@ +import { authentikTenantContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import type { CurrentTenant } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = abstract new (...args: any[]) => T; + +export function WithTenantConfig>( + superclass: T, + subscribe = true, +) { + abstract class WithTenantProvider extends superclass { + @consume({ context: authentikTenantContext, subscribe }) + public tenant!: CurrentTenant; + } + return WithTenantProvider; +} diff --git a/web/src/elements/PageHeader.ts b/web/src/elements/PageHeader.ts index fcdbbeffc..7be55996d 100644 --- a/web/src/elements/PageHeader.ts +++ b/web/src/elements/PageHeader.ts @@ -8,7 +8,8 @@ import { } from "@goauthentik/common/constants"; import { currentInterface } from "@goauthentik/common/sentry"; import { me } from "@goauthentik/common/users"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; @@ -23,7 +24,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { EventsApi } from "@goauthentik/api"; @customElement("ak-page-header") -export class PageHeader extends AKElement { +export class PageHeader extends WithTenantConfig(AKElement) { @property() icon?: string; @@ -35,9 +36,8 @@ export class PageHeader extends AKElement { @property() set header(value: string) { - const tenant = rootInterface()?.tenant; const currentIf = currentInterface(); - let title = tenant?.brandingTitle || TITLE_DEFAULT; + let title = this.tenant?.brandingTitle || TITLE_DEFAULT; if (currentIf === "admin") { title = `${msg("Admin")} - ${title}`; } diff --git a/web/src/elements/sidebar/SidebarBrand.ts b/web/src/elements/sidebar/SidebarBrand.ts index fa442b36c..b57d336f7 100644 --- a/web/src/elements/sidebar/SidebarBrand.ts +++ b/web/src/elements/sidebar/SidebarBrand.ts @@ -1,6 +1,6 @@ import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants"; -import { first } from "@goauthentik/common/utils"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { CSSResult, TemplateResult, css, html } from "lit"; import { customElement } from "lit/decorators.js"; @@ -27,7 +27,7 @@ export const DefaultTenant: CurrentTenant = { }; @customElement("ak-sidebar-brand") -export class SidebarBrand extends AKElement { +export class SidebarBrand extends WithTenantConfig(AKElement) { static get styles(): CSSResult[] { return [ PFBase, @@ -85,10 +85,7 @@ export class SidebarBrand extends AKElement {
authentik Logo diff --git a/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts b/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts index e7aa36343..f4252f58b 100644 --- a/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts +++ b/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts @@ -2,14 +2,15 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EVENT_REFRESH } from "@goauthentik/common/constants"; import { MessageLevel } from "@goauthentik/common/messages"; import { refreshMe } from "@goauthentik/common/users"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; import { StageHost } from "@goauthentik/flow/stages/base"; import "@goauthentik/user/user-settings/details/stages/prompt/PromptStage"; import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, html } from "lit"; -import { customElement, property, state } from "lit/decorators.js"; +import { customElement, property } from "lit/decorators.js"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; @@ -21,7 +22,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { ChallengeChoices, ChallengeTypes, - CurrentTenant, FlowChallengeResponseRequest, FlowErrorChallenge, FlowsApi, @@ -31,13 +31,13 @@ import { } from "@goauthentik/api"; @customElement("ak-user-settings-flow-executor") -export class UserSettingsFlowExecutor extends AKElement implements StageHost { +export class UserSettingsFlowExecutor + extends WithTenantConfig(AKElement, true) + implements StageHost +{ @property() flowSlug?: string; - @state() - tenant?: CurrentTenant; - private _challenge?: ChallengeTypes; @property({ attribute: false }) @@ -87,7 +87,6 @@ export class UserSettingsFlowExecutor extends AKElement implements StageHost { } firstUpdated(): void { - this.tenant = rootInterface()?.tenant; this.flowSlug = this.tenant?.flowUserSettings; if (!this.flowSlug) { return; From ab411a6a9b26fd6c078172cdc0120e9a4a3997d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:05:19 +0100 Subject: [PATCH 28/37] web: bump lit-analyzer from 2.0.2 to 2.0.3 in /web (#8097) Bumps [lit-analyzer](https://github.com/runem/lit-analyzer) from 2.0.2 to 2.0.3. - [Release notes](https://github.com/runem/lit-analyzer/releases) - [Changelog](https://github.com/runem/lit-analyzer/blob/master/CHANGELOG.md) - [Commits](https://github.com/runem/lit-analyzer/commits) --- updated-dependencies: - dependency-name: lit-analyzer dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 64006c368..2ff7d6313 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -85,7 +85,7 @@ "eslint-plugin-lit": "^1.11.0", "eslint-plugin-sonarjs": "^0.23.0", "eslint-plugin-storybook": "^0.6.15", - "lit-analyzer": "^2.0.2", + "lit-analyzer": "^2.0.3", "npm-run-all": "^4.1.5", "prettier": "^3.1.1", "pseudolocale": "^2.0.0", @@ -13327,9 +13327,9 @@ } }, "node_modules/lit-analyzer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lit-analyzer/-/lit-analyzer-2.0.2.tgz", - "integrity": "sha512-Is3cx8ypCVq5uNl8EKkPdlLuV3HDVntDVUeLNQlzTM2Je3uG5wHcn+06NB+yhCoa4rhwwXCjprU/7g21CSFqOA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lit-analyzer/-/lit-analyzer-2.0.3.tgz", + "integrity": "sha512-XiAjnwVipNrKav7r3CSEZpWt+mwYxrhPRVC7h8knDmn/HWTzzWJvPe+mwBcL2brn4xhItAMzZhFC8tzzqHKmiQ==", "dev": true, "dependencies": { "@vscode/web-custom-data": "^0.4.2", diff --git a/web/package.json b/web/package.json index 5f50add27..aaeec9caa 100644 --- a/web/package.json +++ b/web/package.json @@ -110,7 +110,7 @@ "eslint-plugin-lit": "^1.11.0", "eslint-plugin-sonarjs": "^0.23.0", "eslint-plugin-storybook": "^0.6.15", - "lit-analyzer": "^2.0.2", + "lit-analyzer": "^2.0.3", "npm-run-all": "^4.1.5", "prettier": "^3.1.1", "pseudolocale": "^2.0.0", From 9a0feb1c35ee00696f565d1976e7fa0fbeea4e84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:05:27 +0100 Subject: [PATCH 29/37] web: bump the eslint group in /web with 2 updates (#8095) Bumps the eslint group in /web with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 6.18.0 to 6.18.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.1/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.18.0 to 6.18.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.1/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 88 +++++++++++++++++++++---------------------- web/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 2ff7d6313..43bc5a599 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -74,8 +74,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.18.0", - "@typescript-eslint/parser": "^6.18.0", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", @@ -7576,16 +7576,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", - "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", + "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/type-utils": "6.18.0", - "@typescript-eslint/utils": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/type-utils": "6.18.1", + "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -7644,15 +7644,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", - "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4" }, "engines": { @@ -7672,13 +7672,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", - "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0" + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7689,13 +7689,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", - "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", + "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/utils": "6.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -7716,9 +7716,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", - "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", + "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7729,13 +7729,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", - "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", + "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7814,17 +7814,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", - "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", + "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "semver": "^7.5.4" }, "engines": { @@ -7872,12 +7872,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", - "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/types": "6.18.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/web/package.json b/web/package.json index aaeec9caa..b75608d81 100644 --- a/web/package.json +++ b/web/package.json @@ -99,8 +99,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.18.0", - "@typescript-eslint/parser": "^6.18.0", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", From 2497101c32511a0c9d14a56f9b47c0d8537a2a66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:05:41 +0100 Subject: [PATCH 30/37] web: bump ts-lit-plugin from 2.0.1 to 2.0.2 in /web (#8096) Bumps [ts-lit-plugin](https://github.com/runem/lit-analyzer) from 2.0.1 to 2.0.2. - [Release notes](https://github.com/runem/lit-analyzer/releases) - [Changelog](https://github.com/runem/lit-analyzer/blob/master/CHANGELOG.md) - [Commits](https://github.com/runem/lit-analyzer/commits) --- updated-dependencies: - dependency-name: ts-lit-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 43bc5a599..d8c06f88a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -99,7 +99,7 @@ "rollup-plugin-postcss-lit": "^2.1.0", "storybook": "^7.6.7", "storybook-addon-mock": "^4.3.0", - "ts-lit-plugin": "^2.0.1", + "ts-lit-plugin": "^2.0.2", "tslib": "^2.6.2", "turnstile-types": "^1.2.0", "typescript": "^5.3.3", @@ -17838,9 +17838,9 @@ } }, "node_modules/ts-lit-plugin": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-lit-plugin/-/ts-lit-plugin-2.0.1.tgz", - "integrity": "sha512-Y5G03aDiMYHMLzoZ50kdeVkzgVig2mBw6PVY2oI9PcWl3ONTcDyYq6rJ0QzhlACYWP8sT0dmaPMsHMObgNNvvg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ts-lit-plugin/-/ts-lit-plugin-2.0.2.tgz", + "integrity": "sha512-DPXlVxhjWHxg8AyBLcfSYt2JXgpANV1ssxxwjY98o26gD8MzeiM68HFW9c2VeDd1CjoR3w7B/6/uKxwBQe+ioA==", "dev": true, "dependencies": { "lit-analyzer": "^2.0.1", diff --git a/web/package.json b/web/package.json index b75608d81..500589038 100644 --- a/web/package.json +++ b/web/package.json @@ -124,7 +124,7 @@ "rollup-plugin-postcss-lit": "^2.1.0", "storybook": "^7.6.7", "storybook-addon-mock": "^4.3.0", - "ts-lit-plugin": "^2.0.1", + "ts-lit-plugin": "^2.0.2", "tslib": "^2.6.2", "turnstile-types": "^1.2.0", "typescript": "^5.3.3", From 0fb7d1237fd3296293aa42f6a73f4660cfb50d44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:05:51 +0100 Subject: [PATCH 31/37] web: bump the babel group in /web with 1 update (#8094) Bumps the babel group in /web with 1 update: [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env). Updates `@babel/preset-env` from 7.23.7 to 7.23.8 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.8/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/preset-env" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: babel ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 19 +++++++++---------- web/package.json | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index d8c06f88a..2da2b2170 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -50,7 +50,7 @@ "@babel/plugin-transform-private-methods": "^7.23.3", "@babel/plugin-transform-private-property-in-object": "^7.23.4", "@babel/plugin-transform-runtime": "^7.23.7", - "@babel/preset-env": "^7.23.7", + "@babel/preset-env": "^7.23.8", "@babel/preset-typescript": "^7.23.3", "@hcaptcha/types": "^1.0.3", "@jackfranklin/rollup-plugin-markdown": "^0.4.0", @@ -1119,16 +1119,15 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", - "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-split-export-declaration": "^7.22.6", @@ -1833,9 +1832,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.7.tgz", - "integrity": "sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==", + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", + "integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", "dev": true, "dependencies": { "@babel/compat-data": "^7.23.5", @@ -1871,7 +1870,7 @@ "@babel/plugin-transform-block-scoping": "^7.23.4", "@babel/plugin-transform-class-properties": "^7.23.3", "@babel/plugin-transform-class-static-block": "^7.23.4", - "@babel/plugin-transform-classes": "^7.23.5", + "@babel/plugin-transform-classes": "^7.23.8", "@babel/plugin-transform-computed-properties": "^7.23.3", "@babel/plugin-transform-destructuring": "^7.23.3", "@babel/plugin-transform-dotall-regex": "^7.23.3", diff --git a/web/package.json b/web/package.json index 500589038..07a86fdae 100644 --- a/web/package.json +++ b/web/package.json @@ -75,7 +75,7 @@ "@babel/plugin-transform-private-methods": "^7.23.3", "@babel/plugin-transform-private-property-in-object": "^7.23.4", "@babel/plugin-transform-runtime": "^7.23.7", - "@babel/preset-env": "^7.23.7", + "@babel/preset-env": "^7.23.8", "@babel/preset-typescript": "^7.23.3", "@hcaptcha/types": "^1.0.3", "@jackfranklin/rollup-plugin-markdown": "^0.4.0", From f030128686344da446bc40c33a6814c8294b343f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:06:00 +0100 Subject: [PATCH 32/37] web: bump the eslint group in /tests/wdio with 2 updates (#8093) Bumps the eslint group in /tests/wdio with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 6.18.0 to 6.18.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.1/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.18.0 to 6.18.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.18.1/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 88 ++++++++++++++++++------------------ tests/wdio/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 25720ba07..6ab7d4717 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -7,8 +7,8 @@ "name": "@goauthentik/web-tests", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.18.0", - "@typescript-eslint/parser": "^6.18.0", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", @@ -946,16 +946,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", - "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", + "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/type-utils": "6.18.0", - "@typescript-eslint/utils": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/type-utils": "6.18.1", + "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -981,15 +981,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", - "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4" }, "engines": { @@ -1009,13 +1009,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", - "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0" + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1026,13 +1026,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", - "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", + "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/utils": "6.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1053,9 +1053,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", - "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", + "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1066,13 +1066,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", - "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", + "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1118,17 +1118,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", - "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", + "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "semver": "^7.5.4" }, "engines": { @@ -1143,12 +1143,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", - "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/types": "6.18.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 477652a15..a55a8012f 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -4,8 +4,8 @@ "type": "module", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.18.0", - "@typescript-eslint/parser": "^6.18.0", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", From 1ef654f19b09354c47cb50696735c5af38f8ef78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:06:14 +0100 Subject: [PATCH 33/37] core: bump golang.org/x/oauth2 from 0.15.0 to 0.16.0 (#8092) Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.15.0 to 0.16.0. - [Commits](https://github.com/golang/oauth2/compare/v0.15.0...v0.16.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index aadc18f18..5b08a4a39 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/wwt/guac v1.3.2 goauthentik.io/api/v3 v3.2023105.5 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab - golang.org/x/oauth2 v0.15.0 + golang.org/x/oauth2 v0.16.0 golang.org/x/sync v0.6.0 gopkg.in/yaml.v2 v2.4.0 layeh.com/radius v0.0.0-20210819152912-ad72663a72ab @@ -74,9 +74,9 @@ require ( go.opentelemetry.io/otel v1.17.0 // indirect go.opentelemetry.io/otel/metric v1.17.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index fcbdc7618..c6ecdaf37 100644 --- a/go.sum +++ b/go.sum @@ -327,8 +327,8 @@ golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -394,16 +394,16 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -452,8 +452,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= From 74b4fe5ceeb2379caeb54b33014effd080cc2265 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 12:27:21 +0100 Subject: [PATCH 34/37] website: bump follow-redirects from 1.15.3 to 1.15.4 in /website (#8099) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index e03cb069b..488dda4d8 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -7898,9 +7898,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "funding": [ { "type": "individual", From 9ea41595b7afceeb25b8dd35c45791a4bc4baffb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 12:27:31 +0100 Subject: [PATCH 35/37] web: bump follow-redirects from 1.15.2 to 1.15.4 in /web (#8098) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 2da2b2170..6cab57f36 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -11455,9 +11455,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "funding": [ { "type": "individual", From db95b967fe5172bb24e705377829e590d1d83e3f Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:26:23 +0100 Subject: [PATCH 36/37] translate: Updates for file web/xliff/en.xlf in zh_CN (#8100) Translate web/xliff/en.xlf in zh_CN 100% translated source file: 'web/xliff/en.xlf' on 'zh_CN'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh_CN.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web/xliff/zh_CN.xlf b/web/xliff/zh_CN.xlf index 3bbeaddb9..9f27a492e 100644 --- a/web/xliff/zh_CN.xlf +++ b/web/xliff/zh_CN.xlf @@ -8211,6 +8211,14 @@ Bindings to groups/users are checked against the user of the event. Learn more 了解更多 + + + Maximum concurrent connections + 最大并发连接数 + + + Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. + 允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。 From 6e83b890bd39348bd91f4c64f9840329ff964e4a Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:26:41 +0100 Subject: [PATCH 37/37] translate: Updates for file web/xliff/en.xlf in zh-Hans (#8101) Translate web/xliff/en.xlf in zh-Hans 100% translated source file: 'web/xliff/en.xlf' on 'zh-Hans'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh-Hans.xlf | 50 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 387f668c8..95820ad6b 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8214,10 +8214,12 @@ Bindings to groups/users are checked against the user of the event. Maximum concurrent connections + 最大并发连接数 Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit. + 允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。 - + \ No newline at end of file