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

Fix handling of users with multiple identities #6837

Merged
merged 8 commits into from
Sep 20, 2023
Merged

Conversation

tgoyne
Copy link
Member

@tgoyne tgoyne commented Jul 28, 2023

ROS users were identified by the pair (identity, auth_url), and in the v10 port this was translated to (user_id, provider_type), but that isn't actually how Atlas users work. An App is the equivalent of the old auth_url, and within an App user_id uniquely identifies a user. Users don't actually have a "provider type" at all: users have one or more identities, each of which has a provider type, and the same SyncUser should be used regardless of which identity was used to log in.

This had surprisingly mild consequences, but was visibly broken in a few ways. Logging into the same user using two different identities resulted in two SyncUsers with the same user id. Opening the same partition (or any flx Realm) with both users resulted in both using whichever SyncUser happened to open it first, and the second would not create a SyncSession. This meant that most of the potential bad things (such as creating two session for one file) didn't actually happen, but the second user's list of sessions would be "incorrect", and removing one of the users would remove the incorrect set of local files.

Linking identities to anonymous users resulted in the user still being treated as anonymous. The primary negative effect of this was that linking an identity, logging out, then logging back in would result in the user being removed entirely in between, forcing the re-download of all Realms (and the loss of any un-uploaded data).

This bumps the schema version of the metadata Realm primarily for the sake of recovery on metadata Realms in invalid states: the migration block handles the case of multiple users with the same user id and unifies them. Since this needs a migration anyway, it fixes some incidental problems with the metadata Realm's schema which weren't fixable without a migration: the marked_for_deletion column was redundant with the Removed state, identity objects were leaked due to not being embedded, and the local_uuid field is no longer used for anything other than opening files written by early v10 versions, so there's no need to populate it for new users.

Initializing a sync manager opened the metadata Realm, read the persisted users, and then wrote the persisted users back to the Realm using three separate write transactions per user. It now just reads the data and doesn't write anything.

SyncUser's internal API permitted doing some invalid state transitions such as marking a user as logged in despite it not having any tokens. The two specific things which definitely could break was logging out a user while the profile was being updated and logging out a user while the access token was being refreshed, but there may have been more things. There also just was some dead code trying to support state transitions which could never happen.

@tgoyne tgoyne self-assigned this Jul 28, 2023
@cla-bot cla-bot bot added the cla: yes label Jul 28, 2023
@tgoyne tgoyne force-pushed the tg/user-provider branch 8 times, most recently from c6e0a8c to d5e5cd1 Compare August 2, 2023 22:31
@tgoyne
Copy link
Member Author

tgoyne commented Aug 2, 2023

This unfortunately grew to be pretty large in the process of making tsan happy, but hopefully the commits make enough sense individually that it's not too awful to review. There's no particular hurry here; this is just some incidental bug fixes extracted out of my multiprocess sync work.

@tgoyne tgoyne marked this pull request as ready for review August 3, 2023 00:49
@tgoyne tgoyne requested a review from jbreams August 3, 2023 00:52
@tgoyne tgoyne force-pushed the tg/user-provider branch 3 times, most recently from e0a3e6d to d95d48c Compare August 23, 2023 17:05
@coveralls-official
Copy link

coveralls-official bot commented Sep 14, 2023

Pull Request Test Coverage Report for Build github_pull_request_275077

  • 799 of 830 (96.27%) changed or added relevant lines in 24 files are covered.
  • 31 unchanged lines in 13 files lost coverage.
  • Overall coverage increased (+0.07%) to 91.237%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/realm/object-store/sync/impl/sync_metadata.cpp 199 200 99.5%
test/object-store/sync/app.cpp 82 83 98.8%
test/object-store/util/sync/sync_test_utils.cpp 4 5 80.0%
src/realm/object-store/sync/sync_user.cpp 72 78 92.31%
test/object-store/sync/metadata.cpp 90 96 93.75%
test/object-store/util/unit_test_transport.cpp 128 144 88.89%
Files with Coverage Reduction New Missed Lines %
src/realm/object-store/c_api/app.cpp 1 28.81%
src/realm/object-store/sync/app.cpp 1 93.3%
test/object-store/sync/session/session.cpp 1 98.5%
test/test_dictionary.cpp 1 99.85%
src/realm/object-store/shared_realm.cpp 2 94.59%
src/realm/object-store/sync/sync_user.cpp 2 90.57%
src/realm/sync/instruction_applier.cpp 2 70.35%
src/realm/sync/noinst/client_impl_base.cpp 2 85.54%
src/realm/sort_descriptor.cpp 3 94.33%
src/realm/sync/network/network.cpp 3 89.87%
Totals Coverage Status
Change from base Build 1680: 0.07%
Covered Lines: 233774
Relevant Lines: 256227

💛 - Coveralls

src/realm/object-store/sync/sync_manager.cpp Show resolved Hide resolved
SyncTestFile config(app, partition, schema);
auto r = Realm::get_shared_realm(config);
REQUIRE_FALSE(user->is_logged_in());
REQUIRE(user->state() == SyncUser::State::LoggedOut);
Copy link
Contributor

Choose a reason for hiding this comment

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

should this test wait for the access token response before checking the user state?

Copy link
Contributor

Choose a reason for hiding this comment

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

oh never mind, we use a synchronous transport

Copy link
Contributor

@ironage ironage left a comment

Choose a reason for hiding this comment

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

This is a much needed clean up of a neglected area of the code. 👍
Adding some defensive checks (or assertions) in log_out_user would be bonus, but not blocking.

ROS users were identified by the pair (identity, auth_url), and in the v10 port
this was translated to (user_id, provider_type), but that isn't actually how
Atlas users work. An App is the equivalent of the old auth_url, and within an
App user_id uniquely identifies a user. Users don't actually have a
"provider type" at all: users have one or more identities, each of which has a
provider type, and the same SyncUser should be used regardless of which
identity was used to log in.

This had surprisingly mild consequences, but was visibly broken in a few ways.
Logging into the same user using two different identities resulted in two
SyncUsers with the same user id. Opening the same partition (or any flx Realm)
with both users resulted in both using whichever SyncUser happened to open it
first, and the second would not create a SyncSession. This meant that most of
the potential bad things (such as creating two session for one file) didn't
actually happen, but the second user's list of sessions would be "incorrect",
and removing one of the users would remove the incorrect set of local files.

Linking identities to anonymous users resulted in the user still being treated
as anonymous. The primary negative effect of this was that linking an identity,
logging out, then logging back in would result in the user being removed
entirely in between, forcing the re-download of all Realms (and the loss of any
un-uploaded data).

This bumps the schema version of the metadata Realm primarily for the sake of
recovery on metadata Realms in invalid states: the migration block handles the
case of multiple users with the same user id and unifies them. Since this needs
a migration anyway, it fixes some incidental problems with the metadata Realm's
schema which weren't fixable without a migration: the marked_for_deletion
column was redundant with the Removed state, identity objects were leaked
due to not being embedded, and the local_uuid field is no longer used for
anything other than opening files written by early v10 versions, so there's no
need to populate it for new users.
@tgoyne tgoyne force-pushed the tg/user-provider branch 2 times, most recently from 12d2f62 to dd7e4fa Compare September 19, 2023 23:19
…ealm

Initializing sync users read from the metadata Realm used the same code path as
initializing newly logged in users, resulting in it performing three no-op
write transactions per user to write the data which was just read back to the
Realm.
It had incorrect semantics (users from different Apps which happened to have
the same id would compare equal), and simply isn't neccesary as there should
only ever be a single SyncUser instance per user and so pointer equality
suffices.
SyncUser previously allowed setting the state to LoggedIn without setting its
tokens, and conversely allowed setting tokens while not logged in. This was
error-prone and happened to result in a lock-order inversion due to that both
the state and the tokens had to be checked in places where we only wanted to
care about one of them.
@tgoyne tgoyne merged commit 0d21faa into master Sep 20, 2023
2 checks passed
@tgoyne tgoyne deleted the tg/user-provider branch September 20, 2023 01:57
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants