stages/authenticator_validate: show single button for multiple webauthn authenticators
tested with browser + yubikey 5 closes #1096 The order of allowCredentials doesn't seem to matter, chrome seems to always choose the internal authenticator first. Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
7d26ea1a9c
commit
4fc8e61f8c
|
@ -51,20 +51,29 @@ def get_webauthn_challenge(request: HttpRequest, device: WebAuthnDevice) -> dict
|
|||
# for the reasons outlined in the comment in webauthn_begin_activate.
|
||||
request.session["challenge"] = challenge.rstrip("=")
|
||||
|
||||
webauthn_user = WebAuthnUser(
|
||||
device.user.uid,
|
||||
device.user.username,
|
||||
device.user.name,
|
||||
device.user.avatar,
|
||||
device.credential_id,
|
||||
device.public_key,
|
||||
device.sign_count,
|
||||
device.rp_id,
|
||||
)
|
||||
assertion = {}
|
||||
|
||||
webauthn_assertion_options = WebAuthnAssertionOptions(webauthn_user, challenge)
|
||||
# We want all the user's WebAuthn devices and merge their challenges
|
||||
for device in WebAuthnDevice.objects.filter(user=device.user).order_by("name"):
|
||||
webauthn_user = WebAuthnUser(
|
||||
device.user.uid,
|
||||
device.user.username,
|
||||
device.user.name,
|
||||
device.user.avatar,
|
||||
device.credential_id,
|
||||
device.public_key,
|
||||
device.sign_count,
|
||||
device.rp_id,
|
||||
)
|
||||
webauthn_assertion_options = WebAuthnAssertionOptions(webauthn_user, challenge)
|
||||
if assertion == {}:
|
||||
assertion = webauthn_assertion_options.assertion_dict
|
||||
else:
|
||||
assertion["allowCredentials"] += webauthn_assertion_options.assertion_dict.get(
|
||||
"allowCredentials"
|
||||
)
|
||||
|
||||
return webauthn_assertion_options.assertion_dict
|
||||
return assertion
|
||||
|
||||
|
||||
def validate_challenge_code(code: str, request: HttpRequest, user: User) -> str:
|
||||
|
|
|
@ -20,8 +20,6 @@ from authentik.stages.authenticator_validate.models import AuthenticatorValidate
|
|||
|
||||
LOGGER = get_logger()
|
||||
|
||||
PER_DEVICE_CLASSES = [DeviceClasses.WEBAUTHN]
|
||||
|
||||
|
||||
class AuthenticatorValidationChallenge(WithUserInfoChallenge):
|
||||
"""Authenticator challenge"""
|
||||
|
@ -91,9 +89,9 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
|||
if device_class not in stage.device_classes:
|
||||
LOGGER.debug("device class not allowed", device_class=device_class)
|
||||
continue
|
||||
# Ensure only classes in PER_DEVICE_CLASSES are returned per device
|
||||
# otherwise only return a single challenge
|
||||
if device_class in seen_classes and device_class not in PER_DEVICE_CLASSES:
|
||||
# Ensure only one challenge per device class
|
||||
# WebAuthn does another device loop to find all webuahtn devices
|
||||
if device_class in seen_classes:
|
||||
continue
|
||||
if device_class not in seen_classes:
|
||||
seen_classes.append(device_class)
|
||||
|
|
|
@ -180,7 +180,7 @@ export class AuthenticatorValidateStage
|
|||
${this.selectedDeviceChallenge
|
||||
? ""
|
||||
: html`<p class="pf-c-login__main-header-desc">
|
||||
${t`Select an identification method.`}
|
||||
${t`Select an authentication method.`}
|
||||
</p>`}
|
||||
</header>
|
||||
${this.selectedDeviceChallenge
|
||||
|
|
|
@ -3370,6 +3370,10 @@ msgstr "Request token URL"
|
|||
msgid "Required"
|
||||
msgstr "Required"
|
||||
|
||||
#: src/flows/stages/prompt/PromptStage.ts
|
||||
msgid "Required."
|
||||
msgstr "Required."
|
||||
|
||||
#: src/pages/user-settings/UserSelfForm.ts
|
||||
#: src/pages/users/ServiceAccountForm.ts
|
||||
#: src/pages/users/UserForm.ts
|
||||
|
@ -3524,13 +3528,17 @@ msgstr "Select a provider that this application should use. Alternatively, creat
|
|||
msgid "Select all rows"
|
||||
msgstr "Select all rows"
|
||||
|
||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||
msgid "Select an authentication method."
|
||||
msgstr "Select an authentication method."
|
||||
|
||||
#: src/pages/stages/invitation/InvitationListLink.ts
|
||||
msgid "Select an enrollment flow"
|
||||
msgstr "Select an enrollment flow"
|
||||
|
||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||
msgid "Select an identification method."
|
||||
msgstr "Select an identification method."
|
||||
#:
|
||||
#~ msgid "Select an identification method."
|
||||
#~ msgstr "Select an identification method."
|
||||
|
||||
#: src/pages/users/GroupSelectModal.ts
|
||||
msgid "Select groups to add user to"
|
||||
|
@ -3757,9 +3765,13 @@ msgstr "Source(s)"
|
|||
msgid "Sources"
|
||||
msgstr "Sources"
|
||||
|
||||
#:
|
||||
#~ msgid "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
#~ msgstr "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
|
||||
#: src/pages/sources/SourcesListPage.ts
|
||||
msgid "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
msgstr "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||
msgstr "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||
|
||||
#: src/pages/flows/BoundStagesList.ts
|
||||
#: src/pages/flows/StageBindingForm.ts
|
||||
|
|
|
@ -3362,6 +3362,10 @@ msgstr ""
|
|||
msgid "Required"
|
||||
msgstr ""
|
||||
|
||||
#: src/flows/stages/prompt/PromptStage.ts
|
||||
msgid "Required."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/user-settings/UserSelfForm.ts
|
||||
#: src/pages/users/ServiceAccountForm.ts
|
||||
#: src/pages/users/UserForm.ts
|
||||
|
@ -3516,13 +3520,17 @@ msgstr ""
|
|||
msgid "Select all rows"
|
||||
msgstr ""
|
||||
|
||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||
msgid "Select an authentication method."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/invitation/InvitationListLink.ts
|
||||
msgid "Select an enrollment flow"
|
||||
msgstr ""
|
||||
|
||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||
msgid "Select an identification method."
|
||||
msgstr ""
|
||||
#:
|
||||
#~ msgid "Select an identification method."
|
||||
#~ msgstr ""
|
||||
|
||||
#: src/pages/users/GroupSelectModal.ts
|
||||
msgid "Select groups to add user to"
|
||||
|
@ -3749,8 +3757,12 @@ msgstr ""
|
|||
msgid "Sources"
|
||||
msgstr ""
|
||||
|
||||
#:
|
||||
#~ msgid "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
#~ msgstr ""
|
||||
|
||||
#: src/pages/sources/SourcesListPage.ts
|
||||
msgid "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/BoundStagesList.ts
|
||||
|
|
Reference in a new issue