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:
|
class Meta:
|
||||||
|
|
||||||
model = AuthenticateWebAuthnStage
|
model = AuthenticateWebAuthnStage
|
||||||
fields = StageSerializer.Meta.fields + ["configure_flow"]
|
fields = StageSerializer.Meta.fields + ["configure_flow", "user_verification"]
|
||||||
|
|
||||||
|
|
||||||
class AuthenticateWebAuthnStageViewSet(UsedByMixin, ModelViewSet):
|
class AuthenticateWebAuthnStageViewSet(UsedByMixin, ModelViewSet):
|
||||||
|
|
|
@ -9,15 +9,36 @@ from django.views import View
|
||||||
from django_otp.models import Device
|
from django_otp.models import Device
|
||||||
from rest_framework.serializers import BaseSerializer
|
from rest_framework.serializers import BaseSerializer
|
||||||
from webauthn.helpers.base64url_to_bytes import base64url_to_bytes
|
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.core.types import UserSettingSerializer
|
||||||
from authentik.flows.models import ConfigurableStage, Stage
|
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):
|
class AuthenticateWebAuthnStage(ConfigurableStage, Stage):
|
||||||
"""WebAuthn stage"""
|
"""WebAuthn stage"""
|
||||||
|
|
||||||
|
user_verification = models.TextField(
|
||||||
|
choices=UserVerification.choices,
|
||||||
|
default=UserVerification.PREFERRED,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> BaseSerializer:
|
def serializer(self) -> BaseSerializer:
|
||||||
from authentik.stages.authenticator_webauthn.api import AuthenticateWebAuthnStageSerializer
|
from authentik.stages.authenticator_webauthn.api import AuthenticateWebAuthnStageSerializer
|
||||||
|
|
|
@ -14,7 +14,6 @@ from webauthn.helpers.structs import (
|
||||||
PublicKeyCredentialCreationOptions,
|
PublicKeyCredentialCreationOptions,
|
||||||
RegistrationCredential,
|
RegistrationCredential,
|
||||||
ResidentKeyRequirement,
|
ResidentKeyRequirement,
|
||||||
UserVerificationRequirement,
|
|
||||||
)
|
)
|
||||||
from webauthn.registration.verify_registration_response import VerifiedRegistration
|
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.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import ChallengeStageView
|
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
|
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
@ -83,7 +82,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
||||||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||||
# clear session variables prior to starting a new registration
|
# clear session variables prior to starting a new registration
|
||||||
self.request.session.pop("challenge", None)
|
self.request.session.pop("challenge", None)
|
||||||
|
stage: AuthenticateWebAuthnStage = self.executor.current_stage
|
||||||
user = self.get_pending_user()
|
user = self.get_pending_user()
|
||||||
|
|
||||||
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
|
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
|
||||||
|
@ -94,7 +93,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
||||||
user_display_name=user.name,
|
user_display_name=user.name,
|
||||||
authenticator_selection=AuthenticatorSelectionCriteria(
|
authenticator_selection=AuthenticatorSelectionCriteria(
|
||||||
resident_key=ResidentKeyRequirement.PREFERRED,
|
resident_key=ResidentKeyRequirement.PREFERRED,
|
||||||
user_verification=UserVerificationRequirement.PREFERRED,
|
user_verification=str(stage.user_verification),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
registration_options.user.id = user.uid
|
registration_options.user.id = user.uid
|
||||||
|
|
20
schema.yml
20
schema.yml
|
@ -15395,6 +15395,14 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
- in: query
|
||||||
|
name: user_verification
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- discouraged
|
||||||
|
- preferred
|
||||||
|
- required
|
||||||
tags:
|
tags:
|
||||||
- stages
|
- stages
|
||||||
security:
|
security:
|
||||||
|
@ -19240,6 +19248,8 @@ components:
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Flow used by an authenticated user to configure this Stage.
|
description: Flow used by an authenticated user to configure this Stage.
|
||||||
If empty, user will not be able to configure this stage.
|
If empty, user will not be able to configure this stage.
|
||||||
|
user_verification:
|
||||||
|
$ref: '#/components/schemas/UserVerificationEnum'
|
||||||
required:
|
required:
|
||||||
- component
|
- component
|
||||||
- meta_model_name
|
- meta_model_name
|
||||||
|
@ -19264,6 +19274,8 @@ components:
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Flow used by an authenticated user to configure this Stage.
|
description: Flow used by an authenticated user to configure this Stage.
|
||||||
If empty, user will not be able to configure this stage.
|
If empty, user will not be able to configure this stage.
|
||||||
|
user_verification:
|
||||||
|
$ref: '#/components/schemas/UserVerificationEnum'
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
AuthenticatedSession:
|
AuthenticatedSession:
|
||||||
|
@ -26611,6 +26623,8 @@ components:
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Flow used by an authenticated user to configure this Stage.
|
description: Flow used by an authenticated user to configure this Stage.
|
||||||
If empty, user will not be able to configure this stage.
|
If empty, user will not be able to configure this stage.
|
||||||
|
user_verification:
|
||||||
|
$ref: '#/components/schemas/UserVerificationEnum'
|
||||||
PatchedAuthenticatorDuoStageRequest:
|
PatchedAuthenticatorDuoStageRequest:
|
||||||
type: object
|
type: object
|
||||||
description: AuthenticatorDuoStage Serializer
|
description: AuthenticatorDuoStage Serializer
|
||||||
|
@ -31235,6 +31249,12 @@ components:
|
||||||
- pk
|
- pk
|
||||||
- source
|
- source
|
||||||
- user
|
- user
|
||||||
|
UserVerificationEnum:
|
||||||
|
enum:
|
||||||
|
- required
|
||||||
|
- preferred
|
||||||
|
- discouraged
|
||||||
|
type: string
|
||||||
UserWriteStage:
|
UserWriteStage:
|
||||||
type: object
|
type: object
|
||||||
description: UserWriteStage Serializer
|
description: UserWriteStage Serializer
|
||||||
|
|
|
@ -4325,6 +4325,7 @@ msgstr "Stage(s)"
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||||
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
||||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
|
@ -5510,6 +5511,22 @@ msgstr "User password writeback"
|
||||||
msgid "User status"
|
msgid "User status"
|
||||||
msgstr "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
|
#: src/pages/events/utils.ts
|
||||||
msgid "User was written to"
|
msgid "User was written to"
|
||||||
msgstr "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_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||||
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
||||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
|
@ -5448,6 +5449,22 @@ msgstr "Réécriture du mot de passe utilisateur"
|
||||||
msgid "User status"
|
msgid "User status"
|
||||||
msgstr "Statut utilisateur"
|
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
|
#: src/pages/events/utils.ts
|
||||||
msgid "User was written to"
|
msgid "User was written to"
|
||||||
msgstr "L'utilisateur a été écrit vers "
|
msgstr "L'utilisateur a été écrit vers "
|
||||||
|
|
|
@ -4315,6 +4315,7 @@ msgstr ""
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_webauthn/AuthenticateWebAuthnStageForm.ts
|
||||||
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
#: src/pages/stages/captcha/CaptchaStageForm.ts
|
||||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
|
@ -5490,6 +5491,22 @@ msgstr ""
|
||||||
msgid "User status"
|
msgid "User status"
|
||||||
msgstr ""
|
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
|
#: src/pages/events/utils.ts
|
||||||
msgid "User was written to"
|
msgid "User was written to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { UserVerificationEnum } from "@goauthentik/api/dist/models/UserVerificationEnum";
|
||||||
|
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
|
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
|
@ -52,6 +54,40 @@ export class AuthenticateWebAuthnStageForm extends ModelForm<AuthenticateWebAuth
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</ak-form-element-horizontal>
|
</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>`;
|
</form>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue