Skip to content

fix: block suspended users from authenticating (closes #37) - #363

Open
mrofreP wants to merge 1 commit into
UndernetIRC:masterfrom
mrofreP:fix/block-suspended-user-login
Open

mrofreP wants to merge 1 commit into
UndernetIRC:masterfrom
mrofreP:fix/block-suspended-user-login

Conversation

@mrofreP

@mrofreP mrofreP commented Jul 18, 2026

Copy link
Copy Markdown

A user carrying the global suspend flag could still authenticate. Login
did not check the flag; and even with that check, the other token-minting
paths did not -- so an already-authenticated user kept full access after
being suspended. RefreshToken re-issues a 7-day refresh token on every
call, letting a live client roll its session indefinitely, and
VerifyFactor completed any 2FA login whose state token was minted before
the suspension landed.

Add a rejectIfSuspended helper and call it on every path that mints a
token:

  • Login: after password validation, before the MFA challenge, so a
    suspended 2FA user is refused without leaking an MFA_REQUIRED state
    token.
  • RefreshToken: after the user is loaded, before the refresh token is
    consumed, so no new token pair is issued.
  • VerifyFactor: after the user is loaded, before 2FA completes.

All three return 403 with an identical message so the response does not
reveal which check fired. Document the 403 on the Login endpoint and
regenerate the Swagger definitions.

Tests: Login suspended cases (403, no Set-Cookie, no MFA_REQUIRED leak)
as a struct table; unit coverage of the RefreshToken and VerifyFactor
paths (TestAuthenticationController_SuspendedAccountCannotMintTokens);
and an integration test that creates a suspended user and asserts Login
returns 403.

A user carrying the global suspend flag could still authenticate. Login
did not check the flag; and even with that check, the other token-minting
paths did not -- so an already-authenticated user kept full access after
being suspended. RefreshToken re-issues a 7-day refresh token on every
call, letting a live client roll its session indefinitely, and
VerifyFactor completed any 2FA login whose state token was minted before
the suspension landed.

Add a rejectIfSuspended helper and call it on every path that mints a
token:
- Login: after password validation, before the MFA challenge, so a
  suspended 2FA user is refused without leaking an MFA_REQUIRED state
  token.
- RefreshToken: after the user is loaded, before the refresh token is
  consumed, so no new token pair is issued.
- VerifyFactor: after the user is loaded, before 2FA completes.

All three return 403 with an identical message so the response does not
reveal which check fired. Document the 403 on the Login endpoint and
regenerate the Swagger definitions.

Tests: Login suspended cases (403, no Set-Cookie, no MFA_REQUIRED leak)
as a struct table; unit coverage of the RefreshToken and VerifyFactor
paths (TestAuthenticationController_SuspendedAccountCannotMintTokens);
and an integration test that creates a suspended user and asserts Login
returns 403.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 4 complexity · 0 duplication

Metric Results
Complexity 4
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant