Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebAuthn 2FA in UI #2108

Closed
wants to merge 51 commits into from
Closed

Add WebAuthn 2FA in UI #2108

wants to merge 51 commits into from

Conversation

grzuy
Copy link
Contributor

@grzuy grzuy commented Aug 21, 2019

First stab at #1948 in collaboration with @padulafacundo.

Prototype adding experimental support for WebAuthn as a 2nd factor.

Goal of this first prototype is to have a working solution that can be tested by rubygems.org and community developers to get early feedback and start the discussion.

What it does

  • Let's a user who already has 2FA (OTP) configure register WebAuthn Security Keys
  • On UI Sign In, user can 2FA with WebAuthn Security or fallback to OTP

Pending:

  • Ability to delete the registered WebAuthn credential
  • Support multiple WebAuthn credentials
  • Check the User Agent supports WebAuthn
  • Better handle Sign In failures
  • user id randomness in credential creation options (https://www.w3.org/TR/webauthn-2/#user-handle)
  • Fix 3 failing tests
  • Polish credential list UI
  • Polish WebAuthn session prompt UX
  • Adjust user-facing terminology ("Credential" vs. "Security Key")
  • Integration with OTP setup in the "Edit profile" page
  • Show "Last used" for each security key to the user
  • Update sign_count to bigint
  • Rate limit WebAuthn routes
  • Push all encoding/decoding to the webauthn gem
  • Fix CI build docker step
  • Let user know what's happening when registration of same security key fails
  • Remove encoding in webauthn tests
  • Depend on a webauthn gem released version, not master (after gem release)

Follow up items:

  • Support WebAuthn 2FA at the API level

app/models/user.rb Outdated Show resolved Hide resolved
app/views/layouts/application.html.erb Outdated Show resolved Hide resolved
app/views/sessions/webauthn_prompt.html.erb Outdated Show resolved Hide resolved
@ecnelises ecnelises self-requested a review August 22, 2019 02:15
config/locales/en.yml Outdated Show resolved Hide resolved
app/controllers/webauthn_credentials_controller.rb Outdated Show resolved Hide resolved
app/controllers/sessions_controller.rb Outdated Show resolved Hide resolved
app/controllers/sessions_controller.rb Outdated Show resolved Hide resolved
app/models/user.rb Outdated Show resolved Hide resolved
vendor/assets/javascripts/webauthn-json.js Outdated Show resolved Hide resolved
app/controllers/webauthn_credentials_controller.rb Outdated Show resolved Hide resolved
config/routes.rb Outdated

resources :webauthn_credentials, only: %i[index create destroy] do
collection do
get :create_options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get :create_options route is not protected against CSRF. Consider if this should use post instead to gain CSRF protection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This action is not a state-changing action.

We renamed it, create_options was a bit confusing.

config/routes.rb Outdated
@@ -169,6 +176,10 @@

resource :session, only: %i[create destroy] do
post 'mfa_create', to: 'sessions#mfa_create', as: :mfa_create
collection do
get :webauthn_authentication_options, constraints: { format: :json }, defaults: { format: :json }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider altering the :webauthn_authentication_options route to use post instead of get to take advantage of Rails' CSRF protection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was coded as a GET because not a state-changing action.

grzuy and others added 5 commits August 27, 2019 10:06
@eliotsykes
Copy link
Contributor

Would any of the new WebAuthn routes need throttling to mitigate brute force attacks?

@grzuy grzuy changed the title Add WebAuthn 2FA support Add WebAuthn 2FA support in UI Sep 20, 2019
@grzuy grzuy changed the title Add WebAuthn 2FA support in UI Add WebAuthn 2FA in UI Sep 20, 2019
@grzuy grzuy marked this pull request as ready for review September 20, 2019 14:25
<%= render "sessions/webauthn_prompt" %>
<% end %>

<%= render "sessions/otp_prompt" %>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please this a horizontal split? vertical looks clunky. l-half--l and l-half--r may be helpful.

@@ -16,6 +16,8 @@ de:
please_sign_in:
otp_incorrect:
otp_missing:
use_key: Sign in with Security Key
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add keys (empty value) for non-english locales.

@@ -102,6 +102,8 @@
</div>
<%= submit_tag t('.mfa.update'), :class => 'form__submit' %>
<% end %>

<h2><%= link_to t('webauthn_credentials.index.title'), webauthn_credentials_path %></h2>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this stands, the user can only add webauth security keys after they have registered a TOTP authenticator device. I am not sure I understand this requirement. Shouldn't the user be able to enable mfa and only register webauth keys?

@sonalkr132
Copy link
Member

Please add a section in CONTRIBUTING.md (or a new doc page) for steps to tests this locally. I was able to use https://github.com/google/virtual-authenticators-tab but it would nice to have this or perhaps an alternate method documented where we may not have to purchase a yubikey.

We will also need guides (for users) similar to https://guides.rubygems.org/setting-up-multifactor-authentication/
perhaps clarifying the downside that this method doesn't support gem cli.

@user = current_user
end

def destroy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it acceptable to allow users to delete the key without verifying that they have access to the key?

@@ -218,6 +224,26 @@ def otp_verified?(otp)
save!(validate: false)
end

def webauthn_verified?(current_challenge, webauthn_credential)
Copy link
Member

@sonalkr132 sonalkr132 Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand why this method is in User model. Would it be better if we asked WebauthnCredential object if it was valid/verified? Do we want to ensure that webauthn_credential belongs to the user?

@sonalkr132
Copy link
Member

Closing this in favour of #2865

@sonalkr132 sonalkr132 closed this Jun 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants