fix(auth): honour an approval granted before sign-up instead of parking the account
Follow-up to the commit fix, from the deep-review. Persisting the account was only half the story: when the admin had approved the address BEFORE the person registered, the account landed is_active=False against an invite that is no longer pending — absent from the Access-requests queue, and approve_invite 409s on an already-decided invite. The sign-up worked and still could not sign in. Derive activation from is_allowed() at the moment ownership is attested: - verify_email_confirm activates a pre-approved account when the emailed link is confirmed (only the mailbox owner can follow it), so SEC-10 stays intact; - _register_account activates only when there is no SMTP to verify with, where the admin whitelist is by design the sole gate — the same one add_invite already activates on. Tests: the pre-approved no-SMTP case and the verify-activates case are real regression tests (both fail without this change); guards cover the unknown-email and denied->pending branches, verification of an unapproved account, and the first end-to-end coverage of the /auth/register route and its allow_registration gate. Release notes rewritten — the previous entry miscounted its regression tests and advertised an email fix this release has no code for.
This commit is contained in:
@@ -637,6 +637,15 @@ def _register_account(email: str, password: str) -> None:
|
||||
db.rollback()
|
||||
return
|
||||
upsert_pending_invite(db, email) # admin-approval gate (commits only when it writes a row)
|
||||
# Honour an approval the admin had ALREADY given for this address. Without this the account
|
||||
# lands is_active=False against a non-pending invite: it never shows up in the Access-requests
|
||||
# queue (which lists pending only) and approve_invite 409s on an already-decided invite, so
|
||||
# the admin has no obvious way to let the person in. Attestation still gates it — with SMTP on
|
||||
# the address is unverified at this point, so activation waits for the verify link (see
|
||||
# verify_email_confirm). With no SMTP there is no attestation to wait for and the admin's
|
||||
# whitelist is by design the only gate, the very one add_invite already activates on.
|
||||
if not email_ok and is_allowed(db, email):
|
||||
user.is_active = True
|
||||
# Persist the account ourselves. upsert_pending_invite commits only when it actually inserts
|
||||
# (or revives) an invite row, and _issue_token below only runs with SMTP on — so for an email
|
||||
# the admin had ALREADY approved, on an instance with no SMTP, nothing along this path
|
||||
@@ -663,6 +672,12 @@ def verify_email_confirm(body: TokenIn, db: Session = Depends(get_db)) -> dict:
|
||||
status_code=400, detail="This verification link is invalid or has expired."
|
||||
)
|
||||
user.email_verified = True
|
||||
# Ownership is attested now (only the mailbox owner can follow this link), so an approval the
|
||||
# admin granted BEFORE the person signed up can finally be honoured. Otherwise they sit at
|
||||
# is_active=False behind a request no admin screen shows — the invite is already decided, so it
|
||||
# is absent from the pending queue and approve_invite would 409 on it.
|
||||
if not user.is_active and is_allowed(db, user.email):
|
||||
user.is_active = True
|
||||
db.commit()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user