stages/authenticator_validate: add ability to select multiple configuration stages which the user can choose

closes #1843

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-02-12 16:55:50 +01:00
parent 9070df6c26
commit 2ccab75021
16 changed files with 346 additions and 102 deletions

View File

@ -13,8 +13,8 @@ class AuthenticatorValidateStageSerializer(StageSerializer):
def validate_not_configured_action(self, value): def validate_not_configured_action(self, value):
"""Ensure that a configuration stage is set when not_configured_action is configure""" """Ensure that a configuration stage is set when not_configured_action is configure"""
configuration_stage = self.initial_data.get("configuration_stage") configuration_stages = self.initial_data.get("configuration_stages")
if value == NotConfiguredAction.CONFIGURE and configuration_stage is None: if value == NotConfiguredAction.CONFIGURE and configuration_stages is None:
raise ValidationError( raise ValidationError(
( (
'When "Not configured action" is set to "Configure", ' 'When "Not configured action" is set to "Configure", '
@ -29,7 +29,7 @@ class AuthenticatorValidateStageSerializer(StageSerializer):
fields = StageSerializer.Meta.fields + [ fields = StageSerializer.Meta.fields + [
"not_configured_action", "not_configured_action",
"device_classes", "device_classes",
"configuration_stage", "configuration_stages",
] ]
@ -38,5 +38,5 @@ class AuthenticatorValidateStageViewSet(UsedByMixin, ModelViewSet):
queryset = AuthenticatorValidateStage.objects.all() queryset = AuthenticatorValidateStage.objects.all()
serializer_class = AuthenticatorValidateStageSerializer serializer_class = AuthenticatorValidateStageSerializer
filterset_fields = ["name", "not_configured_action", "configuration_stage"] filterset_fields = ["name", "not_configured_action", "configuration_stages"]
ordering = ["name"] ordering = ["name"]

View File

@ -0,0 +1,44 @@
# Generated by Django 4.0.1 on 2022-01-05 22:09
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def migrate_configuration_stage(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
AuthenticatorValidateStage = apps.get_model(
"authentik_stages_authenticator_validate", "AuthenticatorValidateStage"
)
for stage in AuthenticatorValidateStage.objects.using(db_alias).all():
if stage.configuration_stage:
stage.configuration_stages.set([stage.configuration_stage])
stage.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0021_auto_20211227_2103"),
("authentik_stages_authenticator_validate", "0009_default_stage"),
]
operations = [
migrations.AddField(
model_name="authenticatorvalidatestage",
name="configuration_stages",
field=models.ManyToManyField(
blank=True,
default=None,
help_text="Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.",
related_name="+",
to="authentik_flows.Stage",
),
),
migrations.RunPython(migrate_configuration_stage),
migrations.RemoveField(
model_name="authenticatorvalidatestage",
name="configuration_stage",
),
]

View File

@ -38,16 +38,14 @@ class AuthenticatorValidateStage(Stage):
choices=NotConfiguredAction.choices, default=NotConfiguredAction.SKIP choices=NotConfiguredAction.choices, default=NotConfiguredAction.SKIP
) )
configuration_stage = models.ForeignKey( configuration_stages = models.ManyToManyField(
Stage, Stage,
null=True,
blank=True, blank=True,
default=None, default=None,
on_delete=models.SET_DEFAULT,
related_name="+", related_name="+",
help_text=_( help_text=_(
( (
"Stage used to configure Authenticator when user doesn't have any compatible " "Stages used to configure Authenticator when user doesn't have any compatible "
"devices. After this configuration Stage passes, the user is not prompted again." "devices. After this configuration Stage passes, the user is not prompted again."
) )
), ),

View File

@ -1,10 +1,12 @@
"""Authenticator Validation""" """Authenticator Validation"""
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django_otp import devices_for_user from django_otp import devices_for_user
from rest_framework.fields import CharField, IntegerField, JSONField, ListField from rest_framework.fields import CharField, IntegerField, JSONField, ListField, UUIDField
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import User
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.events.utils import cleanse_dict, sanitize_dict from authentik.events.utils import cleanse_dict, sanitize_dict
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge
@ -26,6 +28,18 @@ from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
LOGGER = get_logger() LOGGER = get_logger()
SESSION_STAGES = "goauthentik.io/stages/authenticator_validate/stages"
SESSION_SELECTED_STAGE = "goauthentik.io/stages/authenticator_validate/selected_stage"
SESSION_DEVICE_CHALLENGES = "goauthentik.io/stages/authenticator_validate/device_challenges"
class SelectableStageSerializer(PassiveSerializer):
"""Serializer for stages which can be selected by users"""
pk = UUIDField()
name = CharField()
verbose_name = CharField()
meta_model_name = CharField()
class AuthenticatorValidationChallenge(WithUserInfoChallenge): class AuthenticatorValidationChallenge(WithUserInfoChallenge):
@ -33,12 +47,14 @@ class AuthenticatorValidationChallenge(WithUserInfoChallenge):
device_challenges = ListField(child=DeviceChallenge()) device_challenges = ListField(child=DeviceChallenge())
component = CharField(default="ak-stage-authenticator-validate") component = CharField(default="ak-stage-authenticator-validate")
configuration_stages = ListField(child=SelectableStageSerializer())
class AuthenticatorValidationChallengeResponse(ChallengeResponse): class AuthenticatorValidationChallengeResponse(ChallengeResponse):
"""Challenge used for Code-based and WebAuthn authenticators""" """Challenge used for Code-based and WebAuthn authenticators"""
selected_challenge = DeviceChallenge(required=False) selected_challenge = DeviceChallenge(required=False)
selected_stage = CharField(required=False)
code = CharField(required=False) code = CharField(required=False)
webauthn = JSONField(required=False) webauthn = JSONField(required=False)
@ -84,6 +100,15 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
select_challenge(self.stage.request, devices.first()) select_challenge(self.stage.request, devices.first())
return challenge return challenge
def validate_selected_stage(self, stage_pk: str) -> str:
"""Check that the selected stage is valid"""
stages = self.stage.request.session.get(SESSION_STAGES, [])
if not any(str(stage.pk) == stage_pk for stage in stages):
raise ValidationError("Selected stage is invalid")
LOGGER.debug("Setting selected stage to ", stage=stage_pk)
self.stage.request.session[SESSION_SELECTED_STAGE] = stage_pk
return stage_pk
def validate(self, attrs: dict): def validate(self, attrs: dict):
# Checking if the given data is from a valid device class is done above # Checking if the given data is from a valid device class is done above
# Here we only check if the any data was sent at all # Here we only check if the any data was sent at all
@ -164,7 +189,7 @@ class AuthenticatorValidateStageView(ChallengeStageView):
else: else:
LOGGER.debug("No pending user, continuing") LOGGER.debug("No pending user, continuing")
return self.executor.stage_ok() return self.executor.stage_ok()
self.request.session["device_challenges"] = challenges self.request.session[SESSION_DEVICE_CHALLENGES] = challenges
# No allowed devices # No allowed devices
if len(challenges) < 1: if len(challenges) < 1:
@ -175,35 +200,71 @@ class AuthenticatorValidateStageView(ChallengeStageView):
LOGGER.debug("Authenticator not configured, denying") LOGGER.debug("Authenticator not configured, denying")
return self.executor.stage_invalid() return self.executor.stage_invalid()
if stage.not_configured_action == NotConfiguredAction.CONFIGURE: if stage.not_configured_action == NotConfiguredAction.CONFIGURE:
if not stage.configuration_stage: LOGGER.debug("Authenticator not configured, forcing configure")
Event.new( return self.prepare_stages(user)
EventAction.CONFIGURATION_ERROR,
message=(
"Authenticator validation stage is set to configure user "
"but no configuration flow is set."
),
stage=self,
).from_http(self.request).set_user(user).save()
return self.executor.stage_invalid()
LOGGER.debug("Authenticator not configured, sending user to configure")
# Because the foreign key to stage.configuration_stage points to
# a base stage class, we need to do another lookup
stage = Stage.objects.get_subclass(pk=stage.configuration_stage.pk)
# plan.insert inserts at 1 index, so when stage_ok pops 0,
# the configuration stage is next
self.executor.plan.insert_stage(stage)
return self.executor.stage_ok()
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def get_challenge(self) -> AuthenticatorValidationChallenge: def prepare_stages(self, user: User, *args, **kwargs) -> HttpResponse:
challenges = self.request.session.get("device_challenges") """Check how the user can configure themselves. If no stages are set, return an error.
if not challenges: If a single stage is set, insert that stage directly. If multiple are selected, include
LOGGER.debug("Authenticator Validation stage ran without challenges") them in the challenge."""
stage: AuthenticatorValidateStage = self.executor.current_stage
if not stage.configuration_stages.exists():
Event.new(
EventAction.CONFIGURATION_ERROR,
message=(
"Authenticator validation stage is set to configure user "
"but no configuration flow is set."
),
stage=self,
).from_http(self.request).set_user(user).save()
return self.executor.stage_invalid() return self.executor.stage_invalid()
if stage.configuration_stages.count() == 1:
self.request.session[SESSION_SELECTED_STAGE] = stage.configuration_stages.first()
LOGGER.debug(
"Single stage configured, auto-selecting",
stage=self.request.session[SESSION_SELECTED_STAGE],
)
stages = Stage.objects.filter(pk__in=stage.configuration_stages.all()).select_subclasses()
self.request.session[SESSION_STAGES] = stages
return super().get(self.request, *args, **kwargs)
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
if (
SESSION_SELECTED_STAGE in self.request.session
and self.executor.current_stage.not_configured_action == NotConfiguredAction.CONFIGURE
):
LOGGER.debug("Got selected stage in session, running that")
stage_pk = self.request.session.get(SESSION_SELECTED_STAGE)
# Because the foreign key to stage.configuration_stage points to
# a base stage class, we need to do another lookup
stage = Stage.objects.get_subclass(pk=stage_pk)
# plan.insert inserts at 1 index, so when stage_ok pops 0,
# the configuration stage is next
self.executor.plan.insert_stage(stage)
return self.executor.stage_ok()
return super().post(request, *args, **kwargs)
def get_challenge(self) -> AuthenticatorValidationChallenge:
challenges = self.request.session.get(SESSION_DEVICE_CHALLENGES, [])
stages = self.request.session.get(SESSION_STAGES, [])
stage_challenges = []
for stage in stages:
serializer = SelectableStageSerializer(
data={
"pk": stage.pk,
"name": stage.name,
"verbose_name": str(stage._meta.verbose_name),
"meta_model_name": f"{stage._meta.app_label}.{stage._meta.model_name}",
}
)
serializer.is_valid()
stage_challenges.append(serializer.data)
return AuthenticatorValidationChallenge( return AuthenticatorValidationChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value, "type": ChallengeTypes.NATIVE.value,
"device_challenges": challenges, "device_challenges": challenges,
"configuration_stages": stage_challenges,
} }
) )

View File

@ -43,8 +43,8 @@ class AuthenticatorValidateStageTests(FlowTestCase):
stage = AuthenticatorValidateStage.objects.create( stage = AuthenticatorValidateStage.objects.create(
name="foo", name="foo",
not_configured_action=NotConfiguredAction.CONFIGURE, not_configured_action=NotConfiguredAction.CONFIGURE,
configuration_stage=conf_stage,
) )
stage.configuration_stages.set([conf_stage])
flow = Flow.objects.create(name="test", slug="test", title="test") flow = Flow.objects.create(name="test", slug="test", title="test")
FlowStageBinding.objects.create(target=flow, stage=conf_stage, order=0) FlowStageBinding.objects.create(target=flow, stage=conf_stage, order=0)
FlowStageBinding.objects.create(target=flow, stage=stage, order=1) FlowStageBinding.objects.create(target=flow, stage=stage, order=1)

View File

@ -15045,10 +15045,14 @@ paths:
description: AuthenticatorValidateStage Viewset description: AuthenticatorValidateStage Viewset
parameters: parameters:
- in: query - in: query
name: configuration_stage name: configuration_stages
schema: schema:
type: string type: array
format: uuid items:
type: string
format: uuid
explode: true
style: form
- in: query - in: query
name: name name: name
schema: schema:
@ -19826,11 +19830,12 @@ components:
items: items:
$ref: '#/components/schemas/DeviceClassesEnum' $ref: '#/components/schemas/DeviceClassesEnum'
description: Device classes which can be used to authenticate description: Device classes which can be used to authenticate
configuration_stage: configuration_stages:
type: string type: array
format: uuid items:
nullable: true type: string
description: Stage used to configure Authenticator when user doesn't have format: uuid
description: Stages used to configure Authenticator when user doesn't have
any compatible devices. After this configuration Stage passes, the user any compatible devices. After this configuration Stage passes, the user
is not prompted again. is not prompted again.
required: required:
@ -19858,11 +19863,12 @@ components:
items: items:
$ref: '#/components/schemas/DeviceClassesEnum' $ref: '#/components/schemas/DeviceClassesEnum'
description: Device classes which can be used to authenticate description: Device classes which can be used to authenticate
configuration_stage: configuration_stages:
type: string type: array
format: uuid items:
nullable: true type: string
description: Stage used to configure Authenticator when user doesn't have format: uuid
description: Stages used to configure Authenticator when user doesn't have
any compatible devices. After this configuration Stage passes, the user any compatible devices. After this configuration Stage passes, the user
is not prompted again. is not prompted again.
required: required:
@ -19892,7 +19898,12 @@ components:
type: array type: array
items: items:
$ref: '#/components/schemas/DeviceChallenge' $ref: '#/components/schemas/DeviceChallenge'
configuration_stages:
type: array
items:
$ref: '#/components/schemas/SelectableStage'
required: required:
- configuration_stages
- device_challenges - device_challenges
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
@ -19907,6 +19918,9 @@ components:
default: ak-stage-authenticator-validate default: ak-stage-authenticator-validate
selected_challenge: selected_challenge:
$ref: '#/components/schemas/DeviceChallengeRequest' $ref: '#/components/schemas/DeviceChallengeRequest'
selected_stage:
type: string
minLength: 1
code: code:
type: string type: string
minLength: 1 minLength: 1
@ -26677,11 +26691,12 @@ components:
items: items:
$ref: '#/components/schemas/DeviceClassesEnum' $ref: '#/components/schemas/DeviceClassesEnum'
description: Device classes which can be used to authenticate description: Device classes which can be used to authenticate
configuration_stage: configuration_stages:
type: string type: array
format: uuid items:
nullable: true type: string
description: Stage used to configure Authenticator when user doesn't have format: uuid
description: Stages used to configure Authenticator when user doesn't have
any compatible devices. After this configuration Stage passes, the user any compatible devices. After this configuration Stage passes, the user
is not prompted again. is not prompted again.
PatchedCaptchaStageRequest: PatchedCaptchaStageRequest:
@ -30017,6 +30032,24 @@ components:
- direct - direct
- cached - cached
type: string type: string
SelectableStage:
type: object
description: Serializer for stages which can be selected by users
properties:
pk:
type: string
format: uuid
name:
type: string
verbose_name:
type: string
meta_model_name:
type: string
required:
- meta_model_name
- name
- pk
- verbose_name
ServiceConnection: ServiceConnection:
type: object type: object
description: ServiceConnection Serializer description: ServiceConnection Serializer

View File

@ -67,7 +67,7 @@ export class AuthenticatorValidateStage
return this._selectedDeviceChallenge; return this._selectedDeviceChallenge;
} }
submit(payload: AuthenticatorValidationChallengeResponseRequest): Promise<void> { submit(payload: AuthenticatorValidationChallengeResponseRequest): Promise<boolean> {
return this.host?.submit(payload) || Promise.resolve(); return this.host?.submit(payload) || Promise.resolve();
} }
@ -140,7 +140,7 @@ export class AuthenticatorValidateStage
} }
renderDevicePicker(): TemplateResult { renderDevicePicker(): TemplateResult {
return html` <ul> return html`<ul>
${this.challenge?.deviceChallenges.map((challenges) => { ${this.challenge?.deviceChallenges.map((challenges) => {
return html`<li> return html`<li>
<button <button
@ -157,6 +157,30 @@ export class AuthenticatorValidateStage
</ul>`; </ul>`;
} }
renderStagePicker(): TemplateResult {
return html`<ul>
${this.challenge?.configurationStages.map((stage) => {
return html`<li>
<button
class="pf-c-button authenticator-button"
type="button"
@click=${() => {
this.submit({
component: this.challenge.component || "",
selectedStage: stage.pk,
});
}}
>
<div class="right">
<p>${stage.name}</p>
<small>${stage.verboseName}</small>
</div>
</button>
</li>`;
})}
</ul>`;
}
renderDeviceChallenge(): TemplateResult { renderDeviceChallenge(): TemplateResult {
if (!this.selectedDeviceChallenge) { if (!this.selectedDeviceChallenge) {
return html``; return html``;
@ -242,6 +266,9 @@ export class AuthenticatorValidateStage
${this.selectedDeviceChallenge ${this.selectedDeviceChallenge
? "" ? ""
: html`<p>${t`Select an authentication method.`}</p>`} : html`<p>${t`Select an authentication method.`}</p>`}
${this.challenge.configurationStages.length > 0
? this.renderStagePicker()
: html``}
</form> </form>
${this.renderDevicePicker()} ${this.renderDevicePicker()}
</div> </div>

View File

@ -959,8 +959,12 @@ msgid "Configuration flow"
msgstr "Ablauf der Konfiguration" msgstr "Ablauf der Konfiguration"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "Konfiguration Stufe" #~ msgstr "Konfiguration Stufe"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "Konfiguriere WebAuthn" #~ msgstr "Konfiguriere WebAuthn"
@ -4410,8 +4414,8 @@ msgid "Stage type"
msgstr "Phasen Typ" msgstr "Phasen Typ"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Phase zum Konfigurieren von Authenticator, wenn der Benutzer keine kompatiblen Geräte hat. Nach Ablauf dieser Konfigurationsphase wird der Benutzer nicht erneut aufgefordert." #~ msgstr "Phase zum Konfigurieren von Authenticator, wenn der Benutzer keine kompatiblen Geräte hat. Nach Ablauf dieser Konfigurationsphase wird der Benutzer nicht erneut aufgefordert."
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4470,6 +4474,10 @@ msgstr "Phasen"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "Phasen sind einzelne Schritte eines Flows, durch die ein Benutzer geführt wird. Eine Phase kann nur innerhalb eines Flows ausgeführt werden." msgstr "Phasen sind einzelne Schritte eines Flows, durch die ein Benutzer geführt wird. Eine Phase kann nur innerhalb eines Flows ausgeführt werden."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "Zustand" msgstr "Zustand"
@ -5935,6 +5943,10 @@ msgstr "Wenn diese Option aktiviert ist, wird die Einladung nach ihrer Benutzung
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "Wenn diese Option aktiviert ist, werden Benutzerfelder unabhängig von ihrem Format abgeglichen." msgstr "Wenn diese Option aktiviert ist, werden Benutzerfelder unabhängig von ihrem Format abgeglichen."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "Wenn diese Option ausgewählt ist, wird ein Passwortfeld auf derselben Seite statt auf einer separaten Seite angezeigt. Dadurch werden Angriffe auf die Aufzählung von Benutzernamen verhindert." msgstr "Wenn diese Option ausgewählt ist, wird ein Passwortfeld auf derselben Seite statt auf einer separaten Seite angezeigt. Dadurch werden Angriffe auf die Aufzählung von Benutzernamen verhindert."

View File

@ -950,8 +950,12 @@ msgid "Configuration flow"
msgstr "Flujo de configuración" msgstr "Flujo de configuración"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "Etapa de configuración" #~ msgstr "Etapa de configuración"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "Configurar WebAuthn" #~ msgstr "Configurar WebAuthn"
@ -4403,8 +4407,8 @@ msgid "Stage type"
msgstr "Tipo de escenario" msgstr "Tipo de escenario"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Etapa utilizada para configurar Authenticator cuando el usuario no tiene ningún dispositivo compatible. Una vez superada esta etapa de configuración, no se volverá a preguntar al usuario." #~ msgstr "Etapa utilizada para configurar Authenticator cuando el usuario no tiene ningún dispositivo compatible. Una vez superada esta etapa de configuración, no se volverá a preguntar al usuario."
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4463,6 +4467,10 @@ msgstr "Etapas"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "Las etapas son pasos individuales de un flujo por los que se guía al usuario. Una etapa solo se puede ejecutar desde dentro de un flujo." msgstr "Las etapas son pasos individuales de un flujo por los que se guía al usuario. Una etapa solo se puede ejecutar desde dentro de un flujo."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "Estado" msgstr "Estado"
@ -5928,6 +5936,10 @@ msgstr "Cuando se habilita, la invitación se eliminará después de su uso."
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "Cuando se habilita, los campos de usuario coinciden independientemente de su carcasa." msgstr "Cuando se habilita, los campos de usuario coinciden independientemente de su carcasa."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "Cuando se selecciona, se muestra un campo de contraseña en la misma página en lugar de en una página separada. Esto evita ataques de enumeración de nombres de usuario." msgstr "Cuando se selecciona, se muestra un campo de contraseña en la misma página en lugar de en una página separada. Esto evita ataques de enumeración de nombres de usuario."

View File

@ -947,8 +947,12 @@ msgid "Configuration flow"
msgstr "Przepływ konfiguracji" msgstr "Przepływ konfiguracji"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "Etap konfiguracji" #~ msgstr "Etap konfiguracji"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "Skonfiguruj WebAuthn" #~ msgstr "Skonfiguruj WebAuthn"
@ -4400,8 +4404,8 @@ msgid "Stage type"
msgstr "Typ etapu" msgstr "Typ etapu"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Etap używany do konfiguracji uwierzytelniacza, gdy użytkownik nie ma żadnych kompatybilnych urządzeń. Po zakończeniu tego etapu konfiguracji użytkownik nie jest ponownie pytany." #~ msgstr "Etap używany do konfiguracji uwierzytelniacza, gdy użytkownik nie ma żadnych kompatybilnych urządzeń. Po zakończeniu tego etapu konfiguracji użytkownik nie jest ponownie pytany."
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4460,6 +4464,10 @@ msgstr "Etapy"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "Etapy to pojedyncze kroki przepływu, przez które prowadzony jest użytkownik. Etap można wykonać tylko z przepływu." msgstr "Etapy to pojedyncze kroki przepływu, przez które prowadzony jest użytkownik. Etap można wykonać tylko z przepływu."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "Stan" msgstr "Stan"
@ -5925,6 +5933,10 @@ msgstr "Po włączeniu zaproszenie zostanie usunięte po użyciu."
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "Po włączeniu pola użytkownika są dopasowywane niezależnie od wielkości liter." msgstr "Po włączeniu pola użytkownika są dopasowywane niezależnie od wielkości liter."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "Po wybraniu pole hasła jest wyświetlane na tej samej stronie zamiast na osobnej stronie. Zapobiega to atakom polegającym na wyliczaniu nazw użytkowników." msgstr "Po wybraniu pole hasła jest wyświetlane na tej samej stronie zamiast na osobnej stronie. Zapobiega to atakom polegającym na wyliczaniu nazw użytkowników."

View File

@ -950,8 +950,12 @@ msgid "Configuration flow"
msgstr "Yapılandırma akışı" msgstr "Yapılandırma akışı"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "Yapılandırma aşamasında" #~ msgstr "Yapılandırma aşamasında"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "WebAuthn'i Yapılandır" #~ msgstr "WebAuthn'i Yapılandır"
@ -4405,8 +4409,8 @@ msgid "Stage type"
msgstr "Aşama türü" msgstr "Aşama türü"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Kullanıcının uyumlu bir aygıtı olmadığında Kimlik Doğrulayıcısı'nı yapılandırmak için kullanılan Aşama. Bu yapılandırma Stage geçtikten sonra kullanıcıya yeniden istenmez." #~ msgstr "Kullanıcının uyumlu bir aygıtı olmadığında Kimlik Doğrulayıcısı'nı yapılandırmak için kullanılan Aşama. Bu yapılandırma Stage geçtikten sonra kullanıcıya yeniden istenmez."
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4465,6 +4469,10 @@ msgstr "Aşamalar"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "Aşamalar, bir Akış'ın kullanıcının yönlendirildiği tek adımlardır. Bir aşama yalnızca bir akış içinden yürütülebilir." msgstr "Aşamalar, bir Akış'ın kullanıcının yönlendirildiği tek adımlardır. Bir aşama yalnızca bir akış içinden yürütülebilir."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "Eyalet" msgstr "Eyalet"
@ -5930,6 +5938,10 @@ msgstr "Etkinleştirildiğinde, davetiye kullanımdan sonra silinir."
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "Etkinleştirildiğinde, kullanıcı alanları muhafazası ne olursa olsun eşleştirilir." msgstr "Etkinleştirildiğinde, kullanıcı alanları muhafazası ne olursa olsun eşleştirilir."
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "Seçildiğinde, ayrı bir sayfa yerine aynı sayfada bir parola alanı gösterilir. Bu, kullanıcı adı numaralandırma saldırılarını engeller." msgstr "Seçildiğinde, ayrı bir sayfa yerine aynı sayfada bir parola alanı gösterilir. Bu, kullanıcı adı numaralandırma saldırılarını engeller."

View File

@ -948,8 +948,12 @@ msgid "Configuration flow"
msgstr "配置流程" msgstr "配置流程"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "配置阶段" #~ msgstr "配置阶段"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "配置 WebAuthn" #~ msgstr "配置 WebAuthn"
@ -4401,8 +4405,8 @@ msgid "Stage type"
msgstr "阶段类型" msgstr "阶段类型"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Stage 用于在用户没有任何兼容设备时配置身份验证器。此配置 Stage 通过后,不会再次提示用户。" #~ msgstr "Stage 用于在用户没有任何兼容设备时配置身份验证器。此配置 Stage 通过后,不会再次提示用户。"
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4461,6 +4465,10 @@ msgstr "阶段"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "阶段是引导用户完成的流程的单个步骤。阶段只能在流程内部执行。" msgstr "阶段是引导用户完成的流程的单个步骤。阶段只能在流程内部执行。"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "状态" msgstr "状态"
@ -5926,6 +5934,10 @@ msgstr "启用后,邀请将在使用后被删除。"
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "启用后,无论用户字段大小写如何,都将匹配用户字段。" msgstr "启用后,无论用户字段大小写如何,都将匹配用户字段。"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。" msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。"

View File

@ -948,8 +948,12 @@ msgid "Configuration flow"
msgstr "配置流程" msgstr "配置流程"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "配置阶段" #~ msgstr "配置阶段"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "配置 WebAuthn" #~ msgstr "配置 WebAuthn"
@ -4401,8 +4405,8 @@ msgid "Stage type"
msgstr "阶段类型" msgstr "阶段类型"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Stage 用于在用户没有任何兼容设备时配置身份验证器。此配置 Stage 通过后,不会再次提示用户。" #~ msgstr "Stage 用于在用户没有任何兼容设备时配置身份验证器。此配置 Stage 通过后,不会再次提示用户。"
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4461,6 +4465,10 @@ msgstr "阶段"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "阶段是引导用户完成的流程的单个步骤。阶段只能在流程内部执行。" msgstr "阶段是引导用户完成的流程的单个步骤。阶段只能在流程内部执行。"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "州" msgstr "州"
@ -5926,6 +5934,10 @@ msgstr "启用后,邀请将在使用后被删除。"
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "启用后,无论用户字段大小写如何,都将匹配用户字段。" msgstr "启用后,无论用户字段大小写如何,都将匹配用户字段。"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。" msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。"

View File

@ -948,8 +948,12 @@ msgid "Configuration flow"
msgstr "配置流程" msgstr "配置流程"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage" #~ msgid "Configuration stage"
msgstr "配置阶段" #~ msgstr "配置阶段"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stages"
msgstr ""
#~ msgid "Configure WebAuthn" #~ msgid "Configure WebAuthn"
#~ msgstr "配置 WebAuthn" #~ msgstr "配置 WebAuthn"
@ -4401,8 +4405,8 @@ msgid "Stage type"
msgstr "阶段类型" msgstr "阶段类型"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again." #~ msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr "Stage 用于在用户没有任何兼容设备时配置身份验证器。此配置 Stage 通过后,不会再次提示用户。" #~ msgstr "Stage 用于在用户没有任何兼容设备时配置身份验证器。此配置 Stage 通过后,不会再次提示用户。"
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts #: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)." msgid "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator)."
@ -4461,6 +4465,10 @@ msgstr "阶段"
msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow." msgid "Stages are single steps of a Flow that a user is guided through. A stage can only be executed from within a flow."
msgstr "阶段是引导用户完成的流程的单个步骤。阶段只能在流程内部执行。" msgstr "阶段是引导用户完成的流程的单个步骤。阶段只能在流程内部执行。"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts
msgid "State" msgid "State"
msgstr "州" msgstr "州"
@ -5926,6 +5934,10 @@ msgstr "启用后,邀请将在使用后被删除。"
msgid "When enabled, user fields are matched regardless of their casing." msgid "When enabled, user fields are matched regardless of their casing."
msgstr "启用后,无论用户字段大小写如何,都将匹配用户字段。" msgstr "启用后,无论用户字段大小写如何,都将匹配用户字段。"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "When multiple stages are selected, the user can choose which one they want to enroll."
msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks." msgid "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。" msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。"

View File

@ -25,14 +25,14 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
stageUuid: pk, stageUuid: pk,
}) })
.then((stage) => { .then((stage) => {
this.showConfigurationStage = this.showConfigurationStages =
stage.notConfiguredAction === NotConfiguredActionEnum.Configure; stage.notConfiguredAction === NotConfiguredActionEnum.Configure;
return stage; return stage;
}); });
} }
@property({ type: Boolean }) @property({ type: Boolean })
showConfigurationStage = true; showConfigurationStages = true;
getSuccessMessage(): string { getSuccessMessage(): string {
if (this.instance) { if (this.instance) {
@ -136,9 +136,9 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
target.selectedOptions[0].value === target.selectedOptions[0].value ===
NotConfiguredActionEnum.Configure NotConfiguredActionEnum.Configure
) { ) {
this.showConfigurationStage = true; this.showConfigurationStages = true;
} else { } else {
this.showConfigurationStage = false; this.showConfigurationStages = false;
} }
}} }}
> >
@ -165,21 +165,13 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
</option> </option>
</select> </select>
</ak-form-element-horizontal> </ak-form-element-horizontal>
${this.showConfigurationStage ${this.showConfigurationStages
? html` ? html`
<ak-form-element-horizontal <ak-form-element-horizontal
label=${t`Configuration stage`} label=${t`Configuration stages`}
?required=${true} name="configurationStages"
name="configurationStage"
> >
<select class="pf-c-form-control"> <select class="pf-c-form-control" multiple>
<option
value=""
?selected=${this.instance?.configurationStage ===
undefined}
>
---------
</option>
${until( ${until(
new StagesApi(DEFAULT_CONFIG) new StagesApi(DEFAULT_CONFIG)
.stagesAllList({ .stagesAllList({
@ -187,9 +179,11 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
}) })
.then((stages) => { .then((stages) => {
return stages.results.map((stage) => { return stages.results.map((stage) => {
const selected = const selected = Array.from(
this.instance?.configurationStage === this.instance?.configurationStages || [],
stage.pk; ).some((su) => {
return su == stage.pk;
});
return html`<option return html`<option
value=${ifDefined(stage.pk)} value=${ifDefined(stage.pk)}
?selected=${selected} ?selected=${selected}
@ -202,7 +196,10 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
)} )}
</select> </select>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${t`Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.`} ${t`Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.`}
</p>
<p class="pf-c-form__helper-text">
${t`When multiple stages are selected, the user can choose which one they want to enroll.`}
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
` `

View File

@ -153,7 +153,7 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
?required=${true} ?required=${true}
name="sources" name="sources"
> >
<select name="users" class="pf-c-form-control" multiple> <select class="pf-c-form-control" multiple>
${until( ${until(
new SourcesApi(DEFAULT_CONFIG) new SourcesApi(DEFAULT_CONFIG)
.sourcesAllList({}) .sourcesAllList({})