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

RFC: Add 2FA auth to RubyGems.org #1252

Closed
jeroenvisser101 opened this Issue Apr 13, 2016 · 20 comments

Comments

@jeroenvisser101
Copy link

jeroenvisser101 commented Apr 13, 2016

Is this something you guys would like to get a PR for? I'd be willing to invest some time and see if I can get it to work with clearance?

@dwradcliffe

This comment has been minimized.

Copy link
Member

dwradcliffe commented Apr 13, 2016

We have talked about this a little bit in the past but never really had the time to think it through. Before we say yes or no I'd like to see a plan for what it would look like and how it would work.

@nateberkopec

This comment has been minimized.

Copy link
Contributor

nateberkopec commented Apr 13, 2016

FWIW, as a user, I would prefer Google Authenticator, because I already have it installed.

@jeroenvisser101

This comment has been minimized.

Copy link
Author

jeroenvisser101 commented Apr 14, 2016

@dwradcliffe – totally, I'll work on mockups and a specification of how it would work (flowchart maybe?)

@nateberkopec – absolutely, scannable QR codes will most certainly be part of this, since Authy, Google Authenticator but also 1Password use this and it has become the industry standard (or so I believe). Thanks for the input!

@jeroenvisser101

This comment has been minimized.

Copy link
Author

jeroenvisser101 commented Oct 3, 2016

Hey, even though this is super cool, I don't think I have the time that I need to invest in this. I'll leave this open for anyone to pick up.

@jvanbaarsen

This comment has been minimized.

Copy link
Contributor

jvanbaarsen commented Apr 8, 2017

@dwradcliffe I would love to work on this feature. You said something about wanting to see some things before implementation works get started. Can you elaborate what type of things you would like to see?

@duckinator

This comment has been minimized.

Copy link
Member

duckinator commented Dec 1, 2017

Hi! I asked for some input on this, since it was brought up on Twitter again.

I don't have any expertise in this area, but I'm happy to help put a plan together for it.

Some thoughts from @indirect:

  1. First step for setting up 2FA should be verifying the email address.
  2. Don't use SMS, because it both costs money and isn't secure.
  3. 2FA setup via QR code or seed number.
  4. Backup codes to save in case of losing the token seed.
  5. After configuring it, requiring a valid token input to validate the user has it set up right before enabling it. (To avoid locking them out of their account.)

Miscellaneous notes from discussion with @indirect and @evanphx:

  1. 2FA gem push is very important, because most authenticated access to rubygems.org is publishing gems.
    • I personally suspect this may actually be more important than website 2FA.
  2. 2FA gem push would impact how Bundler's rake release works
    • However, 2FA would be opt-in, so this shouldn't be a blocking issue.
  3. A good first step is improving handling of the token generated by gem login.
    • E.g., using a JSON Web Token with an expiration, instead of the current one that lasts indefinitely.
  4. A potential approach to improving gem push would be building a new workflow around using SSH public keys.
    • @evanphx has experimented with this before, and may revisit it again. I've offered to help, if it's revisited.
  5. This would require a new RubyGems release that supports a 2FA challenge.
@duckinator

This comment has been minimized.

Copy link
Member

duckinator commented Dec 2, 2017

notes from talking with npm folks

npm added 2FA recently, so I talked to @iarna about how npm approached it!

npm's general approach

  1. If the server wants 2FA for an action, it looks for the the npm-otp HTTP header.
    • If it doesn't find one or it's incorrect, it returns an HTTP 401 with a WWW-Authentication header containing OTP.
  2. If the client gets an HTTP 401:
    a. It checks for a WWW-Authenticate header and if it contains OTP.
    b. If it does, it either instructs the user run the command again with --otp=####, or prompts them for the OTP interactively. (Varies depending on which command.)
  3. Overall design:
    • Use a library on the server to produce a shared secret and recovery codes.
    • Server sends an otpauth URL, in the form of otpauth://?secret=<SECRET>, to the client.
    • The client produces a QR code by passing the otpauth URL to a library that handles that.
    • The user does a test authentication, to make sure it works.
    • If they succeed, the server sends the recovery codes.
  4. Two 2FA modes:
    • 2FA ONLY for login.
    • 2FA for login, publication and anything that changes package ownership or permissions.

Note: otpauth urls can have more stuff in them, and it's worth seeing if any of that would be useful.

standalone client

It was originally developed as a standalone client, then moved into npm later on.

  1. The client does multiple things, because they combined 2FA, command line profile editing, and custom authentication tokens all into one thing.
    • The reasoning for this was that the API for setting 2FA was implemented as a subset of the API for setting other profile values.
  2. Code for handling 401 responses: https://github.com/npm/npm-profile/blob/latest/lib/index.js#L223
  3. Code for CLI 2FA workflow: https://github.com/npm/npm-profile/blob/latest/cmds/tfa.js

Here's the general flow for how their library is used:

profile.set({tfa: {password, mode}})
profile.set({tfa: [otp]})

suggestions

  1. 2FA should also be required for adding/removing maintainers. E.g., the gem owner command.
  2. Have the user go through a test authentication flow before actually enabling 2FA, just to make sure it works.
    • npm originally considered having two confirmations, but decided against it while it was still in development.
@indirect

This comment has been minimized.

Copy link
Member

indirect commented Dec 2, 2017

I have used npm's fully command-line 2fa flow, and it was pretty good. I would be okay with ending up somewhere similar. I also like the idea of 2fa only for login or 2fa for login/push/owner actions.

@ecnelises

This comment has been minimized.

Copy link
Contributor

ecnelises commented Mar 19, 2018

Hello everyone, I'm planning to apply this as a Google Summer of Code project. For the workflow, I have an idea that the authentication should have three levels:

  1. auth-only, just like what npm does, for login and disabling 2FA
  2. auth-and-package, for actions about package, like gem push or gem owner --add, gem owner --remove
  3. auth-and-write, for anything that will change data about current user

Will this be too complicated? And npm's two-level also works fine.

Also, as @duckinator pointed out, change token mechanism to JWT is nice. Maybe I can start from here. But what will be the result of incompatibility with old client that does not support JWT?

Anyway, I'll look for a good solution for OTP generating and create a mock site for feature test.

@connorshea

This comment has been minimized.

Copy link

connorshea commented Apr 18, 2018

@ecnelises did this end up going anywhere? :)

devise-two-factor is used in GitLab, I’m not sure if that’s still the best solution but it seemed like it was when it was added ~two years ago. Also I’m not sure if RubyGems.org even uses devise in the first place.

https://github.com/tinfoil/devise-two-factor

Houdini might also be an option, but it’s not a super active project either: https://github.com/Houdini/two_factor_authentication

@ecnelises

This comment has been minimized.

Copy link
Contributor

ecnelises commented Apr 19, 2018

@connorshea Thanks for your notification.

But RubyGems.org doesn't have dependency with Devise. Instead, it uses Clearance, a simple library for rails application use authentication by email and password. (Occasion for RubyGems.org is not complex. It's much simpler than GitLab, using devise may be a burden)

I also checked the both library for 2FA, both depends on Devise and ROTP which is the real logic for OTP generation. To keep things simple, I think just use it is a good idea.

@ethagnawl

This comment has been minimized.

Copy link

ethagnawl commented Jul 12, 2018

Have you been able to make any progress on this, @ecnelises? After today's NPM fiasco, this (missing) feature immediately jumped to mind.

I've not contributed to this project before, but would be happy to help get this shipped.

Also, FWIW, I'd vote for Google Authenticator or Authy.

@connorshea

This comment has been minimized.

Copy link

connorshea commented Jul 12, 2018

If the 2FA feature uses the standard TOTP algorithm it should support both Google Authenticator and Authy out of the box as far as I understand.

@connorshea

This comment has been minimized.

Copy link

connorshea commented Jul 12, 2018

@ethagnawl also, see #1725, #1729, and #1753. Looks like this is well on its way :)

@ecnelises

This comment has been minimized.

Copy link
Contributor

ecnelises commented Jul 12, 2018

@ethagnawl Some of them are finished and deployed. If you are interested in it, just add a cookie using JavaScript console document.cookie='mfa_feature=true;path=/' when visiting rubygems.org. You can now turn it on for login, but please be sure to keep the recovery codes well :) We now hide it by cookie because it has not been totally completed.

@connorshea Thank you :)

@ethagnawl

This comment has been minimized.

Copy link

ethagnawl commented Jul 12, 2018

@connorshea @ecnelises Excellent! Thanks for the prompt replies and your efforts on this issue!

@envygeeks

This comment has been minimized.

Copy link
Contributor

envygeeks commented Jul 20, 2018

If the 2FA feature uses the standard TOTP algorithm it should support both Google Authenticator and Authy out of the box as far as I understand.

@connorshea it'll support most any authenticator. Google Auth, Authy, 1Password, LastPass, pretty much any other generator that implements it.

@ioquatix

This comment has been minimized.

Copy link

ioquatix commented Dec 26, 2018

Sorry to jump in here, but I'm trying to use OTP and rake release now just hangs. What do I need to do? Can we improve the documentation to explain some of the basics? Is this a bug?

@sonalkr132

This comment has been minimized.

Copy link
Member

sonalkr132 commented Dec 27, 2018

Thank you pointing out @ioquatix. We are going to track this issue here bundler/bundler#6854

@jeroenvisser101

This comment has been minimized.

Copy link
Author

jeroenvisser101 commented Jan 18, 2019

Since this is (at least partially) implemented, I'm going to close the RFC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.