cedarcode / webauthn-ruby

WebAuthn ruby server library ― Make your Ruby/Rails web server become a conformant WebAuthn Relying Party
https://rubygems.org/gems/webauthn
MIT License
658 stars 55 forks source link

Add support for optional authenticator_attachment in PublicKeyCredential #370

Closed 8ma10s closed 1 year ago

8ma10s commented 2 years ago

Why

https://w3c.github.io/webauthn/#iface-pkcredential

Level 3 draft of WebAuthn adds an optional parameter authenticatorAttachment on PublicKeyCredential (and AuthenticatorAttestationResponse and AuthenticatorAssertionResponse which inherits it, of course).

This field allows RP developers to detect whether the authentication was done using platform authenticator that always exists on that particular device, or cross-platform authenticator that only exists on that device temporarily.

In the latter case of using cross-platform authenticator, RP can prompt the user to register a platform authenticator so that the user won't lose the ability to sign in on that device.

Note: If, as the result of a registration or authentication ceremony, authenticatorAttachment's value is "cross-platform" and concurrently isUserVerifyingPlatformAuthenticatorAvailable returns true, then the user employed a roaming authenticator for this ceremony while there is an available platform authenticator. Thus the Relying Party has the opportunity to prompt the user to register the available platform authenticator, which may enable more streamlined user experience flows.

Since some vendors (I confirmed with Mac chrome) are already passing this optional parameter authenticatorAttachment, I want this gem to be able to support reading values from that field.

What

Allow initializing PublicKeyCredential class with an optional argument authenticator_attachment

Misc

I obtained the authenticator response returned from the client on sign-in (using dev-console), and ran WebAuthn::Credential.from_get on that response. As you can see, I can now obtain the value of authenticator_attachment

image

halo commented 2 years ago

UPDATE

Never mind me! I forgot that the authenticatior_selection contains theauthenticator_attachment attribute. See this test

Older Post Hi! Can we also add this to [`WebAuthn::PublicKeyCredential::CreationOptions`](https://github.com/cedarcode/webauthn-ruby/blob/64307ae9583db399585f299125afcc2695a6204f/lib/webauthn/public_key_credential/creation_options.rb#L11-L18)? It's helpful to read that value, but it would be even better to also set that value. Because, I noticed that Safari on macOS behaves differently than Safari on iOS, depending on what you specify in `authenticator_attachment`. You can check it yourself for example here: [demo.quado.io](https://demo.quado.io) If you use *Authenticator type: Unspecified*, no `authenticator_attachment` is sent to the browser, and Safari on macOS will **not** allow a platform authenticator: Screen Shot 2022-10-08 at 11 12 23 But if you choose *Authenticator type: Platform*, then `authenticator_attachment: platform` is sent to the browser, and Safari on macOS will allow using Touch ID: Screen Shot 2022-10-08 at 11 12 34 Safari on iOS will provide ~Touch ID~ Passkey, even without sending `authenticator_attachment`. Maybe we should have a separate PR for the creation options? PS: I didn't know about [`PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable `](https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable) where you can simply check via JS in the browser whether a platform authenticator is available or not. So you can even decide upfront whether to ask for "platform" or not. Unfortunately, if you choose platform, Safari will not allow a portable USB key 🫣
8ma10s commented 1 year ago

Let me check. (sorry for the late reply)

8ma10s commented 1 year ago

@santiagorodriguez96 sorry for late response.

I just played around with the demo rails server, and it seems like the problem is as follows:

So basically, it's not the rails gem's problem, but the frontend code's problem. I confirmed that switching the frontend implementation from using https://github.com/ericelliott/credential to https://github.com/github/webauthn-json successfully returns authenticatorAttachment to your backend demo code.

Here's what I got for the backend after the modification:

    webauthn_credential = WebAuthn::Credential.from_get(params)
    Rails.logger.info(webauthn_credential)

produces

{"type"=>"public-key", "id"=>"TecfTRasmz5e6BkT6T8Yz4cZYDUW_NLXInHrjMojI3A", "rawId"=>"TecfTRasmz5e6BkT6T8Yz4cZYDUW_NLXInHrjMojI3A", "authenticatorAttachment"=>"platform", "response"=>{
...

It feels to me that it could be a good idea to add this argument to the initialization of PublicKeyCredential in both spec/webauthn/public_key_credential_with_attestation_spec.rb and spec/webauthn/public_key_credential_with_assertion_spec.rb

added 👍 3e17fcd

I also found this thing called fake_client that's used in some of the specs, so I modified that code too. This ensures that "even if frontend code (and thus backend server using this gem) starts passing in authenticatorAttachment, the existing behavior will not get affected.