stages/authenticator_webauthn: fix incorrect response being sent
This commit is contained in:
parent
388c8c8bec
commit
451c117ea4
|
@ -0,0 +1,86 @@
|
|||
# Generated by Django 3.1.6 on 2021-02-22 18:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_policies_event_matcher", "0009_auto_20210215_2159"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="eventmatcherpolicy",
|
||||
name="app",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("authentik.admin", "authentik Admin"),
|
||||
("authentik.api", "authentik API"),
|
||||
("authentik.events", "authentik Events"),
|
||||
("authentik.crypto", "authentik Crypto"),
|
||||
("authentik.flows", "authentik Flows"),
|
||||
("authentik.outposts", "authentik Outpost"),
|
||||
("authentik.lib", "authentik lib"),
|
||||
("authentik.policies", "authentik Policies"),
|
||||
("authentik.policies.dummy", "authentik Policies.Dummy"),
|
||||
(
|
||||
"authentik.policies.event_matcher",
|
||||
"authentik Policies.Event Matcher",
|
||||
),
|
||||
("authentik.policies.expiry", "authentik Policies.Expiry"),
|
||||
("authentik.policies.expression", "authentik Policies.Expression"),
|
||||
(
|
||||
"authentik.policies.group_membership",
|
||||
"authentik Policies.Group Membership",
|
||||
),
|
||||
("authentik.policies.hibp", "authentik Policies.HaveIBeenPwned"),
|
||||
("authentik.policies.password", "authentik Policies.Password"),
|
||||
("authentik.policies.reputation", "authentik Policies.Reputation"),
|
||||
("authentik.providers.proxy", "authentik Providers.Proxy"),
|
||||
("authentik.providers.oauth2", "authentik Providers.OAuth2"),
|
||||
("authentik.providers.saml", "authentik Providers.SAML"),
|
||||
("authentik.recovery", "authentik Recovery"),
|
||||
("authentik.sources.ldap", "authentik Sources.LDAP"),
|
||||
("authentik.sources.oauth", "authentik Sources.OAuth"),
|
||||
("authentik.sources.saml", "authentik Sources.SAML"),
|
||||
(
|
||||
"authentik.stages.authenticator_static",
|
||||
"authentik Stages.Authenticator.Static",
|
||||
),
|
||||
(
|
||||
"authentik.stages.authenticator_totp",
|
||||
"authentik Stages.Authenticator.TOTP",
|
||||
),
|
||||
(
|
||||
"authentik.stages.authenticator_validate",
|
||||
"authentik Stages.Authenticator.Validate",
|
||||
),
|
||||
(
|
||||
"authentik.stages.authenticator_webauthn",
|
||||
"authentik Stages.Authenticator.WebAuthn",
|
||||
),
|
||||
("authentik.stages.captcha", "authentik Stages.Captcha"),
|
||||
("authentik.stages.consent", "authentik Stages.Consent"),
|
||||
("authentik.stages.dummy", "authentik Stages.Dummy"),
|
||||
("authentik.stages.email", "authentik Stages.Email"),
|
||||
(
|
||||
"authentik.stages.identification",
|
||||
"authentik Stages.Identification",
|
||||
),
|
||||
("authentik.stages.invitation", "authentik Stages.User Invitation"),
|
||||
("authentik.stages.password", "authentik Stages.Password"),
|
||||
("authentik.stages.prompt", "authentik Stages.Prompt"),
|
||||
("authentik.stages.user_delete", "authentik Stages.User Delete"),
|
||||
("authentik.stages.user_login", "authentik Stages.User Login"),
|
||||
("authentik.stages.user_logout", "authentik Stages.User Logout"),
|
||||
("authentik.stages.user_write", "authentik Stages.User Write"),
|
||||
("authentik.managed", "authentik Managed"),
|
||||
("authentik.core", "authentik Core"),
|
||||
],
|
||||
default="",
|
||||
help_text="Match events created by selected application. When left empty, all applications are matched.",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -22,7 +22,7 @@ def create_default_setup_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEdito
|
|||
designation=FlowDesignation.STAGE_CONFIGURATION,
|
||||
defaults={
|
||||
"name": "default-authenticator-webuahtn-setup",
|
||||
"title": "Setup Static OTP Tokens",
|
||||
"title": "Setup WebAuthn",
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.1.6 on 2021-02-22 18:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_authenticator_webauthn", "0002_default_setup_flow"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="webauthndevice",
|
||||
name="confirmed",
|
||||
field=models.BooleanField(
|
||||
default=True, help_text="Is this device ready for use?"
|
||||
),
|
||||
),
|
||||
]
|
|
@ -8,6 +8,7 @@ from django.urls import reverse
|
|||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from django_otp.models import Device
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from authentik.flows.models import ConfigurableStage, Stage
|
||||
|
@ -56,7 +57,7 @@ class AuthenticateWebAuthnStage(ConfigurableStage, Stage):
|
|||
verbose_name_plural = _("WebAuthn Authenticator Setup Stages")
|
||||
|
||||
|
||||
class WebAuthnDevice(models.Model):
|
||||
class WebAuthnDevice(Device):
|
||||
"""WebAuthn Device for a single user"""
|
||||
|
||||
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||
|
|
|
@ -7,6 +7,7 @@ from rest_framework.serializers import ValidationError
|
|||
from structlog.stdlib import get_logger
|
||||
from webauthn.webauthn import (
|
||||
RegistrationRejectedException,
|
||||
WebAuthnCredential,
|
||||
WebAuthnMakeCredentialOptions,
|
||||
WebAuthnRegistrationResponse,
|
||||
)
|
||||
|
@ -87,7 +88,7 @@ class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
|||
)
|
||||
webauthn_credential.public_key = str(webauthn_credential.public_key, "utf-8")
|
||||
|
||||
return webauthn_registration_response
|
||||
return webauthn_credential
|
||||
|
||||
|
||||
class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
||||
|
@ -145,7 +146,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||
|
||||
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
|
||||
# Webauthn Challenge has already been validated
|
||||
webauthn_credential = response.validated_data["response"]
|
||||
webauthn_credential: WebAuthnCredential = response.validated_data["response"]
|
||||
existing_device = WebAuthnDevice.objects.filter(
|
||||
credential_id=webauthn_credential.credential_id
|
||||
).first()
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# Generated by Django 3.1.6 on 2021-02-22 18:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_prompt", "0002_auto_20200920_1859"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="prompt",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("text", "Text: Simple Text input"),
|
||||
(
|
||||
"username",
|
||||
"Username: Same as Text input, but checks for and prevents duplicate usernames.",
|
||||
),
|
||||
("email", "Email: Text field with Email type."),
|
||||
(
|
||||
"password",
|
||||
"Password: Masked input, password is validated against sources. Policies still have to be applied to this Stage. If two of these are used in the same stage, they are ensured to be identical.",
|
||||
),
|
||||
("number", "Number"),
|
||||
("checkbox", "Checkbox"),
|
||||
("date", "Date"),
|
||||
("date-time", "Date Time"),
|
||||
("separator", "Separator: Static Separator Line"),
|
||||
(
|
||||
"hidden",
|
||||
"Hidden: Hidden field, can be used to insert data into form.",
|
||||
),
|
||||
("static", "Static: Static value, displayed as-is."),
|
||||
],
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -57,10 +57,9 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
|
|||
// post the transformed credential data to the server for validation
|
||||
// and storing the public key
|
||||
try {
|
||||
const response = <WebAuthnAuthenticatorRegisterChallengeResponse>{
|
||||
response: newAssertionForServer
|
||||
};
|
||||
await this.host?.submit(JSON.stringify(response));
|
||||
const formData = new FormData();
|
||||
formData.set("response", JSON.stringify(newAssertionForServer))
|
||||
await this.host?.submit(formData);
|
||||
} catch (err) {
|
||||
throw new Error(gettext(`Server validation of credential failed: ${err}`));
|
||||
}
|
||||
|
@ -100,6 +99,9 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
|
|||
</div>`:
|
||||
html`
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
${this.challenge?.response_errors ?
|
||||
html`<p class="pf-m-block">${this.challenge.response_errors["response"][0].string}</p>`:
|
||||
html``}
|
||||
<p class="pf-m-block">${this.registerMessage}</p>
|
||||
<button class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
|
||||
this.registerWrapper();
|
||||
|
|
|
@ -63,7 +63,7 @@ export class FlowExecutor extends LitElement {
|
|||
});
|
||||
}
|
||||
|
||||
submit(formData?: string | FormData): Promise<void> {
|
||||
submit(formData?: FormData): Promise<void> {
|
||||
const csrftoken = getCookie("authentik_csrf");
|
||||
const request = new Request(DefaultClient.makeUrl(["flows", "executor", this.flowSlug]), {
|
||||
headers: {
|
||||
|
|
Reference in New Issue