3.8 KiB
MFA lifecycle repairs — October 20, 2026
Repairs the two confirmed MFA findings in the readiness review.
Authenticator replacement
Starting replacement requires the current password and an unused authenticator or recovery code. The existing factor and all remaining recovery codes stay active. A ten-minute replacement grant holds the new secret in the authorized server-side session and binds it to the account version and existing factor. The page offers a QR code, manual setup key and cancellation.
Confirmation requires the password again and a valid code from the new device. One transaction locks the account and factor, checks authorization, replaces the encrypted secret, generates ten fresh recovery codes, increments the session version and writes the mandatory audit entry. Other sessions and old recovery codes are revoked only when this transaction commits. The confirmation code is recorded as consumed so it cannot immediately be replayed.
Cancellation, expiration, incorrect credentials and audit failure leave the existing factor intact. Password resets preserve MFA and invalidate the pending session. Competing confirmations cannot both succeed. Signing in clears any previous pending replacement from that session.
Password and code verification
MFA verification checks the current password, active account, session identity and account version under the account lock before consuming an authenticator time step or recovery code. Every mutation follows the account-then-factor lock order, with consumption and mandatory audit committed together. Existing attempt limits continue to apply. The verification API requires the password explicitly.
Security notifications
Email notices use the account address read under the account lock. Events cover initial enrollment, replacement requested, replacement completed and recovery code use. Recovery-authorized replacement sends one combined request/recovery notice. Notices identify the account and UTC time and explain what to do if the activity was unauthorized. They contain no passwords, setup secrets, provisioning links or recovery codes.
Delivery uses the existing SMTP configuration after the security transaction commits. Failed or rolled-back actions send no success notice. A delivery failure does not undo the security change: it produces a visible warning and a log entry containing the account ID and event type. Delivery is best effort, without a new queue or automatic retry; production SMTP/inbox delivery and failure monitoring still need deployment acceptance.
Validation and deployment
New regressions cover 24 HTTP lifecycle assertions, 24 notification assertions and two concurrent database races. Existing MFA capacity and QR scanning tests were updated for explicit replacement confirmation and password-required verification. The release packaging test requires the notification class. All tests use disposable local databases and generated accounts; notification tests capture messages or deliberately disable SMTP. No real account password, MFA factor or recovery codes are changed, and no test email is sent externally.
No database migration, encryption-key change or administrator re-enrollment is
required. Deploy classes/MfaSecurityNotifications.php before the updated
MfaService.php, AuthService.php and Roster.php.
Completed validation: the full suite passed 743 checks and 12 concurrency scenarios. Source validation passed for 65 PHP files, 57 JavaScript files and 39 XSL stylesheets. The four application files were deployed to ositsdevels and their hashes verified. A temporary protected runtime check confirmed the password-required verification API, replacement methods, notification class and working server-side encryption key; the probe was removed immediately afterward. No development database records were changed.