1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-02 11:42:42 +01:00
Commit graph

625 commits

Author SHA1 Message Date
epriestley
02f94cd7d2 Fix an issue with Duo not live-updating properly on login gates
Summary:
See <https://discourse.phabricator-community.org/t/duo-broken-in-2019-week-12/2580/>.

The "live update Duo status" endpoint currently requires full sessions, and doesn't work from the session upgrade gate on login.

Don't require a full session to check the status of an MFA challenge.

Test Plan: Went through Duo gate in a new session, got a live update.

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D20347
2019-03-29 11:00:38 -07:00
epriestley
920ab13cfb Correct a possible fatal in the non-CSRF Duo MFA workflow
Summary:
Ref T13259. If we miss the separate CSRF step in Duo and proceed directly to prompting, we may fail to build a response which turns into a real control and fatal on `null->setLabel()`.

Instead, let MFA providers customize their "bare prompt dialog" response, then make Duo use the same "you have an outstanding request" response for the CSRF and no-CSRF workflows.

Test Plan: Hit Duo auth on a non-CSRF workflow (e.g., edit an MFA provider with Duo enabled). Previously: `setLabel()` fatal. After patch: smooth sailing.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13259

Differential Revision: https://secure.phabricator.com/D20234
2019-03-05 11:33:25 -08:00
Ariel Yang
01d0fc443a Fix a typo
Summary: Fix a type

Test Plan: No need.

Reviewers: #blessed_reviewers, amckinley

Reviewed By: #blessed_reviewers, amckinley

Subscribers: amckinley, epriestley

Differential Revision: https://secure.phabricator.com/D20203
2019-02-24 13:37:14 +00:00
epriestley
701a9bc339 Fix Facebook login on mobile violating CSP after form redirect
Summary: Fixes T13254. See that task for details.

Test Plan: Used iOS Simulator to do a login locally, didn't get blocked. Verified CSP includes "m.facebook.com".

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13254

Differential Revision: https://secure.phabricator.com/D20206
2019-02-23 05:25:09 -08:00
epriestley
8f8e863613 When users follow an email login link but an install does not use passwords, try to get them to link an account
Summary:
Ref T13249. See PHI774. When users follow an email login link ("Forgot password?", "Send Welcome Email", "Send a login link to your email address.", `bin/auth recover`), we send them to a password reset flow if an install uses passwords.

If an install does not use passwords, we previously dumped them unceremoniously into the {nav Settings > External Accounts} UI with no real guidance about what they were supposed to do. Since D20094 we do a slightly better job here in some cases. Continue improving this workflow.

This adds a page like "Reset Password" for "Hey, You Should Probably Link An Account, Here's Some Options".

Overall, this stuff is still pretty rough in a couple of areas that I imagine addressing in the future:

  - When you finish linking, we still dump you back in Settings. At least we got you to link things. But better would be to return you here and say "great job, you're a pro".
  - This UI can become a weird pile of buttons in certain configs and generally looks a little unintentional. This problem is shared among all the "linkable" providers, and the non-login link flow is also weird.

So: step forward, but more work to be done.

Test Plan: {F6211115}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13249

Differential Revision: https://secure.phabricator.com/D20170
2019-02-15 14:41:31 -08:00
epriestley
2ca316d652 When users confirm Duo MFA in the mobile app, live-update the UI
Summary: Ref T13249. Poll for Duo updates in the background so we can automatically update the UI when the user clicks the mobile phone app button.

Test Plan: Hit a Duo gate, clicked "Approve" in the mobile app, saw the UI update immediately.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13249

Differential Revision: https://secure.phabricator.com/D20169
2019-02-15 14:38:15 -08:00
epriestley
5892c78986 Replace all "setQueryParam()" calls with "remove/replaceQueryParam()"
Summary: Ref T13250. See D20149. Mostly: clarify semantics. Partly: remove magic "null" behavior.

Test Plan: Poked around, but mostly just inspection since these are pretty much one-for-one.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: yelirekim

Maniphest Tasks: T13250

Differential Revision: https://secure.phabricator.com/D20154
2019-02-14 11:56:39 -08:00
epriestley
241f06c9ff Clean up final setQueryParams() callsites
Summary: Ref T13250. See D20149.

Test Plan: All trivial?

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13250

Differential Revision: https://secure.phabricator.com/D20153
2019-02-14 11:54:56 -08:00
epriestley
4c12420162 Replace "URI->setQueryParams()" after initialization with a constructor argument
Summary: Ref T13250. See D20149. In a number of cases, we use `setQueryParams()` immediately after URI construction. To simplify this slightly, let the constructor take parameters, similar to `HTTPSFuture`.

Test Plan: See inlines.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13250

Differential Revision: https://secure.phabricator.com/D20151
2019-02-14 11:46:37 -08:00
epriestley
5a89da12e2 When users have no password on their account, guide them through the "reset password" flow in the guise of "set password"
Summary:
Depends on D20119. Fixes T9512. When you don't have a password on your account, the "Password" panel in Settings is non-obviously useless: you can't provide an old password, so you can't change your password.

The correct remedy is to "Forgot password?" and go through the password reset flow. However, we don't guide you to this and it isn't really self-evident.

Instead:

  - Guide users to the password reset flow.
  - Make it work when you're already logged in.
  - Skin it as a "set password" flow.

We're still requiring you to prove you own the email associated with your account. This is a pretty weak requirement, but maybe stops attackers who use the computer at the library after you do in some bizarre emergency and forget to log out? It would probably be fine to just let users "set password", this mostly just keeps us from having two different pieces of code responsible for setting passwords.

Test Plan:
  - Set password as a logged-in user.
  - Reset password on the normal flow as a logged-out user.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: revi

Maniphest Tasks: T9512

Differential Revision: https://secure.phabricator.com/D20120
2019-02-12 15:19:46 -08:00
epriestley
3f35c0068a Allow users to register with non-registration providers if they are invited to an instance
Summary:
Depends on D20117. Fixes T10071. When you're sent an email invitation, it's intended to allow you to register an account even if you otherwise could not (see D11737).

Some time between D11737 and today, this stopped working (or perhaps it never worked and I got things wrong in D11737). I think this actually ended up not mattering for us, given the way Phacility auth was ultimately built.

This feature generally seems reasonable, though, and probably //should// work. Make it work in the "password" and "oauth" cases, at least. This may //still// not work for LDAP, but testing that is nontrivial.

Test Plan:
  - Enabled only passwords, turned off registration, sent an invite, registered with a password.
  - Enabled only Google OAuth, turned off registration, sent an invite, registered with Google OAuth.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T10071

Differential Revision: https://secure.phabricator.com/D20118
2019-02-12 15:19:03 -08:00
epriestley
d22495a820 Make external link/refresh use provider IDs, switch external account MFA to one-shot
Summary:
Depends on D20113. Ref T6703. Continue moving toward a future where multiple copies of a given type of provider may exist.

Switch MFA from session-MFA at the start to one-shot MFA at the actual link action.

Add one-shot MFA to the unlink action. This theoretically prevents an attacker from unlinking an account while you're getting coffee, registering `alIce` which they control, adding a copy of your profile picture, and then trying to trick you into writing a private note with your personal secrets or something.

Test Plan: Linked and unlinked accounts. Refreshed account. Unlinked, then registered a new account. Unlinked, then relinked to my old account.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T6703

Differential Revision: https://secure.phabricator.com/D20117
2019-02-12 15:18:08 -08:00
epriestley
e5ee656fff Make external account unlinking use account IDs, not "providerType + providerDomain" nonsense
Summary: Depends on D20112. Ref T6703. When you go to unlink an account, unlink it by ID. Crazy!

Test Plan: Unlinked and relinked Google accounts.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T6703

Differential Revision: https://secure.phabricator.com/D20113
2019-02-12 15:16:24 -08:00
epriestley
541d794c13 Give ExternalAccount a providerConfigPHID, tying it to a particular provider
Summary:
Depends on D20111. Ref T6703. Currently, each ExternalAccount row is tied to a provider by `providerType` + `providerDomain`. This effectively prevents multiple providers of the same type, since, e.g., two LDAP providers may be on different ports on the same domain. The `domain` also isn't really a useful idea anyway because you can move which hostname an LDAP server is on, and LDAP actually uses the value `self` in all cases. Yeah, yikes.

Instead, just bind each account to a particular provider. Then we can have an LDAP "alice" on seven different servers on different ports on the same machine and they can all move around and we'll still have a consistent, cohesive view of the world.

(On its own, this creates some issues with the link/unlink/refresh flows. Those will be updated in followups, and doing this change in a way with no intermediate breaks would require fixing them to use IDs to reference providerType/providerDomain, then fixing this, then undoing the first fix most of the way.)

Test Plan: Ran migrations, sanity-checked database. See followup changes for more comprehensive testing.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T6703

Differential Revision: https://secure.phabricator.com/D20112
2019-02-12 14:48:14 -08:00
epriestley
55c18bc900 During first-time setup, create an administrator account with no authentication instead of weird, detached authentication
Summary:
Ref T6703. Currently, when you create an account on a new install, we prompt you to select a password.

You can't actually use that password unless you set up a password provider, and that password can't be associated with a provider since a password provider won't exist yet.

Instead, just don't ask for a password: create an account with a username and an email address only. Setup guidance points you toward Auth.

If you lose the session, you can send yourself an email link (if email works yet) or `bin/auth recover` it. This isn't really much different than the pre-change behavior, since you can't use the password you set anyway until you configure password auth.

This also makes fixing T9512 more important, which I'll do in a followup. I also plan to add slightly better guideposts toward Auth.

Test Plan: Hit first-time setup, created an account.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: revi

Maniphest Tasks: T6703

Differential Revision: https://secure.phabricator.com/D20111
2019-02-12 14:47:47 -08:00
epriestley
1fd69f788c Replace "getQueryParams()" callsites in Phabricator
Summary: See D20136. This method is sort of inherently bad because it is destructive for some inputs (`x=1&x=2`) and had "PHP-flavored" behavior for other inputs (`x[]=1&x[]=2`). Move to explicit `...AsMap` and `...AsPairList` methods.

Test Plan: Bit of an adventure, see inlines in a minute.

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D20141
2019-02-12 06:37:03 -08:00
epriestley
a4bab60ad0 Don't show "registration might be too open" warnings unless an auth provider actually allows registration
Summary:
Depends on D20118. Fixes T5351. We possibly raise some warnings about registration (approval queue, email domains), but they aren't relevant if no one can register.

Hide these warnings if no providers actually support registration.

Test Plan: Viewed the Auth provider list with registration providers and with no registration providers, saw more tailored guidance.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T5351

Differential Revision: https://secure.phabricator.com/D20119
2019-02-07 15:32:42 -08:00
epriestley
949afb02fd On login forms, autofocus the "username" field
Summary: Depends on D20120. Fixes T8907. I thought this needed some Javascript nonsense but Safari, Firefox and Chrome all support an `autofocus` attribute.

Test Plan: Loaded login page with password auth enabled in Safari, Firefox, and Chrome; saw username field automatically gain focus.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T8907

Differential Revision: https://secure.phabricator.com/D20122
2019-02-07 15:03:43 -08:00
epriestley
f0364eef8a Remove weird integration between Legalpad and the ExternalAccount table
Summary:
Depends on D20107. Ref T6703. Legalpad currently inserts "email" records into the external account table, but they're never used for anything and nothing else references them.

They also aren't necessary for anything important to work, and the only effect they have is making the UI say "External Account" instead of "None" under the "Account" column. In particular, the signatures still record the actual email address.

Stop doing this, remove all the references, and destroy all the rows.

(Long ago, Maniphest may also have done this, but no longer does. Nuance/Gatekeeper use a more modern and more suitable "ExternalObject" thing that I initially started adapting here before realizing that Legalpad doesn't actually care about this data.)

Test Plan: Signed documents with an email address, saw signature reflected properly in UI. Grepped for other callsites.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T6703

Differential Revision: https://secure.phabricator.com/D20108
2019-02-07 15:00:00 -08:00
epriestley
9f5e6bee90 Make the default behavior of getApplicationTransactionCommentObject() "return null" instead of "throw"
Summary:
Depends on D20115. See <https://discourse.phabricator-community.org/t/transaction-search-endpoint-does-not-work-on-differential-diffs/2369/>.

Currently, `getApplicationTransactionCommentObject()` throws by default. Subclasses must override it to `return null` to indicate that they don't support comments.

This is silly, and leads to a bunch of code that does a `try / catch` around it, and at least some code (here, `transaction.search`) which doesn't `try / catch` and gets the wrong behavior as a result.

Just make it `return null` by default, meaning "no support for comments". Then remove the `try / catch` stuff and all the `return null` implementations.

Test Plan:
  - Grepped for `getApplicationTransactionCommentObject()`, fixed each callsite / definition.
  - Called `transaction.search` on a diff with transactions (i.e., not a sourced-from-commit diff).

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: jbrownEP

Differential Revision: https://secure.phabricator.com/D20121
2019-02-07 14:56:38 -08:00
Austin McKinley
f2236eb061 Autofocus form control for adding TOTP codes
Summary: Ref D20122. This is something I wanted in a bunch of places. Looks like at some point the most-annoying one (autofocus for entering TOTOP codes) already got fixed at some point.

Test Plan: Loaded the form, got autofocus as expected.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

Differential Revision: https://secure.phabricator.com/D20128
2019-02-07 11:56:49 -08:00
epriestley
fc3b90e1d1 Allow users to unlink their last external account with a warning, instead of preventing the action
Summary:
Depends on D20105. Fixes T7732. T7732 describes a case where a user had their Google credentials swapped and had trouble regaining access to their account.

Since we now allow email login even if password auth is disabled, it's okay to let users unlink their final account, and it's even reasonable for users to unlink their final account if it is mis-linked.

Just give them a warning that what they're doing is a little sketchy, rather than preventing the workflow.

Test Plan: Unlinked my only login account, got a stern warning instead of a dead end.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T7732

Differential Revision: https://secure.phabricator.com/D20106
2019-02-06 17:07:41 -08:00
epriestley
d6f691cf5d In "External Accounts", replace hard-to-find tiny "link" icon with a nice button with text on it
Summary:
Ref T6703. Replaces the small "link" icon with a more obvious "Link External Account" button.

Moves us toward operating against `$config` objects instead of against `$provider` objects, which is more modern and will some day allow us to resolve T6703.

Test Plan: Viewed page, saw a more obvious button. Linked an external account.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T6703

Differential Revision: https://secure.phabricator.com/D20105
2019-02-06 16:07:16 -08:00
epriestley
9632c704c6 Always allow users to login via email link, even if an install does not use passwords
Summary:
Depends on D20099. Ref T13244. See PHI774. When password auth is enabled, we support a standard email-based account recovery mechanism with "Forgot password?".

When password auth is not enabled, we disable the self-serve version of this mechanism. You can still get email account login links via "Send Welcome Mail" or "bin/auth recover".

There's no real technical, product, or security reason not to let everyone do email login all the time. On the technical front, these links already work and are used in other contexts. On the product front, we just need to tweak a couple of strings.

On the security front, there's some argument that this mechanism provides more overall surface area for an attacker, but if we find that argument compelling we should probably provide a way to disable the self-serve pathway in all cases, rather than coupling it to which providers are enabled.

Also, inch toward having things iterate over configurations (saved database objects) instead of providers (abstract implementations) so we can some day live in a world where we support multiple configurations of the same provider type (T6703).

Test Plan:
  - With password auth enabled, reset password.
  - Without password auth enabled, did an email login recovery.

{F6184910}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13244

Differential Revision: https://secure.phabricator.com/D20100
2019-02-05 16:00:55 -08:00
epriestley
99e5ef84fc Remove obsolete "PhabricatorAuthLoginHandler"
Summary: Depends on D20096. Reverts D14057. This was added for Phacility use cases in D14057 but never used. It is obsoleted by {nav Auth > Customize Messages} for non-Phacility use cases.

Test Plan: Grepped for removed symbol.

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D20099
2019-02-05 14:20:14 -08:00
epriestley
4fcb38a2a9 Move the Auth Provider edit flow toward a more modern layout
Summary:
Depends on D20095. Ref T13244. Currently, auth providers have a list item view and a single gigantic edit screen complete with a timeline, piles of instructions, supplemental information, etc.

As a step toward making this stuff easier to use and more modern, give them a separate view UI with normal actions, similar to basically every other type of object. Move the timeline and "Disable/Enable" to the view page (from the edit page and the list page, respectively).

Test Plan: Created, edited, and viewed auth providers.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13244

Differential Revision: https://secure.phabricator.com/D20096
2019-02-05 14:19:26 -08:00
epriestley
8c8d56dc56 Replace "Add Auth Provider" radio buttons with a more modern "click to select" UI
Summary:
Depends on D20094. Ref T13244. Ref T6703. See PHI774. Currently, we use an older-style radio-button UI to choose an auth provider type (Google, Password, LDAP, etc).

Instead, use a more modern click-to-select UI.

Test Plan: {F6184343}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13244, T6703

Differential Revision: https://secure.phabricator.com/D20095
2019-02-05 14:18:16 -08:00
epriestley
6f3bd13cf5 Begin adding more guidance to the "One-Time Login" flow
Summary:
Ref T13244. See PHI774. If an install does not use password auth, the "one-time login" flow (via "Welcome" email or "bin/auth recover") is pretty rough. Current behavior:

  - If an install uses passwords, the user is prompted to set a password.
  - If an install does not use passwords, you're dumped to `/settings/external/` to link an external account. This is pretty sketchy and this UI does not make it clear what users are expected to do (link an account) or why (so they can log in).

Instead, improve this flow:

  - Password reset flow is fine.
  - (Future Change) If there are external linkable accounts (like Google) and the user doesn't have any linked, I want to give users a flow like a password reset flow that says "link to an external account".
  - (This Change) If you're an administrator and there are no providers at all, go to "/auth/" so you can set something up.
  - (This Change) If we don't hit on any other rules, just go home?

This may be tweaked a bit as we go, but basically I want to refine the "/settings/external/" case into a more useful flow which gives users more of a chance of surviving it.

Test Plan: Logged in with passwords enabled (got password reset), with nothing enabled as an admin (got sent to Auth), and with something other than passwords enabled (got sent home).

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13244

Differential Revision: https://secure.phabricator.com/D20094
2019-02-05 14:17:25 -08:00
epriestley
03eb989fd8 Give Duo MFA a stronger hint if users continue without answering the challenge
Summary: See PHI912. Also, clean up some leftover copy/pastey code here.

Test Plan: {F6182333}

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D20088
2019-02-05 14:14:41 -08:00
epriestley
db1e123706 Fix an issue where Duo validation could incorrectly apply to other factor types
See <https://discourse.phabricator-community.org/t/configuring-mfa-provider-totp-fails-for-missing-duo-only-options/2355>.

Test Plan: Created a TOTP provider; created a Duo provider (with missing and supplied values).
2019-02-03 06:36:49 -08:00
epriestley
e9b2d667ee Improve handling of "Deny" responses from Duo
Summary:
Ref T13231. See <https://discourse.phabricator-community.org/t/duo-integration-crashes-if-user-is-not-enrolled-and-enrollment-is-disabled/2340/5>

(There's an actual bug here, although I'm not sure exactly what's going on on the Duo side in the report.)

Test Plan:
To reproduce this, I was only able to actually "Deny" my account explicitly in Duo.

  - With "Deny", tried to add a factor. Got a nice helpful error message.
  - Undenied, added a factor, re-denied, tried to pass an MFA gate. Got another nice helpful error message.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13231

Differential Revision: https://secure.phabricator.com/D20065
2019-01-30 19:33:15 -08:00
epriestley
1767b80654 Replace manual query string construction with "phutil_build_http_querystring()"
Summary: Now that we have a nice function for this, use it to simplify some code.

Test Plan: Ran through the Duo enroll workflow to make sure signing still works.

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D20053
2019-01-30 19:14:57 -08:00
epriestley
70b474e550 Allow MFA enrollment guidance to be customized
Summary: Depends on D20039. Ref T13242. If installs want users to install a specific application, reference particular help, etc., let them customize the MFA enrollment message so they can make it say "if you have issues, see this walkthrough on the corporate wiki" or whatever.

Test Plan:
{F6164340}

{F6164341}

{F6164342}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13242

Differential Revision: https://secure.phabricator.com/D20043
2019-01-30 06:21:58 -08:00
epriestley
9fd8343704 Bring Duo MFA upstream
Summary: Depends on D20038. Ref T13231. Although I planned to keep this out of the upstream (see T13229) it ended up having enough pieces that I imagine it may need more fixes/updates than we can reasonably manage by copy/pasting stuff around. Until T5055, we don't really have good tools for managing this. Make my life easier by just upstreaming this.

Test Plan: See T13231 for a bunch of workflow discussion.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13231

Differential Revision: https://secure.phabricator.com/D20039
2019-01-28 18:26:45 -08:00
epriestley
d8d4efe89e Require MFA to edit MFA providers
Summary: Depends on D20037. Ref T13222. Ref T7667. Although administrators can now disable MFA from the web UI, at least require that they survive MFA gates to do so. T7667 (`bin/auth lock`) should provide a sturdier approach here in the long term.

Test Plan: Created and edited MFA providers, was prompted for MFA.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222, T7667

Differential Revision: https://secure.phabricator.com/D20038
2019-01-28 09:44:39 -08:00
epriestley
29b4fad941 Get rid of "throwResult()" for control flow in MFA factors
Summary: Depends on D20034. Ref T13222. This is just cleanup -- I thought we'd have like two of these, but we ended up having a whole lot in Duo and a decent number in SMS. Just let factors return a result explicitly if they can make a decision early. I think using `instanceof` for control flow is a lesser evil than using `catch`, on the balance.

Test Plan: `grep`, went through enroll/gate flows on SMS and Duo.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20035
2019-01-28 09:40:28 -08:00
epriestley
bce44385e1 Add more factor details to the Settings factor list
Summary:
Depends on D20033. Ref T13222. Flesh this UI out a bit, and provide bit-strength information for TOTP.

Also, stop users from adding multiple SMS factors since this is pointless (they all always text your primary contact number).

Test Plan:
{F6156245}

{F6156246}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20034
2019-01-28 09:40:00 -08:00
epriestley
8e5d9c6f0e Allow MFA providers to be deprecated or disabled
Summary: Ref T13222. Providers can now be deprecated (existing factors still work, but users can't add new factors for the provider) or disabled (factors stop working, also can't add new ones).

Test Plan:
  - Enabled, deprecated, and disabled some providers.
  - Viewed provider detail, provider list.
  - Viewed MFA settings list.
  - Verified that I'm prompted for enabled + deprecated only at gates.
  - Tried to disable final provider, got an error.
  - Hit the MFA setup gate by enabling "Require MFA" with no providers, got a more useful message.
  - Immediately forced a user to the "MFA Setup Gate" by disabling their only active provider with another provider enabled ("We no longer support TOTP, you HAVE to finish Duo enrollment to continue starting Monday.").

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20031
2019-01-28 09:29:27 -08:00
epriestley
c9ff6ce390 Add CSRF to SMS challenges, and pave the way for more MFA types (including Duo)
Summary:
Depends on D20026. Ref T13222. Ref T13231. The primary change here is that we'll no longer send you an SMS if you hit an MFA gate without CSRF tokens.

Then there's a lot of support for genralizing into Duo (and other push factors, potentially), I'll annotate things inline.

Test Plan: Implemented Duo, elsewhere.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13231, T13222

Differential Revision: https://secure.phabricator.com/D20028
2019-01-24 15:10:57 -08:00
epriestley
069160404f Add a Duo API future
Summary: Depends on D20025. Ref T13231. Although I'm not currently planning to actually upstream a Duo MFA provider, it's probably easiest to put most of the support pieces in the upstream until T5055.

Test Plan: Used a test script to make some (mostly trivial) API calls and got valid results back, so I think the parameter signing is correct.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13231

Differential Revision: https://secure.phabricator.com/D20026
2019-01-24 15:10:17 -08:00
epriestley
ab2cbbd9f9 Add a "test message" action for contact numbers
Summary: Depends on D20024. See D20022. Put something in place temporarily until we build out validation at some point.

Test Plan: Sent myself a test message.

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D20025
2019-01-23 14:22:27 -08:00
epriestley
587e9cea19 Always require MFA to edit contact numbers
Summary:
Depends on D20023. Ref T13222. Although I think this isn't strictly necessary from a pure security perspective (since you can't modify the primary number while you have MFA SMS), it seems like a generally good idea.

This adds a slightly new MFA mode, where we want MFA if it's available but don't strictly require it.

Test Plan: Disabled, enabled, primaried, unprimaried, and edited contact numbers. With MFA enabled, got prompted for MFA. With no MFA, no prompts.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20024
2019-01-23 14:19:56 -08:00
epriestley
7805b217ad Prevent users from editing, disabling, or swapping their primary contact number while they have SMS MFA
Summary:
Depends on D20022. Ref T13222. Since you can easily lock yourself out of your account by swapping to a bad number, prevent contact number edits while "contact number" MFA (today, always SMS) is enabled.

(Another approach would be to bind factors to specific contact numbers, and then prevent that number from being edited or disabled while SMS MFA was attached to it. However, I think that's a bit more complicated and a little more unwieldy, and ends up in about the same place as this. I'd consider it more strongly in the future if we had like 20 users say "I have 9 phones" but I doubt this is a real use case.)

Test Plan:
  - With SMS MFA, tried to edit my primary contact number, disable it, and promote another number to become primary. Got a sensible error message in all cases.
  - After removing SMS MFA, did all that stuff with no issues.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20023
2019-01-23 14:18:33 -08:00
epriestley
ada8a56bb7 Implement SMS MFA
Summary:
Depends on D20021. Ref T13222. This has a few rough edges, including:

  - The challenges theselves are CSRF-able.
  - You can go disable/edit your contact number after setting up SMS MFA and lock yourself out of your account.
  - SMS doesn't require MFA so an attacker can just swap your number to their number.

...but mostly works.

Test Plan:
  - Added SMS MFA to my account.
  - Typed in the number I was texted.
  - Typed in some other different numbers (didn't work).
  - Cancelled/resumed the workflow, used SMS in conjunction with other factors, tried old codes, etc.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20022
2019-01-23 14:17:38 -08:00
epriestley
6c11f37396 Add a pre-enroll step for MFA, primarily as a CSRF gate
Summary:
Depends on D20020. Ref T13222. This puts another step in the MFA enrollment flow: pick a provider; read text and click "Continue"; actually enroll.

This is primarily to stop CSRF attacks, since otherwise an attacker can put `<img src="phabricator.com/auth/settings/enroll/?providerPHID=xyz" />` on `cute-cat-pix.com` and get you to send yourself some SMS enrollment text messages, which would be mildly annoying.

We could skip this step if we already have a valid CSRF token (and we often will), but I think there's some value in doing it anyway. In particular:

  - For SMS/Duo, it seems nice to have an explicit "we're about to hit your phone" button.
  - We could let installs customize this text and give users a smoother onboard.
  - It allows the relatively wordy enroll form to be a little less wordy.
  - For tokens which can expire (SMS, Duo) it might save you from answering too slowly if you have to go dig your phone out of your bag downstairs or something.

Test Plan: Added factors, read text. Tried to CSRF the endpoint, got a dialog instead of a live challenge generation.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20021
2019-01-23 14:16:57 -08:00
epriestley
f3340c6335 Allow different MFA factor types (SMS, TOTP, Duo, ...) to share "sync" tokens when enrolling new factors
Summary:
Depends on D20019. Ref T13222. Currently, TOTP uses a temporary token to make sure you've set up the app on your phone properly and that you're providing an answer to a secret which we generated (not an attacker-generated secret).

However, most factor types need some kind of sync token. SMS needs to send you a code; Duo needs to store a transaction ID. Turn this "TOTP" token into an "MFA Sync" token and lift the implementation up to the base class.

Also, slightly simplify some of the HTTP form gymnastics.

Test Plan:
  - Hit the TOTP enroll screen.
  - Reloaded it, got new secrets.
  - Reloaded it more than 10 times, got told to stop generating new challenges.
  - Answered a challenge properly, got a new TOTP factor.
  - Grepped for removed class name.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20020
2019-01-23 14:13:50 -08:00
epriestley
7c1d1c13f4 Add a rate limit for enroll attempts when adding new MFA configurations
Summary:
Depends on D20018. Ref T13222. When you add a new MFA configuration, you can technically (?) guess your way through it with brute force. It's not clear why this would ever really be useful (if an attacker can get here and wants to add TOTP, they can just add TOTP!) but it's probably bad, so don't let users do it.

This limit is fairly generous because I don't think this actually part of any real attack, at least today with factors we're considering.

Test Plan:
  - Added TOTP, guessed wrong a ton of times, got rate limited.
  - Added TOTP, guessed right, got a TOTP factor configuration added to my account.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20019
2019-01-23 14:12:19 -08:00
epriestley
e91bc26da6 Don't rate limit users clicking "Wait Patiently" at an MFA gate even if they typed some text earlier
Summary:
Depends on D20017. Ref T13222. Currently, if you:

  - type some text at a TOTP gate;
  - wait ~60 seconds for the challenge to expire;
  - submit the form into a "Wait patiently" message; and
  - mash that wait button over and over again very patiently

...you still rack up rate limiting points, because the hidden text from your original request is preserved and triggers the "is the user responding to a challenge" test. Only perform this test if we haven't already decided that we're going to make them wait.

Test Plan:
  - Did the above; before patch: rate limited; after patch: not rate limited.
  - Intentionally typed a bunch of bad answers which were actually evaluated: rate limited properly.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D20018
2019-01-23 14:11:24 -08:00
epriestley
bb20c13651 Allow MFA factors to provide more guidance text on create workflows
Summary:
Depends on D20016. Ref T920. This does nothing interesting on its own since the TOTP provider has no guidance/warnings, but landing it separately helps to simplify an upcoming SMS diff.

SMS will have these guidance messages:

  - "Administrator: you haven't configured any mailer which can send SMS, like Twilio."
  - "Administrator: SMS is weak."
  - "User: you haven't configured a contact number."

Test Plan: {F6151283} {F6151284}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T920

Differential Revision: https://secure.phabricator.com/D20017
2019-01-23 14:10:16 -08:00
epriestley
af71c51f0a Give "MetaMTAMail" a "message type" and support SMS
Summary:
Depends on D20011. Ref T920. This change lets a "MetaMTAMail" storage object represent various different types of messages, and  makes "all" the `bin/mail` stuff "totally work" with messages of non-email types.

In practice, a lot of the related tooling needs some polish/refinement, but the basics work.

Test Plan: Used `echo beep boop | bin/mail send-test --to epriestley --type sms` to send myself SMS.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T920

Differential Revision: https://secure.phabricator.com/D20012
2019-01-23 14:05:46 -08:00