Skip to content

[3.0] Load the guest data when verification demotes a member to one - #9490

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/logintfa-guest-dataset
Open

[3.0] Load the guest data when verification demotes a member to one#9490
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/logintfa-guest-dataset

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

Two factor authentication cannot be completed on release-3.0 at all, and
a member who is deactivated or banned while signed in gets a fatal error
instead of being logged out. Both are the same bug.

User::loadMe() calls loadUserData() for the member the login cookie claims
to be, so User::$profiles[0] — the guest's data — is only ever built when
that claim was already 0. Both verifyPassword() and verifyTfa() can then
reset User::$my_id back to 0, and everything after them reads
User::$profiles[0], which was never there. setProperties() finishes with

$this->dataset = $profile['dataset'];

and assigning null to a typed property is fatal, so the request dies with

Cannot assign null to property SMF\User::$dataset of type SMF\UserDataset

Two ways in, neither of which needs the member to do anything unusual:

  1. ?action=logintfa. Anyone with a tfa_secret is redirected there after
    their password, and verifyTfa() resets their ID on purpose so the action
    can check the code itself. The page cannot render, so the code prompt never
    appears and TOTP two factor authentication cannot be used.
  2. Deactivated or banned mid-session. The next page load fails
    verifyPassword() on an otherwise valid cookie, hits the same reset, and
    fatals rather than turning them back into a guest.

The fix loads the guest's data at the point we learn we need it — the same
data a visitor who arrived as a guest already gets.

Verified on a running forum, since CI only proves the code parses. A
throwaway member with a real TOTP secret, driven over HTTP, with the identical
run against release-3.0 for comparison:

release-3.0 with this
second factor form appears fatal renders
a correct code signs them in unreachable signs in
a wrong code is refused unreachable refused
backup code form appears fatal renders
deactivated while signed in fatal becomes a guest
member with no second factor logs in ok ok
guest gets the board index ok ok

13 of 13 with the change, 7 of 12 without it. Note the deactivation row: that
one involves no two factor authentication whatsoever, which is what shows the
bug is not confined to the logintfa page.

Also ran composer lint, phplint over Sources, and the four integrity
checks.

Issues References (Fixes|Related|Closes)

  1. Related: [3.0] External authentication (part 3 of 5) — lets members sign in with a passkey #9489, which had to ship passkeys as a first factor only because
    the second factor role has to live on the page this fixes.

User::loadMe() asks loadUserData() for the member the cookie claims, so
User::$profiles[0] is only ever built when that claim is already 0. Both
verifyPassword() and verifyTfa() can then reset User::$my_id back to 0, and
everything after them -- initializeGuest(), setProperties() -- reads
User::$profiles[0], which was never there. setProperties() ends at

    $this->dataset = $profile['dataset'];

and assigning null to a typed property is fatal, so the request dies with
"Cannot assign null to property SMF\User::$dataset of type SMF\UserDataset".

Two ways in, both of which a member can reach without doing anything odd:

- Anyone with a tfa_secret is sent to ?action=logintfa, where verifyTfa()
  resets the ID on purpose so the action can check the code. The page cannot
  render at all, so two factor authentication cannot be completed.
- Anyone deactivated or banned while holding a valid login cookie fails
  verifyPassword() on their next page load and gets the same fatal instead
  of being turned back into a guest.

Loads the guest's data at the point we learn we need it, which is what a
visitor who arrived as a guest already gets.

Signed-off-by: Mathias Albert <mathiaspapealbert@hotmail.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants