diff --git a/api/openapi.yml b/api/openapi.yml index 15443a24e..ae195cfbd 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -1021,23 +1021,28 @@ components: type: string format: byte webauthn.CredentialAttestationResponse: - allOf: - - $ref: '#/components/schemas/webauthn.PublicKeyCredential' - - type: object - properties: - clientExtensionResults: - type: object + type: object + properties: + credential: + allOf: + - $ref: '#/components/schemas/webauthn.PublicKeyCredential' + - type: object properties: - appidExclude: - type: boolean - response: - allOf: - - $ref: '#/components/schemas/webauthn.AuthenticatorResponse' - - type: object + clientExtensionResults: + type: object properties: - attestationObject: - type: string - format: byte + appidExclude: + type: boolean + response: + allOf: + - $ref: '#/components/schemas/webauthn.AuthenticatorResponse' + - type: object + properties: + attestationObject: + type: string + format: byte + description: + type: string webauthn.CredentialAssertionResponse: allOf: - $ref: '#/components/schemas/webauthn.PublicKeyCredential' diff --git a/internal/handlers/handler_register_webauthn.go b/internal/handlers/handler_register_webauthn.go index 60f89d254..26f94d738 100644 --- a/internal/handlers/handler_register_webauthn.go +++ b/internal/handlers/handler_register_webauthn.go @@ -2,6 +2,7 @@ package handlers import ( "bytes" + "encoding/json" "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" @@ -83,6 +84,11 @@ func SecondFactorWebauthnAttestationGET(ctx *middlewares.AutheliaCtx, _ string) // WebauthnAttestationPOST processes the attestation challenge response from the client. func WebauthnAttestationPOST(ctx *middlewares.AutheliaCtx) { + type requestPostData struct { + Credential json.RawMessage `json:"credential"` + Description string `json:"description"` + } + var ( err error w *webauthn.WebAuthn @@ -90,6 +96,7 @@ func WebauthnAttestationPOST(ctx *middlewares.AutheliaCtx) { attestationResponse *protocol.ParsedCredentialCreationData credential *webauthn.Credential + postData *requestPostData ) userSession := ctx.GetSession() @@ -110,8 +117,17 @@ func WebauthnAttestationPOST(ctx *middlewares.AutheliaCtx) { return } - if attestationResponse, err = protocol.ParseCredentialCreationResponseBody(bytes.NewReader(ctx.PostBody())); err != nil { - ctx.Logger.Errorf("Unable to parse %s assertionfor user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + err = json.Unmarshal(ctx.PostBody(), &postData) + if err != nil { + ctx.Logger.Errorf("Unable to parse %s assertion request data for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + + respondUnauthorized(ctx, messageMFAValidationFailed) + + return + } + + if attestationResponse, err = protocol.ParseCredentialCreationResponseBody(bytes.NewReader(postData.Credential)); err != nil { + ctx.Logger.Errorf("Unable to parse %s assertion for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -134,7 +150,7 @@ func WebauthnAttestationPOST(ctx *middlewares.AutheliaCtx) { return } - device := model.NewWebauthnDeviceFromCredential(w.Config.RPID, userSession.Username, "Primary", credential) + device := model.NewWebauthnDeviceFromCredential(w.Config.RPID, userSession.Username, postData.Description, credential) if err = ctx.Providers.StorageProvider.SaveWebauthnDevice(ctx, device); err != nil { ctx.Logger.Errorf("Unable to load %s devices for assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) diff --git a/web/src/services/Webauthn.ts b/web/src/services/Webauthn.ts index 7dc2de6ce..c8e72ec16 100644 --- a/web/src/services/Webauthn.ts +++ b/web/src/services/Webauthn.ts @@ -314,10 +314,14 @@ export async function getAssertionPublicKeyCredentialResult( async function postAttestationPublicKeyCredentialResult( credential: AttestationPublicKeyCredential, + description: string, ): Promise>> { const credentialJSON = encodeAttestationPublicKeyCredential(credential); - - return axios.post>(WebauthnAttestationPath, credentialJSON); + const postBody = { + credential: credentialJSON, + description: description, + }; + return axios.post>(WebauthnAttestationPath, postBody); } export async function postAssertionPublicKeyCredentialResult( @@ -327,11 +331,10 @@ export async function postAssertionPublicKeyCredentialResult( workflowID?: string, ): Promise>> { const credentialJSON = encodeAssertionPublicKeyCredential(credential, targetURL, workflow, workflowID); - return axios.post>(WebauthnAssertionPath, credentialJSON); } -export async function performAttestationCeremony(token: string): Promise { +export async function performAttestationCeremony(token: string, description: string): Promise { const attestationCreationOpts = await getAttestationCreationOptions(token); if (attestationCreationOpts.status !== 200 || attestationCreationOpts.options == null) { @@ -350,7 +353,7 @@ export async function performAttestationCeremony(token: string): Promise