Page MenuHomePhabricator

Convoluted flow when locked out of account with only one auth provider
Closed, ResolvedPublic

Description

Someone at our company had username X with Google Apps and username X with Phabricator. One day, he changed his Google Apps username to Y. We decidedly, logically enough, to change his Phabricator username to Y. I used the web UI to "change username." Somehow (unsure how) even though he said he had a window which was logged into Phabricator, something (maybe the username changed?) logged him out.

Our install has only a single auth provider configured, which is Google. Unfortunately, his account was still linked to the old (X) Google Apps account. His Google account had already been changed and there was no easy way to switch it back, so there was no way to get him back into Phabricator.

What we did:

  • Used the web UI to temporarily make him an administrator
  • Ran ./bin/auth recover to generate a link to let him log in
  • Removed his administrator status
  • Ask him to go to /settings/panel/external/ to set up auth correctly

At this point, Phabricator won't let him delete the existing connection to Google because it's his only auth method. There's also no obvious way to add a second Google account. I started wondering if maybe the only way out of this sticky situation was to temporarily add a second auth provider, then delete it after sorting this out.

Turns out, there was a way out. If you click the "refresh" icon next to the Google provider, you can add a second account. However, at this point, trying to delete the old Google account from the list of providers gives an error: "More than 1 result from loadOneWhere()!" He can log in just fine now so I won't worry about this, but it was still a weird experience.

I realize this is a corner case, but it seems like there could be some small changes in this flow that would lead to big UX wins. My biggest concrete suggestion is to maybe add a note on the providers page (if there's only one provider available) with some sort of "add 2nd Google account" button.

Event Timeline

jhurwitz raised the priority of this task from to Needs Triage.
jhurwitz updated the task description. (Show Details)
jhurwitz added a subscriber: jhurwitz.
  • T2549 discusses linking multiple accounts from a single provider.
  • T6707 discusses the "refresh" / multi-link error.

The expectation on this workflow is that the user will receive an email informing them that their username was changed. This email includes a one-time login link which bypasses authentication. So I would have expected things to work like this:

  • You change the username.
  • They click the link in the email to get back in.
  • At this point, T2549 / T6707 prevent moving forward because you have only one auth provider.

Do you know what happened to the email? Two possibilities I can imagine are:

  • It was sent to the old account?
  • It was received, but the wording wasn't clear in this context so no one thought to click the link?

This is the email he received:

Subject: [Phabricator] Username Changed

jhurwitz (Jacob Hurwitz) has changed your Phabricator username.

  Old Username: [X]
  New Username: [Y]

That's the entire email -- no links.

I can't reproduce 'no links' in my test install locally:

chad (Chad Little) has changed your Phabricator username.

  Old Username: notchad
  New Username: notchad2

If you use a password to login, you'll need to reset it before you can login
again. You can reset your password by following this link:

  http://phab.local/login/once/rename/3/zg3rvhcwzk3iw2o2kzzvujpa2l6u3qck/

And, of course, you'll need to use your new username to login from now on. If
you use OAuth to login, nothing should change.

If you disable passwords as an authentication provider for your test install, does the email content change?

  • Fixing the most general problem here (T2549) is in the 20-40 hour range.
  • Fixing just T6707 is about 1 hour.
  • This could also possibly be avoided if Google has permanent primary account identifiers now (instead of email addresses), assuming that both Google accounts were really the same account and they weren't recognized as such because we use email addresses as a primary identifier. I vaguely recall this being an issue when I wrote the integration originally, but Google was evolving auth a lot around that time and there might be a more durable identifier we can use now. This is ~1 hour to check and 2-4 hours to implement if something suitable is available. This problem likely wouldn't be possible with most other OAuth providers, which do have durable identifiers (e.g., user IDs).
  • We don't need to use the username as an input to any of the auth hashing, so we could remove the "changing usernames logs you out" interaction. This happens only because all the hashes invalidate, not because there's any fundamental security goal served by invalidating sessions. This is probably 3-6 hours of work.

There are other possible attacks on this, but those seem most promising offhand.

Although this is a rare edge case that we're unlikely to run into again, the fact that it ate up an hour of my life makes me think that spending ~5 hours to fix is worth it just in case we ever do run into this.

https://developers.google.com/identity/protocols/OpenIDConnect

An identifier for the user, unique among all Google accounts and never reused. A Google account can have multiple emails at different points in time, but the sub value is never changed. Use sub within your application as the unique-identifier key for the user.

I think this would be my preferred solution.

It looks like we also have access to id here, which is probably (but not necessarily) the same value:

https://developers.google.com/+/api/latest/people#resource

(IIRC, the first version of the Google auth required us to query your address book and look at the 0th entry to get your email address. We had to ask you for "read and write your address book" permission to do this, and this seemed to be accepted as the best approach at the time.)

T4289 is possibly similar, in that adding support for JIRA5 would imply a nondurable -> durable identifier upgrade when moving to JIRA6.

jhurwitz added a project: Restricted Project.Jun 3 2015, 9:27 PM

The workaround I provided in the task description ("If you click the "refresh" icon next to the Google provider, you can add a second account.") no longer works after D14319.

I now have someone who's completely locked out of Phabricator because of the situation described above. (Google is our only auth provider, his Google Apps username changed, then his Phabricator username changed.) I'm out of ideas, other than potentially (a) temporarily adding a new auth provider for the entire install, which I'd be uncomfortable doing, or (b) deleting the Phabricator account and creating a new one.

You can manually update phabricator_user.user_externalaccount to change the external account ID reference.

That worked for now -- hacky, but thanks.

I've marked D20106 as resolving this. Although all possible permutations of this situation aren't completely fixed, I believe we've added enough tools that this situation can be resolved by clicking a couple of things, and usually resolved by users without administrator intervention:

Older changes:

  • Long ago, usernames were used as salt in some digests, notably password digests. This meant that changing usernames invalidated some credentials. Since D18908 (Jan 2018) we no longer use usernames as a password salt (or any other salt) and automatically upgrade digests on login.
    • I'm not entirely sure if changing usernames ever actually invalidated sessions. I couldn't immediately find evidence that it did, although I vaguely recall that it may have.
    • Regardless, changing usernames does not invalidate sessions now (at least, locally, moments ago -- if you find a way to invalidate sessions, this is a bug and we'll fix it) and does not invalidate anything else either, with a technical footnote about passwords set before Jan 2018 which haven't been used since then.
  • bin/auth recover can recover non-administrator accounts since D18901.

Recent changes:

  • After D20100, users will always have an option to login by sending themselves an email link, even if an install does not use password auth. You can use this to recover access if other auth methods (like Google) are broken.
  • After D20102, we no longer issue any kind of "you need to reset / login again" guidance on username changes. This guidance has been less and less relevant since Jan 2018.
  • After D20106, users are warned about unlinking their last account, but the action is no longer prevented. Unlink + Relink now works, you just have to click one extra dialog. If you accidentally lose your session, you can use an email link to recover access.

There may still be some way to stumble into a bad state with multiple accounts, but the most obvious path should no longer get you there and this should become impossible as T6703 continues to move toward resolution.