stages/authenticator_webauthn: make user_verification configurable
closes #1921 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
aa6b595545
commit
4e6714fffe
|
@ -18,7 +18,7 @@ class AuthenticateWebAuthnStageSerializer(StageSerializer):
|
|||
class Meta:
|
||||
|
||||
model = AuthenticateWebAuthnStage
|
||||
fields = StageSerializer.Meta.fields + ["configure_flow"]
|
||||
fields = StageSerializer.Meta.fields + ["configure_flow", "user_verification"]
|
||||
|
||||
|
||||
class AuthenticateWebAuthnStageViewSet(UsedByMixin, ModelViewSet):
|
||||
|
|
|
@ -9,15 +9,36 @@ from django.views import View
|
|||
from django_otp.models import Device
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
from webauthn.helpers.base64url_to_bytes import base64url_to_bytes
|
||||
from webauthn.helpers.structs import PublicKeyCredentialDescriptor
|
||||
from webauthn.helpers.structs import PublicKeyCredentialDescriptor, UserVerificationRequirement
|
||||
|
||||
from authentik.core.types import UserSettingSerializer
|
||||
from authentik.flows.models import ConfigurableStage, Stage
|
||||
|
||||
|
||||
class UserVerification(models.TextChoices):
|
||||
"""The degree to which the Relying Party wishes to verify a user's identity.
|
||||
|
||||
Members:
|
||||
`REQUIRED`: User verification must occur
|
||||
`PREFERRED`: User verification would be great, but if not that's okay too
|
||||
`DISCOURAGED`: User verification should not occur, but it's okay if it does
|
||||
|
||||
https://www.w3.org/TR/webauthn-2/#enumdef-userverificationrequirement
|
||||
"""
|
||||
|
||||
REQUIRED = UserVerificationRequirement.REQUIRED
|
||||
PREFERRED = UserVerificationRequirement.PREFERRED
|
||||
DISCOURAGED = UserVerificationRequirement.DISCOURAGED
|
||||
|
||||
|
||||
class AuthenticateWebAuthnStage(ConfigurableStage, Stage):
|
||||
"""WebAuthn stage"""
|
||||
|
||||
user_verification = models.TextField(
|
||||
choices=UserVerification.choices,
|
||||
default=UserVerification.PREFERRED,
|
||||
)
|
||||
|
||||
@property
|
||||
def serializer(self) -> BaseSerializer:
|
||||
from authentik.stages.authenticator_webauthn.api import AuthenticateWebAuthnStageSerializer
|
||||
|
|
|
@ -14,7 +14,6 @@ from webauthn.helpers.structs import (
|
|||
PublicKeyCredentialCreationOptions,
|
||||
RegistrationCredential,
|
||||
ResidentKeyRequirement,
|
||||
UserVerificationRequirement,
|
||||
)
|
||||
from webauthn.registration.verify_registration_response import VerifiedRegistration
|
||||
|
||||
|
@ -27,7 +26,7 @@ from authentik.flows.challenge import (
|
|||
)
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||
from authentik.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage, WebAuthnDevice
|
||||
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
@ -83,7 +82,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
# clear session variables prior to starting a new registration
|
||||
self.request.session.pop("challenge", None)
|
||||
|
||||
stage: AuthenticateWebAuthnStage = self.executor.current_stage
|
||||
user = self.get_pending_user()
|
||||
|
||||
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
|
||||
|
@ -94,7 +93,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||
user_display_name=user.name,
|
||||
authenticator_selection=AuthenticatorSelectionCriteria(
|
||||
resident_key=ResidentKeyRequirement.PREFERRED,
|
||||
user_verification=UserVerificationRequirement.PREFERRED,
|
||||
user_verification=str(stage.user_verification),
|
||||
),
|
||||
)
|
||||
registration_options.user.id = user.uid
|
||||
|
|
20
schema.yml
20
schema.yml
|
@ -15395,6 +15395,14 @@ paths:
|
|||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- in: query
|
||||
name: user_verification
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- discouraged
|
||||
- preferred
|
||||
- required
|
||||
tags:
|
||||
- stages
|
||||
security:
|
||||
|
@ -19240,6 +19248,8 @@ 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.
|
||||
user_verification:
|
||||
$ref: '#/components/schemas/UserVerificationEnum'
|
||||
required:
|
||||
- component
|
||||
- meta_model_name
|
||||
|
@ -19264,6 +19274,8 @@ 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.
|
||||
user_verification:
|
||||
$ref: '#/components/schemas/UserVerificationEnum'
|
||||
required:
|
||||
- name
|
||||
AuthenticatedSession:
|
||||
|
@ -26611,6 +26623,8 @@ 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.
|
||||
user_verification:
|
||||
$ref: '#/components/schemas/UserVerificationEnum'
|
||||
PatchedAuthenticatorDuoStageRequest:
|
||||
type: object
|
||||
description: AuthenticatorDuoStage Serializer
|
||||
|
@ -31235,6 +31249,12 @@ components:
|
|||
- pk
|
||||
- source
|
||||
- user
|
||||
UserVerificationEnum:
|
||||
enum:
|
||||
- required
|
||||
- preferred
|
||||
- discouraged
|
||||
type: string
|
||||
UserWriteStage:
|
||||
type: object
|
||||
description: UserWriteStage Serializer
|
||||
|
|
|
@ -4325,6 +4325,7 @@ msgstr "Stage(s)"
|
|||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||
#: src/pages/stages/email/EmailStageForm.ts
|
||||
|
@ -5510,6 +5511,22 @@ msgstr "User password writeback"
|
|||
msgid "User status"
|
||||
msgstr "User status"
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification"
|
||||
msgstr "User verification"
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification is preferred if available, but not required."
|
||||
msgstr "User verification is preferred if available, but not required."
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification must occur."
|
||||
msgstr "User verification must occur."
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification should not occur."
|
||||
msgstr "User verification should not occur."
|
||||
|
||||
#: src/pages/events/utils.ts
|
||||
msgid "User was written to"
|
||||
msgstr "User was written to"
|
||||
|
|
|
@ -4285,6 +4285,7 @@ msgstr "Étape(s)"
|
|||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||
#: src/pages/stages/email/EmailStageForm.ts
|
||||
|
@ -5448,6 +5449,22 @@ msgstr "Réécriture du mot de passe utilisateur"
|
|||
msgid "User status"
|
||||
msgstr "Statut utilisateur"
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification is preferred if available, but not required."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification must occur."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification should not occur."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/events/utils.ts
|
||||
msgid "User was written to"
|
||||
msgstr "L'utilisateur a été écrit vers "
|
||||
|
|
|
@ -4315,6 +4315,7 @@ msgstr ""
|
|||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||
#: src/pages/stages/email/EmailStageForm.ts
|
||||
|
@ -5490,6 +5491,22 @@ msgstr ""
|
|||
msgid "User status"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification is preferred if available, but not required."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification must occur."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||
msgid "User verification should not occur."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/events/utils.ts
|
||||
msgid "User was written to"
|
||||
msgstr ""
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { UserVerificationEnum } from "@goauthentik/api/dist/models/UserVerificationEnum";
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
import { TemplateResult, html } from "lit";
|
||||
|
@ -52,6 +54,40 @@ export class AuthenticateWebAuthnStageForm extends ModelForm<AuthenticateWebAuth
|
|||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-group .expanded=${true}>
|
||||
<span slot="header"> ${t`Stage-specific settings`} </span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${t`User verification`}
|
||||
?required=${true}
|
||||
name="userVerification"
|
||||
>
|
||||
<select name="users" class="pf-c-form-control">
|
||||
<option
|
||||
value="${UserVerificationEnum.Required}"
|
||||
?selected=${this.instance?.userVerification ===
|
||||
UserVerificationEnum.Required}
|
||||
>
|
||||
${t`User verification must occur.`}
|
||||
</option>
|
||||
<option
|
||||
value="${UserVerificationEnum.Preferred}"
|
||||
?selected=${this.instance?.userVerification ===
|
||||
UserVerificationEnum.Preferred}
|
||||
>
|
||||
${t`User verification is preferred if available, but not required.`}
|
||||
</option>
|
||||
<option
|
||||
value="${UserVerificationEnum.Discouraged}"
|
||||
?selected=${this.instance?.userVerification ===
|
||||
UserVerificationEnum.Discouraged}
|
||||
>
|
||||
${t`User verification should not occur.`}
|
||||
</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue