stages/authentiactor_validate: improve error handling for duo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
1f90359310
commit
0248755cda
|
@ -1,10 +1,12 @@
|
||||||
"""Validation stage challenge checking"""
|
"""Validation stage challenge checking"""
|
||||||
from json import dumps, loads
|
from json import dumps, loads
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.http.response import Http404
|
from django.http.response import Http404
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.utils.translation import gettext as __
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_otp import match_token
|
from django_otp import match_token
|
||||||
from django_otp.models import Device
|
from django_otp.models import Device
|
||||||
|
@ -17,9 +19,11 @@ from webauthn.helpers.exceptions import InvalidAuthenticationResponse
|
||||||
from webauthn.helpers.structs import AuthenticationCredential
|
from webauthn.helpers.structs import AuthenticationCredential
|
||||||
|
|
||||||
from authentik.core.api.utils import PassiveSerializer
|
from authentik.core.api.utils import PassiveSerializer
|
||||||
from authentik.core.models import User
|
from authentik.core.models import Application, User
|
||||||
from authentik.core.signals import login_failed
|
from authentik.core.signals import login_failed
|
||||||
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.flows.stage import StageView
|
from authentik.flows.stage import StageView
|
||||||
|
from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE
|
||||||
from authentik.lib.utils.http import get_client_ip
|
from authentik.lib.utils.http import get_client_ip
|
||||||
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
||||||
from authentik.stages.authenticator_sms.models import SMSDevice
|
from authentik.stages.authenticator_sms.models import SMSDevice
|
||||||
|
@ -27,6 +31,7 @@ from authentik.stages.authenticator_validate.models import DeviceClasses
|
||||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||||
from authentik.stages.authenticator_webauthn.stage import SESSION_KEY_WEBAUTHN_CHALLENGE
|
from authentik.stages.authenticator_webauthn.stage import SESSION_KEY_WEBAUTHN_CHALLENGE
|
||||||
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
|
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
|
||||||
|
from authentik.stages.consent.stage import PLAN_CONTEXT_CONSENT_TITLE
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
@ -155,13 +160,32 @@ def validate_challenge_duo(device_pk: int, stage_view: StageView, user: User) ->
|
||||||
LOGGER.warning("device mismatch")
|
LOGGER.warning("device mismatch")
|
||||||
raise Http404
|
raise Http404
|
||||||
stage: AuthenticatorDuoStage = device.stage
|
stage: AuthenticatorDuoStage = device.stage
|
||||||
|
|
||||||
|
# Get additional context for push
|
||||||
|
pushinfo = {
|
||||||
|
__("Domain"): stage_view.request.get_host(),
|
||||||
|
}
|
||||||
|
if PLAN_CONTEXT_CONSENT_TITLE in stage_view.executor.plan.context:
|
||||||
|
pushinfo[__("Title")] = stage_view.executor.plan.context[PLAN_CONTEXT_CONSENT_TITLE]
|
||||||
|
if SESSION_KEY_APPLICATION_PRE in stage_view.request.session:
|
||||||
|
pushinfo[__("Application")] = stage_view.request.session.get(
|
||||||
|
SESSION_KEY_APPLICATION_PRE, Application()
|
||||||
|
).name
|
||||||
|
|
||||||
|
try:
|
||||||
response = stage.client.auth(
|
response = stage.client.auth(
|
||||||
"auto",
|
"auto",
|
||||||
user_id=device.duo_user_id,
|
user_id=device.duo_user_id,
|
||||||
ipaddr=get_client_ip(stage_view.request),
|
ipaddr=get_client_ip(stage_view.request),
|
||||||
type="authentik Login request",
|
type=__(
|
||||||
|
"%(brand_name)s Login request"
|
||||||
|
% {
|
||||||
|
"brand_name": stage_view.request.tenant.branding_title,
|
||||||
|
}
|
||||||
|
),
|
||||||
display_username=user.username,
|
display_username=user.username,
|
||||||
device="auto",
|
device="auto",
|
||||||
|
pushinfo=urlencode(pushinfo),
|
||||||
)
|
)
|
||||||
# {'result': 'allow', 'status': 'allow', 'status_msg': 'Success. Logging you in...'}
|
# {'result': 'allow', 'status': 'allow', 'status_msg': 'Success. Logging you in...'}
|
||||||
if response["result"] == "deny":
|
if response["result"] == "deny":
|
||||||
|
@ -175,3 +199,10 @@ def validate_challenge_duo(device_pk: int, stage_view: StageView, user: User) ->
|
||||||
raise ValidationError("Duo denied access")
|
raise ValidationError("Duo denied access")
|
||||||
device.save()
|
device.save()
|
||||||
return device
|
return device
|
||||||
|
except RuntimeError as exc:
|
||||||
|
Event.new(
|
||||||
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
message=f"Failed to DUO authenticate user: {str(exc)}",
|
||||||
|
user=user,
|
||||||
|
).from_http(stage_view.request, user)
|
||||||
|
raise ValidationError("Duo denied access")
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-07-02 15:10+0000\n"
|
"POT-Creation-Date: 2022-07-28 19:11+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -39,11 +39,11 @@ msgstr ""
|
||||||
msgid "Create a SAML Provider by importing its Metadata."
|
msgid "Create a SAML Provider by importing its Metadata."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/api/users.py:90
|
#: authentik/core/api/users.py:93
|
||||||
msgid "No leading or trailing slashes allowed."
|
msgid "No leading or trailing slashes allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/api/users.py:93
|
#: authentik/core/api/users.py:96
|
||||||
msgid "No empty segments in user path allowed."
|
msgid "No empty segments in user path allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -59,105 +59,105 @@ msgstr ""
|
||||||
msgid "User's display name."
|
msgid "User's display name."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:237 authentik/providers/oauth2/models.py:318
|
#: authentik/core/models.py:239 authentik/providers/oauth2/models.py:321
|
||||||
msgid "User"
|
msgid "User"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:238
|
#: authentik/core/models.py:240
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:249
|
#: authentik/core/models.py:251
|
||||||
msgid "Flow used when authorizing this provider."
|
msgid "Flow used when authorizing this provider."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:282
|
#: authentik/core/models.py:284
|
||||||
msgid "Application's display Name."
|
msgid "Application's display Name."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:283
|
#: authentik/core/models.py:285
|
||||||
msgid "Internal application name, used in URLs."
|
msgid "Internal application name, used in URLs."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:295
|
#: authentik/core/models.py:297
|
||||||
msgid "Open launch URL in a new browser tab or window."
|
msgid "Open launch URL in a new browser tab or window."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:354
|
#: authentik/core/models.py:356
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:355
|
#: authentik/core/models.py:357
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:361
|
#: authentik/core/models.py:363
|
||||||
msgid "Use the source-specific identifier"
|
msgid "Use the source-specific identifier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:369
|
#: authentik/core/models.py:371
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use the user's email address, but deny enrollment when the email address "
|
"Use the user's email address, but deny enrollment when the email address "
|
||||||
"already exists."
|
"already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:378
|
#: authentik/core/models.py:380
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use the user's username, but deny enrollment when the username already "
|
"Use the user's username, but deny enrollment when the username already "
|
||||||
"exists."
|
"exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:385
|
#: authentik/core/models.py:387
|
||||||
msgid "Source's display Name."
|
msgid "Source's display Name."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:386
|
#: authentik/core/models.py:388
|
||||||
msgid "Internal source name, used in URLs."
|
msgid "Internal source name, used in URLs."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:399
|
#: authentik/core/models.py:401
|
||||||
msgid "Flow to use when authenticating existing users."
|
msgid "Flow to use when authenticating existing users."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:408
|
#: authentik/core/models.py:410
|
||||||
msgid "Flow to use when enrolling new users."
|
msgid "Flow to use when enrolling new users."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:557
|
#: authentik/core/models.py:560
|
||||||
msgid "Token"
|
msgid "Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:558
|
#: authentik/core/models.py:561
|
||||||
msgid "Tokens"
|
msgid "Tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:601
|
#: authentik/core/models.py:604
|
||||||
msgid "Property Mapping"
|
msgid "Property Mapping"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:602
|
#: authentik/core/models.py:605
|
||||||
msgid "Property Mappings"
|
msgid "Property Mappings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:638
|
#: authentik/core/models.py:641
|
||||||
msgid "Authenticated Session"
|
msgid "Authenticated Session"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py:639
|
#: authentik/core/models.py:642
|
||||||
msgid "Authenticated Sessions"
|
msgid "Authenticated Sessions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/sources/flow_manager.py:177
|
#: authentik/core/sources/flow_manager.py:176
|
||||||
msgid "source"
|
msgid "source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/sources/flow_manager.py:245
|
#: authentik/core/sources/flow_manager.py:243
|
||||||
#: authentik/core/sources/flow_manager.py:283
|
#: authentik/core/sources/flow_manager.py:281
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Successfully authenticated with %(source)s!"
|
msgid "Successfully authenticated with %(source)s!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/sources/flow_manager.py:264
|
#: authentik/core/sources/flow_manager.py:262
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Successfully linked %(source)s!"
|
msgid "Successfully linked %(source)s!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -168,8 +168,8 @@ msgstr ""
|
||||||
|
|
||||||
#: authentik/core/templates/if/admin.html:18
|
#: authentik/core/templates/if/admin.html:18
|
||||||
#: authentik/core/templates/if/admin.html:24
|
#: authentik/core/templates/if/admin.html:24
|
||||||
#: authentik/core/templates/if/flow.html:35
|
#: authentik/core/templates/if/flow.html:37
|
||||||
#: authentik/core/templates/if/flow.html:41
|
#: authentik/core/templates/if/flow.html:43
|
||||||
#: authentik/core/templates/if/user.html:18
|
#: authentik/core/templates/if/user.html:18
|
||||||
#: authentik/core/templates/if/user.html:24
|
#: authentik/core/templates/if/user.html:24
|
||||||
msgid "Loading..."
|
msgid "Loading..."
|
||||||
|
@ -355,6 +355,10 @@ msgstr ""
|
||||||
msgid "Flow not applicable to current user/request: %(messages)s"
|
msgid "Flow not applicable to current user/request: %(messages)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/flows/exceptions.py:17
|
||||||
|
msgid "Flow does not apply to current user (denied by policy)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/flows/models.py:117
|
#: authentik/flows/models.py:117
|
||||||
msgid "Visible in the URL."
|
msgid "Visible in the URL."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -742,98 +746,104 @@ msgstr ""
|
||||||
msgid "Client Type"
|
msgid "Client Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:151
|
#: authentik/providers/oauth2/models.py:147
|
||||||
|
msgid ""
|
||||||
|
"Confidential clients are capable of maintaining the confidentiality of their "
|
||||||
|
"credentials. Public clients are incapable"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/providers/oauth2/models.py:154
|
||||||
msgid "Client ID"
|
msgid "Client ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:157
|
#: authentik/providers/oauth2/models.py:160
|
||||||
msgid "Client Secret"
|
msgid "Client Secret"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:163
|
#: authentik/providers/oauth2/models.py:166
|
||||||
msgid "Redirect URIs"
|
msgid "Redirect URIs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:164
|
#: authentik/providers/oauth2/models.py:167
|
||||||
msgid "Enter each URI on a new line."
|
msgid "Enter each URI on a new line."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:169
|
#: authentik/providers/oauth2/models.py:172
|
||||||
msgid "Include claims in id_token"
|
msgid "Include claims in id_token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:217
|
#: authentik/providers/oauth2/models.py:220
|
||||||
msgid "Signing Key"
|
msgid "Signing Key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:221
|
#: authentik/providers/oauth2/models.py:224
|
||||||
msgid ""
|
msgid ""
|
||||||
"Key used to sign the tokens. Only required when JWT Algorithm is set to "
|
"Key used to sign the tokens. Only required when JWT Algorithm is set to "
|
||||||
"RS256."
|
"RS256."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:228
|
#: authentik/providers/oauth2/models.py:231
|
||||||
msgid ""
|
msgid ""
|
||||||
"Any JWT signed by the JWK of the selected source can be used to authenticate."
|
"Any JWT signed by the JWK of the selected source can be used to authenticate."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:310
|
#: authentik/providers/oauth2/models.py:313
|
||||||
msgid "OAuth2/OpenID Provider"
|
msgid "OAuth2/OpenID Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:311
|
#: authentik/providers/oauth2/models.py:314
|
||||||
msgid "OAuth2/OpenID Providers"
|
msgid "OAuth2/OpenID Providers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:319
|
#: authentik/providers/oauth2/models.py:322
|
||||||
msgid "Scopes"
|
msgid "Scopes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:338
|
#: authentik/providers/oauth2/models.py:341
|
||||||
msgid "Code"
|
msgid "Code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:339
|
#: authentik/providers/oauth2/models.py:342
|
||||||
msgid "Nonce"
|
msgid "Nonce"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:340
|
#: authentik/providers/oauth2/models.py:343
|
||||||
msgid "Is Authentication?"
|
msgid "Is Authentication?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:341
|
#: authentik/providers/oauth2/models.py:344
|
||||||
msgid "Code Challenge"
|
msgid "Code Challenge"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:343
|
#: authentik/providers/oauth2/models.py:346
|
||||||
msgid "Code Challenge Method"
|
msgid "Code Challenge Method"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:357
|
#: authentik/providers/oauth2/models.py:360
|
||||||
msgid "Authorization Code"
|
msgid "Authorization Code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:358
|
#: authentik/providers/oauth2/models.py:361
|
||||||
msgid "Authorization Codes"
|
msgid "Authorization Codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:401
|
#: authentik/providers/oauth2/models.py:404
|
||||||
msgid "Access Token"
|
msgid "Access Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:402
|
#: authentik/providers/oauth2/models.py:405
|
||||||
msgid "Refresh Token"
|
msgid "Refresh Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:403
|
#: authentik/providers/oauth2/models.py:406
|
||||||
msgid "ID Token"
|
msgid "ID Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:406
|
#: authentik/providers/oauth2/models.py:409
|
||||||
msgid "OAuth2 Token"
|
msgid "OAuth2 Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/providers/oauth2/models.py:407
|
#: authentik/providers/oauth2/models.py:410
|
||||||
msgid "OAuth2 Tokens"
|
msgid "OAuth2 Tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1385,7 +1395,7 @@ msgstr ""
|
||||||
msgid "TOTP Authenticator Setup Stages"
|
msgid "TOTP Authenticator Setup Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/challenge.py:110
|
#: authentik/stages/authenticator_validate/challenge.py:115
|
||||||
msgid "Invalid Token"
|
msgid "Invalid Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1687,51 +1697,57 @@ msgstr ""
|
||||||
msgid "Invalid password"
|
msgid "Invalid password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:38
|
#: authentik/stages/prompt/models.py:40
|
||||||
msgid "Text: Simple Text input"
|
msgid "Text: Simple Text input"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:41
|
#: authentik/stages/prompt/models.py:43
|
||||||
msgid "Text (read-only): Simple Text input, but cannot be edited."
|
msgid "Text (read-only): Simple Text input, but cannot be edited."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:48
|
#: authentik/stages/prompt/models.py:50
|
||||||
msgid "Email: Text field with Email type."
|
msgid "Email: Text field with Email type."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:64
|
#: authentik/stages/prompt/models.py:69
|
||||||
|
msgid ""
|
||||||
|
"File: File upload for arbitrary files. File content will be available in "
|
||||||
|
"flow context as data-URI"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/prompt/models.py:74
|
||||||
msgid "Separator: Static Separator Line"
|
msgid "Separator: Static Separator Line"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:65
|
#: authentik/stages/prompt/models.py:75
|
||||||
msgid "Hidden: Hidden field, can be used to insert data into form."
|
msgid "Hidden: Hidden field, can be used to insert data into form."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:66
|
#: authentik/stages/prompt/models.py:76
|
||||||
msgid "Static: Static value, displayed as-is."
|
msgid "Static: Static value, displayed as-is."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:68
|
#: authentik/stages/prompt/models.py:78
|
||||||
msgid "authentik: Selection of locales authentik supports"
|
msgid "authentik: Selection of locales authentik supports"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:77
|
#: authentik/stages/prompt/models.py:101
|
||||||
msgid "Name of the form field, also used to store the value"
|
msgid "Name of the form field, also used to store the value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:170
|
#: authentik/stages/prompt/models.py:198
|
||||||
msgid "Prompt"
|
msgid "Prompt"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:171
|
#: authentik/stages/prompt/models.py:199
|
||||||
msgid "Prompts"
|
msgid "Prompts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:199
|
#: authentik/stages/prompt/models.py:227
|
||||||
msgid "Prompt Stage"
|
msgid "Prompt Stage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/prompt/models.py:200
|
#: authentik/stages/prompt/models.py:228
|
||||||
msgid "Prompt Stages"
|
msgid "Prompt Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1807,10 +1823,10 @@ msgid ""
|
||||||
"and `ba.b`"
|
"and `ba.b`"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/tenants/models.py:75
|
#: authentik/tenants/models.py:80
|
||||||
msgid "Tenant"
|
msgid "Tenant"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/tenants/models.py:76
|
#: authentik/tenants/models.py:81
|
||||||
msgid "Tenants"
|
msgid "Tenants"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -55,6 +55,7 @@ export class AuthenticatorValidateStage
|
||||||
set selectedDeviceChallenge(value: DeviceChallenge | undefined) {
|
set selectedDeviceChallenge(value: DeviceChallenge | undefined) {
|
||||||
this._selectedDeviceChallenge = value;
|
this._selectedDeviceChallenge = value;
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
if (value === this._selectedDeviceChallenge) return;
|
||||||
// We don't use this.submit here, as we don't want to advance the flow.
|
// We don't use this.submit here, as we don't want to advance the flow.
|
||||||
// We just want to notify the backend which challenge has been selected.
|
// We just want to notify the backend which challenge has been selected.
|
||||||
new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
|
new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
|
||||||
|
|
|
@ -50,6 +50,7 @@ export class AuthenticatorValidateStageWebDuo extends BaseStage<
|
||||||
if (!this.challenge) {
|
if (!this.challenge) {
|
||||||
return html`<ak-empty-state ?loading="${true}" header=${t`Loading`}> </ak-empty-state>`;
|
return html`<ak-empty-state ?loading="${true}" header=${t`Loading`}> </ak-empty-state>`;
|
||||||
}
|
}
|
||||||
|
const errors = this.challenge.responseErrors?.duo || [];
|
||||||
return html`<div class="pf-c-login__main-body">
|
return html`<div class="pf-c-login__main-body">
|
||||||
<form
|
<form
|
||||||
class="pf-c-form"
|
class="pf-c-form"
|
||||||
|
@ -69,6 +70,10 @@ export class AuthenticatorValidateStageWebDuo extends BaseStage<
|
||||||
</div>
|
</div>
|
||||||
</ak-form-static>
|
</ak-form-static>
|
||||||
|
|
||||||
|
${errors.map((err) => {
|
||||||
|
return html`<p>${err.string}</p>`;
|
||||||
|
})}
|
||||||
|
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||||
${t`Continue`}
|
${t`Continue`}
|
||||||
|
|
|
@ -2259,6 +2259,10 @@ msgstr "Felder"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "Felder, mit denen sich ein Benutzer identifizieren kann. Wenn keine Felder ausgewählt sind, kann der Benutzer nur Quellen verwenden."
|
msgstr "Felder, mit denen sich ein Benutzer identifizieren kann. Wenn keine Felder ausgewählt sind, kann der Benutzer nur Quellen verwenden."
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2295,6 +2295,10 @@ msgstr "Fields"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgstr "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr "File"
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr "Finish"
|
msgstr "Finish"
|
||||||
|
|
|
@ -2250,6 +2250,10 @@ msgstr "Campos"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "Campos con los que un usuario puede identificarse. Si no se seleccionan campos, el usuario solo podrá usar fuentes."
|
msgstr "Campos con los que un usuario puede identificarse. Si no se seleccionan campos, el usuario solo podrá usar fuentes."
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2275,6 +2275,10 @@ msgstr "Champs"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "Champs avec lesquels un utilisateur peut s'identifier. Si aucun champ n'est sélectionné, l'utilisateur ne pourra utiliser que des sources."
|
msgstr "Champs avec lesquels un utilisateur peut s'identifier. Si aucun champ n'est sélectionné, l'utilisateur ne pourra utiliser que des sources."
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2247,6 +2247,10 @@ msgstr "Pola"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "Pola, z którymi użytkownik może się identyfikować. Jeśli żadne pola nie zostaną wybrane, użytkownik będzie mógł korzystać tylko ze źródeł."
|
msgstr "Pola, z którymi użytkownik może się identyfikować. Jeśli żadne pola nie zostaną wybrane, użytkownik będzie mógł korzystać tylko ze źródeł."
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2281,6 +2281,10 @@ msgstr ""
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2250,6 +2250,10 @@ msgstr "Alanlar"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "Kullanıcının kendilerini tanımlayabileceği alanlar. Herhangi bir alan seçilmezse, kullanıcı yalnızca kaynakları kullanabilir."
|
msgstr "Kullanıcının kendilerini tanımlayabileceği alanlar. Herhangi bir alan seçilmezse, kullanıcı yalnızca kaynakları kullanabilir."
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2238,6 +2238,10 @@ msgstr "字段"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "用户可以用来标识自己的字段。如果未选择任何字段,则用户将只能使用源。"
|
msgstr "用户可以用来标识自己的字段。如果未选择任何字段,则用户将只能使用源。"
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr "完成"
|
msgstr "完成"
|
||||||
|
|
|
@ -2241,6 +2241,10 @@ msgstr "字段"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "用户可以用来标识自己的字段。如果未选择任何字段,则用户将只能使用源。"
|
msgstr "用户可以用来标识自己的字段。如果未选择任何字段,则用户将只能使用源。"
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr "完成"
|
msgstr "完成"
|
||||||
|
|
|
@ -2241,6 +2241,10 @@ msgstr "字段"
|
||||||
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
msgid "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||||
msgstr "用户可以用来标识自己的字段。如果未选择任何字段,则用户将只能使用源。"
|
msgstr "用户可以用来标识自己的字段。如果未选择任何字段,则用户将只能使用源。"
|
||||||
|
|
||||||
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/elements/wizard/Wizard.ts
|
#: src/elements/wizard/Wizard.ts
|
||||||
msgid "Finish"
|
msgid "Finish"
|
||||||
msgstr "完成"
|
msgstr "完成"
|
||||||
|
|
Reference in New Issue