fix(auth): a tab acts only as the account it was built for, and the review's other findings
A tab names the account it was claimed for on every request, beacon and upload (X-Siftlode-Expect-Account); current_user and /auth/logout refuse a mismatch with 401 account_changed and keep the session, so a tab left showing the account signed in before reloads instead of writing to the new one. /auth/login clears a connect marker left by an abandoned connect, and a link completes only on a session that still holds. The prefs merge reads the row under a lock. A tab's sessionStorage records its own owner. A page the account loses is given up, address bar and remembered page included. The panel layouts are preferences; the storage contract also refuses a key handed to the Storage API or to usePref outside its kind. A refused sign-in as someone else and a failed sign-out say so. The chromium-only e2e specs are in the gate register, the member walk waits for its requests, and devices.spec checks the save itself.
This commit is contained in:
@@ -270,6 +270,41 @@ def test_linking_a_free_identity_attaches_it(client, db, google, make_user):
|
||||
assert (me.google_sub, me.google_email) == ("sub-free", "me3.google@example.com")
|
||||
|
||||
|
||||
def test_a_connect_abandoned_at_google_leaves_the_next_sign_in_a_sign_in(
|
||||
client, db, google, make_user, monkeypatch
|
||||
):
|
||||
# A connect left at Google's screen (Back, a closed tab) never reaches the callback that pops
|
||||
# its marker. "Sign in as someone else" afterwards must sign that person in, not link their
|
||||
# Google identity onto the account still signed in here.
|
||||
me = make_user(email="me4@example.com")
|
||||
make_user(email="them4@example.com", google_sub="sub-them4", password=None)
|
||||
monkeypatch.setattr(settings, "allowed_emails", "them4@example.com")
|
||||
_start_link(client, "me4@example.com")
|
||||
assert client.get("/auth/login", follow_redirects=False).headers["location"] == "/fake-google"
|
||||
|
||||
r = _sign_in(client, google, sub="sub-them4", email="them4@example.com")
|
||||
|
||||
assert r.headers["location"] == "/"
|
||||
assert client.get("/api/me").json()["email"] == "them4@example.com"
|
||||
db.refresh(me)
|
||||
assert me.google_sub is None
|
||||
|
||||
|
||||
def test_a_link_whose_session_was_revoked_meanwhile_does_not_finish(client, db, google, make_user):
|
||||
# "Log out everywhere" (or a password change) between the start and the callback: the cookie
|
||||
# still names the account, but its session no longer holds, so it may not attach an identity.
|
||||
me = make_user(email="me5@example.com")
|
||||
_start_link(client, "me5@example.com")
|
||||
me.session_epoch = (me.session_epoch or 0) + 1
|
||||
db.commit()
|
||||
|
||||
r = _sign_in(client, google, sub="sub-late", email="late@example.com")
|
||||
|
||||
assert r.headers["location"] == "/?link=error"
|
||||
db.refresh(me)
|
||||
assert me.google_sub is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("access", "scope", "prompt"),
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user