We've run into a situation where a user modified their preferred
gerrit email address then modified their email address in our openid
provider. This initially hit a conflict within Gerrit because logging
in with the openid provider at that point tried to create a new
account (I suspect the openid provider updated the openid when the
email address changed), but this failed because the preferred email
address belonged to an existing account.
Eventually the user reverted the openid provider email changes setting
email back to a different value. This seems to have reverted the
openid url value as well, but since the email address didn't conflict
Gerrit updated the external id for that openid url with a new email
address. This effectively forced Gerrit to create a new account
because the email addresses for the existing account and the email
address associated with the openid no longer overlapped. Also the old
account is no longer accessible via openid login because no openid
external id is associated with it.
I'm not sure how well I've described this with words so here are the
current external-ids:
Old Account
[{"identity":"username:oldaccount","trusted":true},{"identity":"mailto:
oldac...@foo.com","email_address":"
oldac...@foo.com","trusted":true,"can_delete":true},{"identity":"mailto:
diff...@bar.com","email_address":"
diff...@bar.com","trusted":true,"can_delete":true}]
New Account
[{"identity":"
https://login.somewhere.com/+id/stuff","email_address":"
thir...@foo.com","trusted":true,"can_delete":true}]
Prior to notedb we would have addressed this with some straightforward
SQL table updates. The process was roughly to do an `UPDATE
account_external_ids SET account_id=12345 WHERE
external_id="
https://login.foo.bar/+baz";` Then disable the account
that was created in error via the SSH or HTTP API and maybe flush
caches.
With notedb this no longer seems straightforward as the Gerrit api [0]
does not have methods for updating external ids other than to delete
them. One thought was that we could delete the openid external-id and
disable the new account then have the user login with the desired
email address. This would create a new external-id for the openid that
maps to the existing account's email addresses. But I'm fairly certain
Gerrit would throw an error claiming that there is an email address
conflict.
The external id notedb situation is documented [1] and that doc says
we can manually push an update to All-Users:refs/meta/external-ids.
Gerrit will sanity check this push and reject it if we've got
something fundamentally wrong. What I don't understand is how are we
supposed to avoid races between new users being created and pushing an
update to refs/meta/external-ids? It seems that this process is
inherently flawed, but I may be missing something obvious. We could
disable all external access to our server temporarily but that is less
than desirable. Maybe we rebase and retry until it is a fast
forwardable update?
Also, to make sure I've understood what the docs are telling us: I
would update the external-id for
"identity":"
https://login.somewhere.com/+id/stuff" to set
"email_address":"
oldac...@foo.com". Having the email address map to
the old existing account is what will tie them together? Do we need to
reindex accounts after doing this?
Any help on how to properly fix this with the least amount of risk to
All-Users external-id consistency would be appreciated.
Finally, it would be nice if we could avoid this problem in the future
(perhaps this points to a bug in openid external-id updates? eg don't
update them if it would detach an existing user account from its
openid). And exposing external-id management through the api if
possible would likely simplify this greatly for us.
[0]
https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#get-account-external-ids
[1]
https://gerrit-review.googlesource.com/Documentation/config-accounts.html#external-ids
Clark