From 6192d01b7e5e5b3de36e89e0dacddafe084d4019 Mon Sep 17 00:00:00 2001 From: sdimovv <36302090+sdimovv@users.noreply.github.com> Date: Sun, 2 Apr 2023 15:52:44 +0100 Subject: [PATCH] stages: Add ability to set user friendly names for MFA stages (#5005) * Added ability to name MFA stage * Schema * Changed Charfield to Textfield * Regenerated schema * Add explicit required * set null instead of blank so title check works Signed-off-by: Jens Langhammer * add help text and adjust wording Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer Co-authored-by: Jens Langhammer --- authentik/core/types.py | 2 +- authentik/flows/models.py | 9 +++ authentik/stages/authenticator_duo/api.py | 1 + ...005_authenticatorduostage_friendly_name.py | 20 ++++++ authentik/stages/authenticator_duo/models.py | 6 +- authentik/stages/authenticator_sms/api.py | 1 + ...006_authenticatorsmsstage_friendly_name.py | 17 +++++ authentik/stages/authenticator_sms/models.py | 6 +- authentik/stages/authenticator_static/api.py | 2 +- ..._authenticatorstaticstage_friendly_name.py | 17 +++++ .../stages/authenticator_static/models.py | 6 +- authentik/stages/authenticator_totp/api.py | 2 +- ...07_authenticatortotpstage_friendly_name.py | 17 +++++ authentik/stages/authenticator_totp/models.py | 6 +- .../stages/authenticator_webauthn/api.py | 1 + ...authenticatewebauthnstage_friendly_name.py | 17 +++++ .../stages/authenticator_webauthn/models.py | 6 +- schema.yml | 71 +++++++++++++++++++ .../AuthenticatorDuoStageForm.ts | 17 ++++- .../AuthenticatorSMSStageForm.ts | 29 +++++--- .../AuthenticatorStaticStageForm.ts | 17 ++++- .../AuthenticatorTOTPStageForm.ts | 18 ++++- .../AuthenticateWebAuthnStageForm.ts | 18 ++++- .../user/user-settings/mfa/MFADevicesPage.ts | 16 +---- 24 files changed, 275 insertions(+), 47 deletions(-) create mode 100644 authentik/stages/authenticator_duo/migrations/0005_authenticatorduostage_friendly_name.py create mode 100644 authentik/stages/authenticator_sms/migrations/0006_authenticatorsmsstage_friendly_name.py create mode 100644 authentik/stages/authenticator_static/migrations/0006_authenticatorstaticstage_friendly_name.py create mode 100644 authentik/stages/authenticator_totp/migrations/0007_authenticatortotpstage_friendly_name.py create mode 100644 authentik/stages/authenticator_webauthn/migrations/0009_authenticatewebauthnstage_friendly_name.py diff --git a/authentik/core/types.py b/authentik/core/types.py index 2bcab71ac..5677242fc 100644 --- a/authentik/core/types.py +++ b/authentik/core/types.py @@ -27,6 +27,6 @@ class UserSettingSerializer(PassiveSerializer): object_uid = CharField() component = CharField() - title = CharField() + title = CharField(required=True) configure_url = CharField(required=False) icon_url = CharField(required=False) diff --git a/authentik/flows/models.py b/authentik/flows/models.py index 7646faeb9..f638ef04d 100644 --- a/authentik/flows/models.py +++ b/authentik/flows/models.py @@ -271,6 +271,15 @@ class ConfigurableStage(models.Model): abstract = True +class FriendlyNamedStage(models.Model): + """Abstract base class for a Stage that can have a user friendly name configured.""" + + friendly_name = models.TextField(null=True) + + class Meta: + abstract = True + + class FlowToken(Token): """Subclass of a standard Token, stores the currently active flow plan upon creation. Can be used to later resume a flow.""" diff --git a/authentik/stages/authenticator_duo/api.py b/authentik/stages/authenticator_duo/api.py index abebf26fa..3d038de31 100644 --- a/authentik/stages/authenticator_duo/api.py +++ b/authentik/stages/authenticator_duo/api.py @@ -33,6 +33,7 @@ class AuthenticatorDuoStageSerializer(StageSerializer): model = AuthenticatorDuoStage fields = StageSerializer.Meta.fields + [ "configure_flow", + "friendly_name", "client_id", "client_secret", "api_hostname", diff --git a/authentik/stages/authenticator_duo/migrations/0005_authenticatorduostage_friendly_name.py b/authentik/stages/authenticator_duo/migrations/0005_authenticatorduostage_friendly_name.py new file mode 100644 index 000000000..3367dd4fa --- /dev/null +++ b/authentik/stages/authenticator_duo/migrations/0005_authenticatorduostage_friendly_name.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.7 on 2023-04-02 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ( + "authentik_stages_authenticator_duo", + "0004_authenticatorduostage_admin_integration_key_and_more", + ), + ] + + operations = [ + migrations.AddField( + model_name="authenticatorduostage", + name="friendly_name", + field=models.TextField(null=True), + ), + ] diff --git a/authentik/stages/authenticator_duo/models.py b/authentik/stages/authenticator_duo/models.py index 1cb76970e..542dfc31c 100644 --- a/authentik/stages/authenticator_duo/models.py +++ b/authentik/stages/authenticator_duo/models.py @@ -12,12 +12,12 @@ from rest_framework.serializers import BaseSerializer, Serializer from authentik import __version__ from authentik.core.types import UserSettingSerializer -from authentik.flows.models import ConfigurableStage, Stage +from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage from authentik.lib.models import SerializerModel from authentik.lib.utils.http import authentik_user_agent -class AuthenticatorDuoStage(ConfigurableStage, Stage): +class AuthenticatorDuoStage(ConfigurableStage, FriendlyNamedStage, Stage): """Setup Duo authenticator devices""" api_hostname = models.TextField() @@ -68,7 +68,7 @@ class AuthenticatorDuoStage(ConfigurableStage, Stage): def ui_user_settings(self) -> Optional[UserSettingSerializer]: return UserSettingSerializer( data={ - "title": str(self._meta.verbose_name), + "title": self.friendly_name or str(self._meta.verbose_name), "component": "ak-user-settings-authenticator-duo", } ) diff --git a/authentik/stages/authenticator_sms/api.py b/authentik/stages/authenticator_sms/api.py index 59f602cad..bfa0b323e 100644 --- a/authentik/stages/authenticator_sms/api.py +++ b/authentik/stages/authenticator_sms/api.py @@ -19,6 +19,7 @@ class AuthenticatorSMSStageSerializer(StageSerializer): model = AuthenticatorSMSStage fields = StageSerializer.Meta.fields + [ "configure_flow", + "friendly_name", "provider", "from_number", "account_sid", diff --git a/authentik/stages/authenticator_sms/migrations/0006_authenticatorsmsstage_friendly_name.py b/authentik/stages/authenticator_sms/migrations/0006_authenticatorsmsstage_friendly_name.py new file mode 100644 index 000000000..de2d36b96 --- /dev/null +++ b/authentik/stages/authenticator_sms/migrations/0006_authenticatorsmsstage_friendly_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.7 on 2023-04-02 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_stages_authenticator_sms", "0005_authenticatorsmsstage_mapping"), + ] + + operations = [ + migrations.AddField( + model_name="authenticatorsmsstage", + name="friendly_name", + field=models.TextField(null=True), + ), + ] diff --git a/authentik/stages/authenticator_sms/models.py b/authentik/stages/authenticator_sms/models.py index 159847650..9f2e117b4 100644 --- a/authentik/stages/authenticator_sms/models.py +++ b/authentik/stages/authenticator_sms/models.py @@ -17,7 +17,7 @@ from twilio.rest import Client from authentik.core.types import UserSettingSerializer from authentik.events.models import Event, EventAction, NotificationWebhookMapping from authentik.events.utils import sanitize_item -from authentik.flows.models import ConfigurableStage, Stage +from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage from authentik.lib.models import SerializerModel from authentik.lib.utils.errors import exception_to_string from authentik.lib.utils.http import get_http_session @@ -39,7 +39,7 @@ class SMSAuthTypes(models.TextChoices): BEARER = "bearer" -class AuthenticatorSMSStage(ConfigurableStage, Stage): +class AuthenticatorSMSStage(ConfigurableStage, FriendlyNamedStage, Stage): """Use SMS-based TOTP instead of authenticator-based.""" provider = models.TextField(choices=SMSProviders.choices) @@ -168,7 +168,7 @@ class AuthenticatorSMSStage(ConfigurableStage, Stage): def ui_user_settings(self) -> Optional[UserSettingSerializer]: return UserSettingSerializer( data={ - "title": str(self._meta.verbose_name), + "title": self.friendly_name or str(self._meta.verbose_name), "component": "ak-user-settings-authenticator-sms", } ) diff --git a/authentik/stages/authenticator_static/api.py b/authentik/stages/authenticator_static/api.py index 32fd18051..a5f534cbd 100644 --- a/authentik/stages/authenticator_static/api.py +++ b/authentik/stages/authenticator_static/api.py @@ -18,7 +18,7 @@ class AuthenticatorStaticStageSerializer(StageSerializer): class Meta: model = AuthenticatorStaticStage - fields = StageSerializer.Meta.fields + ["configure_flow", "token_count"] + fields = StageSerializer.Meta.fields + ["configure_flow", "friendly_name", "token_count"] class AuthenticatorStaticStageViewSet(UsedByMixin, ModelViewSet): diff --git a/authentik/stages/authenticator_static/migrations/0006_authenticatorstaticstage_friendly_name.py b/authentik/stages/authenticator_static/migrations/0006_authenticatorstaticstage_friendly_name.py new file mode 100644 index 000000000..89ab51d15 --- /dev/null +++ b/authentik/stages/authenticator_static/migrations/0006_authenticatorstaticstage_friendly_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.7 on 2023-04-02 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_stages_authenticator_static", "0005_default_setup_flow"), + ] + + operations = [ + migrations.AddField( + model_name="authenticatorstaticstage", + name="friendly_name", + field=models.TextField(null=True), + ), + ] diff --git a/authentik/stages/authenticator_static/models.py b/authentik/stages/authenticator_static/models.py index a4edaf167..631458a21 100644 --- a/authentik/stages/authenticator_static/models.py +++ b/authentik/stages/authenticator_static/models.py @@ -7,10 +7,10 @@ from django.views import View from rest_framework.serializers import BaseSerializer from authentik.core.types import UserSettingSerializer -from authentik.flows.models import ConfigurableStage, Stage +from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage -class AuthenticatorStaticStage(ConfigurableStage, Stage): +class AuthenticatorStaticStage(ConfigurableStage, FriendlyNamedStage, Stage): """Generate static tokens for the user as a backup.""" token_count = models.IntegerField(default=6) @@ -34,7 +34,7 @@ class AuthenticatorStaticStage(ConfigurableStage, Stage): def ui_user_settings(self) -> Optional[UserSettingSerializer]: return UserSettingSerializer( data={ - "title": str(self._meta.verbose_name), + "title": self.friendly_name or str(self._meta.verbose_name), "component": "ak-user-settings-authenticator-static", } ) diff --git a/authentik/stages/authenticator_totp/api.py b/authentik/stages/authenticator_totp/api.py index 12b800f01..61f596843 100644 --- a/authentik/stages/authenticator_totp/api.py +++ b/authentik/stages/authenticator_totp/api.py @@ -18,7 +18,7 @@ class AuthenticatorTOTPStageSerializer(StageSerializer): class Meta: model = AuthenticatorTOTPStage - fields = StageSerializer.Meta.fields + ["configure_flow", "digits"] + fields = StageSerializer.Meta.fields + ["configure_flow", "friendly_name", "digits"] class AuthenticatorTOTPStageViewSet(UsedByMixin, ModelViewSet): diff --git a/authentik/stages/authenticator_totp/migrations/0007_authenticatortotpstage_friendly_name.py b/authentik/stages/authenticator_totp/migrations/0007_authenticatortotpstage_friendly_name.py new file mode 100644 index 000000000..5568657d6 --- /dev/null +++ b/authentik/stages/authenticator_totp/migrations/0007_authenticatortotpstage_friendly_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.7 on 2023-04-02 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_stages_authenticator_totp", "0006_default_setup_flow"), + ] + + operations = [ + migrations.AddField( + model_name="authenticatortotpstage", + name="friendly_name", + field=models.TextField(null=True), + ), + ] diff --git a/authentik/stages/authenticator_totp/models.py b/authentik/stages/authenticator_totp/models.py index 26e274557..03c84b553 100644 --- a/authentik/stages/authenticator_totp/models.py +++ b/authentik/stages/authenticator_totp/models.py @@ -7,7 +7,7 @@ from django.views import View from rest_framework.serializers import BaseSerializer from authentik.core.types import UserSettingSerializer -from authentik.flows.models import ConfigurableStage, Stage +from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage class TOTPDigits(models.IntegerChoices): @@ -17,7 +17,7 @@ class TOTPDigits(models.IntegerChoices): EIGHT = 8, _("8 digits, not compatible with apps like Google Authenticator") -class AuthenticatorTOTPStage(ConfigurableStage, Stage): +class AuthenticatorTOTPStage(ConfigurableStage, FriendlyNamedStage, Stage): """Enroll a user's device into Time-based OTP.""" digits = models.IntegerField(choices=TOTPDigits.choices) @@ -41,7 +41,7 @@ class AuthenticatorTOTPStage(ConfigurableStage, Stage): def ui_user_settings(self) -> Optional[UserSettingSerializer]: return UserSettingSerializer( data={ - "title": str(self._meta.verbose_name), + "title": self.friendly_name or str(self._meta.verbose_name), "component": "ak-user-settings-authenticator-totp", } ) diff --git a/authentik/stages/authenticator_webauthn/api.py b/authentik/stages/authenticator_webauthn/api.py index 6ca63155f..9d1914353 100644 --- a/authentik/stages/authenticator_webauthn/api.py +++ b/authentik/stages/authenticator_webauthn/api.py @@ -19,6 +19,7 @@ class AuthenticateWebAuthnStageSerializer(StageSerializer): model = AuthenticateWebAuthnStage fields = StageSerializer.Meta.fields + [ "configure_flow", + "friendly_name", "user_verification", "authenticator_attachment", "resident_key_requirement", diff --git a/authentik/stages/authenticator_webauthn/migrations/0009_authenticatewebauthnstage_friendly_name.py b/authentik/stages/authenticator_webauthn/migrations/0009_authenticatewebauthnstage_friendly_name.py new file mode 100644 index 000000000..2f51f3438 --- /dev/null +++ b/authentik/stages/authenticator_webauthn/migrations/0009_authenticatewebauthnstage_friendly_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.7 on 2023-04-02 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_stages_authenticator_webauthn", "0008_alter_webauthndevice_credential_id"), + ] + + operations = [ + migrations.AddField( + model_name="authenticatewebauthnstage", + name="friendly_name", + field=models.TextField(null=True), + ), + ] diff --git a/authentik/stages/authenticator_webauthn/models.py b/authentik/stages/authenticator_webauthn/models.py index f94ad8bd2..e498f2a0b 100644 --- a/authentik/stages/authenticator_webauthn/models.py +++ b/authentik/stages/authenticator_webauthn/models.py @@ -12,7 +12,7 @@ from webauthn.helpers.base64url_to_bytes import base64url_to_bytes from webauthn.helpers.structs import PublicKeyCredentialDescriptor from authentik.core.types import UserSettingSerializer -from authentik.flows.models import ConfigurableStage, Stage +from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage from authentik.lib.models import SerializerModel @@ -66,7 +66,7 @@ class AuthenticatorAttachment(models.TextChoices): CROSS_PLATFORM = "cross-platform" -class AuthenticateWebAuthnStage(ConfigurableStage, Stage): +class AuthenticateWebAuthnStage(ConfigurableStage, FriendlyNamedStage, Stage): """WebAuthn stage""" user_verification = models.TextField( @@ -100,7 +100,7 @@ class AuthenticateWebAuthnStage(ConfigurableStage, Stage): def ui_user_settings(self) -> Optional[UserSettingSerializer]: return UserSettingSerializer( data={ - "title": str(self._meta.verbose_name), + "title": self.friendly_name or str(self._meta.verbose_name), "component": "ak-user-settings-authenticator-webauthn", } ) diff --git a/schema.yml b/schema.yml index 0fa1a0d0e..28e1bbb3d 100644 --- a/schema.yml +++ b/schema.yml @@ -20345,6 +20345,10 @@ paths: schema: type: string format: uuid + - in: query + name: friendly_name + schema: + type: string - in: query name: from_number schema: @@ -20650,6 +20654,10 @@ paths: schema: type: string format: uuid + - in: query + name: friendly_name + schema: + type: string - in: query name: name schema: @@ -20946,6 +20954,10 @@ paths: * `6` - 6 digits, widely compatible * `8` - 8 digits, not compatible with apps like Google Authenticator + - in: query + name: friendly_name + schema: + type: string - in: query name: name schema: @@ -21533,6 +21545,10 @@ paths: schema: type: string format: uuid + - in: query + name: friendly_name + schema: + type: string - in: query name: name schema: @@ -26560,6 +26576,9 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true user_verification: $ref: '#/components/schemas/UserVerificationEnum' authenticator_attachment: @@ -26592,6 +26611,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 user_verification: $ref: '#/components/schemas/UserVerificationEnum' authenticator_attachment: @@ -26819,6 +26842,9 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true client_id: type: string api_hostname: @@ -26875,6 +26901,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 client_id: type: string minLength: 1 @@ -26973,6 +27003,9 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true provider: $ref: '#/components/schemas/ProviderEnum' from_number: @@ -27023,6 +27056,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 provider: $ref: '#/components/schemas/ProviderEnum' from_number: @@ -27129,6 +27166,9 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true token_count: type: integer maximum: 2147483647 @@ -27157,6 +27197,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 token_count: type: integer maximum: 2147483647 @@ -27240,6 +27284,9 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true digits: allOf: - $ref: '#/components/schemas/DigitsEnum' @@ -27270,6 +27317,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 digits: allOf: - $ref: '#/components/schemas/DigitsEnum' @@ -35347,6 +35398,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 user_verification: $ref: '#/components/schemas/UserVerificationEnum' authenticator_attachment: @@ -35372,6 +35427,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 client_id: type: string minLength: 1 @@ -35404,6 +35463,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 provider: $ref: '#/components/schemas/ProviderEnum' from_number: @@ -35446,6 +35509,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 token_count: type: integer maximum: 2147483647 @@ -35467,6 +35534,10 @@ components: nullable: true description: Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage. + friendly_name: + type: string + nullable: true + minLength: 1 digits: allOf: - $ref: '#/components/schemas/DigitsEnum' diff --git a/web/src/admin/stages/authenticator_duo/AuthenticatorDuoStageForm.ts b/web/src/admin/stages/authenticator_duo/AuthenticatorDuoStageForm.ts index fbd155026..01cf8fbad 100644 --- a/web/src/admin/stages/authenticator_duo/AuthenticatorDuoStageForm.ts +++ b/web/src/admin/stages/authenticator_duo/AuthenticatorDuoStageForm.ts @@ -10,7 +10,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; -import { ifDefined } from "lit/directives/if-defined.js"; import { AuthenticatorDuoStage, @@ -59,11 +58,25 @@ export class AuthenticatorDuoStageForm extends ModelForm + + +

+ ${t`Display name of this authenticator, used by users when they enroll an authenticator.`} +

+
@@ -87,7 +86,7 @@ export class AuthenticatorSMSStageForm extends ModelForm @@ -131,7 +130,7 @@ export class AuthenticatorSMSStageForm extends ModelForm @@ -142,7 +141,7 @@ export class AuthenticatorSMSStageForm extends ModelForm

@@ -156,7 +155,7 @@ export class AuthenticatorSMSStageForm extends ModelForm

@@ -206,11 +205,25 @@ export class AuthenticatorSMSStageForm extends ModelForm + + +

+ ${t`Display name of this authenticator, used by users when they enroll an authenticator.`} +

+
${t`Stage-specific settings`}
@@ -247,7 +260,7 @@ export class AuthenticatorSMSStageForm extends ModelForm diff --git a/web/src/admin/stages/authenticator_static/AuthenticatorStaticStageForm.ts b/web/src/admin/stages/authenticator_static/AuthenticatorStaticStageForm.ts index 4f193f404..35fbef7e0 100644 --- a/web/src/admin/stages/authenticator_static/AuthenticatorStaticStageForm.ts +++ b/web/src/admin/stages/authenticator_static/AuthenticatorStaticStageForm.ts @@ -9,7 +9,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; -import { ifDefined } from "lit/directives/if-defined.js"; import { AuthenticatorStaticStage, @@ -57,11 +56,25 @@ export class AuthenticatorStaticStageForm extends ModelForm + + +

+ ${t`Display name of this authenticator, used by users when they enroll an authenticator.`} +

+
${t`Stage-specific settings`}
diff --git a/web/src/admin/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts b/web/src/admin/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts index ff8f622f6..bf6347b73 100644 --- a/web/src/admin/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts +++ b/web/src/admin/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts @@ -1,5 +1,6 @@ import { RenderFlowOption } from "@goauthentik/admin/flows/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import { first } from "@goauthentik/common/utils"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; @@ -9,7 +10,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; -import { ifDefined } from "lit/directives/if-defined.js"; import { AuthenticatorTOTPStage, @@ -58,11 +58,25 @@ export class AuthenticatorTOTPStageForm extends ModelForm + + +

+ ${t`Display name of this authenticator, used by users when they enroll an authenticator.`} +

+
${t`Stage-specific settings`}
diff --git a/web/src/admin/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts b/web/src/admin/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts index 0c9abf1d2..e8b31b2f6 100644 --- a/web/src/admin/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts +++ b/web/src/admin/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts @@ -1,5 +1,6 @@ import { RenderFlowOption } from "@goauthentik/admin/flows/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import { first } from "@goauthentik/common/utils"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import "@goauthentik/elements/forms/Radio"; @@ -9,7 +10,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; -import { ifDefined } from "lit/directives/if-defined.js"; import { AuthenticateWebAuthnStage, @@ -63,11 +63,25 @@ export class AuthenticateWebAuthnStageForm extends ModelForm + + +

+ ${t`Display name of this authenticator, used by users when they enroll an authenticator.`} +

+
${t`Stage-specific settings`}
diff --git a/web/src/user/user-settings/mfa/MFADevicesPage.ts b/web/src/user/user-settings/mfa/MFADevicesPage.ts index cebeb170a..229d4ae61 100644 --- a/web/src/user/user-settings/mfa/MFADevicesPage.ts +++ b/web/src/user/user-settings/mfa/MFADevicesPage.ts @@ -4,8 +4,7 @@ import "@goauthentik/elements/buttons/ModalButton"; import "@goauthentik/elements/buttons/TokenCopyButton"; import "@goauthentik/elements/forms/DeleteBulkForm"; import "@goauthentik/elements/forms/ModalForm"; -import { PaginatedResponse } from "@goauthentik/elements/table/Table"; -import { Table, TableColumn } from "@goauthentik/elements/table/Table"; +import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; import "@goauthentik/user/user-settings/mfa/MFADeviceForm"; import { t } from "@lingui/macro"; @@ -17,17 +16,8 @@ import { ifDefined } from "lit/directives/if-defined.js"; import { AuthenticatorsApi, Device, UserSetting } from "@goauthentik/api"; export function stageToAuthenticatorName(stage: UserSetting): string { - switch (stage.component) { - case "ak-user-settings-authenticator-duo": - return t`Duo authenticator`; - case "ak-user-settings-authenticator-sms": - return t`SMS authenticator`; - case "ak-user-settings-authenticator-static": - return t`Static authenticator`; - case "ak-user-settings-authenticator-totp": - return t`TOTP authenticator`; - case "ak-user-settings-authenticator-webauthn": - return t`Security key authenticator`; + if (stage.title) { + return stage.title; } return `Invalid stage component ${stage.component}`; }