github/webauthn-json

Write tests using Chrome's virtual authenticator API

lgarron opened this issue · 4 comments

I've held off on writing thorough tests, because getting a good mock WebAuthn authenticator working was a bit daunting. However, Chrome's DevTools protocol now supports virtual authenticators: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/

This should make it possible to write fairly robust tests.

I haven't set up a GitHub action testing using the DevTools protocol, so we could use some help if anyone is familiar with how to set that up.

halo commented

Using Capybara and the webauthn gem, I was able to get integration tests working in a Rails environment. I thought I'd post it here for a kickstart (which testing-stack are you intending to use, by the way?).

To my surprise, recent versions of selenium/webdrivers support this out-of-the-box.

# Setup is only possible *after* an initial request (visit in Capybara) has been made.
visit '/login'

# Ensure same-origin
WebAuthn.configuration.origin = Capybara.current_session.server.base_url

# Enable virtual authenticators in browser
devtools = page.driver.browser.devtools
devtools.send_cmd 'WebAuthn.enable'

# Create an Authenticator
# See https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/#type-VirtualAuthenticatorOptions
options = {
  protocol: :ctap2,
  transport: :internal,
  hasResidentKey: false, # Chrome should not have to reveal a list of existing virtual authenticator IDs.
  # isUserConsenting: true, # Not sure, this option exists in selenium but not in chrome?
  hasUserVerification: true,
  isUserVerified: true,
}
attributes = record.devtools.send_cmd 'WebAuthn.addVirtualAuthenticator', options: options
id = attributes.dig('result', 'authenticatorId')

# Make sure to tear down after each test because it will interfere with further tests
devtools.send_cmd 'WebAuthn.removeVirtualAuthenticator', authenticatorId: id
devtools.send_cmd 'WebAuthn.disable'
halo commented

Thanks to this commit it just got much simpler:

visit '/login'

options = ::Selenium::WebDriver::VirtualAuthenticatorOptions.new
page.driver.browser.add_virtual_authenticator(options)

click_on 'Start the registration ceremony using my new hardware key'

Thanks to this commit it just got much simpler:

Thanks!

Just to be transparent, though: In the interest of keeping this library as easy as possible to maintain for its limited remaining lifetime, I think any JS testing framework would be preferable over Ruby (or over any other separate language).

halo commented

I completely agree, thanks for being clear. I just wanted to post this as a heads-up that selenium is in the progress of directly implementing those DevTools calls. Three months ago JS got them as well. Good luck!