# 3. Two-Factor Authentication — Test Cases

User Type: **Super Administrator**
Source: *Mi Digital Academy - Education CRM Features Document*
Spec: two_factor_authentication.md — every feature, sub-feature, and rule covered

---

## Test Execution Policy
- Zero tolerance: any deviation from documented behavior = FAILED = bug
- Every bug is immediately logged/reported (Bug ID, feature, sub-feature, expected vs actual, severity) and fixed 100% before the group passes
- Feature group passes only at 100% test pass rate

## Coverage Matrix
| Feature | Sub-feature / Rule | Test IDs |
|---------|--------------------|----------|
| 3.1 2FA Setup and Management | Enrollment flow: choose channel, register, confirm | TC-SA-01-03-001 |
| 3.1 2FA Setup and Management | Authenticator app support (QR + manual secret, time-sync) | TC-SA-01-03-002, TC-SA-01-03-003 |
| 3.1 2FA Setup and Management | SMS/email OTP channel bound to verified contact | TC-SA-01-03-004 |
| 3.1 2FA Setup and Management | Backup codes generated, shown once, downloadable | TC-SA-01-03-005 |
| 3.1 2FA Setup and Management | Enrollment complete only after successful confirmation | TC-SA-01-03-006 |
| 3.1 2FA Setup and Management | Management screen: view, add, replace, revoke channels | TC-SA-01-03-007, TC-SA-01-03-008, TC-SA-01-03-009 |
| 3.1 2FA Setup and Management | Policy configuration: mandatory per role, optional others | TC-SA-01-03-010 |
| 3.1 2FA Setup and Management | Guided enrollment at login for mandatory-role unenrolled | TC-SA-01-03-011 |
| 3.1 2FA Setup and Management | Admin enforcement: force-enable, reset | TC-SA-01-03-012, TC-SA-01-03-013 |
| 3.1 2FA Setup and Management | Adoption reporting | TC-SA-01-03-014 |
| 3.1 2FA Setup and Management | Full audit logging of enrollment, channel, policy changes | TC-SA-01-03-015 |
| 3.1 2FA Setup and Management | Rule: enrollment incomplete until test code verified | TC-SA-01-03-016 |
| 3.1 2FA Setup and Management | Rule: no half-enrolled state; failed confirmation discards channel | TC-SA-01-03-017 |
| 3.1 2FA Setup and Management | Rule: backup codes shown once, only hashed stored | TC-SA-01-03-018 |
| 3.1 2FA Setup and Management | Rule: lost channel → re-enroll after identity re-verification | TC-SA-01-03-019 |
| 3.1 2FA Setup and Management | Rule: mandatory policy blocks login completion, guided flow | TC-SA-01-03-020 |
| 3.1 2FA Setup and Management | Rule: channel change/revoke requires current 2FA challenge | TC-SA-01-03-021 |
| 3.1 2FA Setup and Management | Rule: all changes audit-logged with actor and timestamp | TC-SA-01-03-022 |
| 3.2 OTP-Based Second Factor | TOTP verification with 30s window and skew tolerance | TC-SA-01-03-023, TC-SA-01-03-024 |
| 3.2 OTP-Based Second Factor | SMS/email OTP with validity window | TC-SA-01-03-025 |
| 3.2 OTP-Based Second Factor | Entry screen: auto-advance, paste, expiry countdown | TC-SA-01-03-026, TC-SA-01-03-027 |
| 3.2 OTP-Based Second Factor | Attempt limit invalidates challenge | TC-SA-01-03-028 |
| 3.2 OTP-Based Second Factor | Resend (delivery channels) with cooldown and maximum | TC-SA-01-03-029 |
| 3.2 OTP-Based Second Factor | Trusted-device skip for a trust window | TC-SA-01-03-030 |
| 3.2 OTP-Based Second Factor | Backup code fallback, single-use | TC-SA-01-03-031 |
| 3.2 OTP-Based Second Factor | Exhausted-recovery path blocks login | TC-SA-01-03-032 |
| 3.2 OTP-Based Second Factor | Full logging of all challenge events | TC-SA-01-03-033 |
| 3.2 OTP-Based Second Factor | Rule: TOTP single-use per window, skew tolerance only | TC-SA-01-03-034 |
| 3.2 OTP-Based Second Factor | Rule: delivery OTPs single-use, expire with expired message | TC-SA-01-03-035 |
| 3.2 OTP-Based Second Factor | Rule: five wrong entries invalidate challenge | TC-SA-01-03-036 |
| 3.2 OTP-Based Second Factor | Rule: low backup-code count prompts regeneration | TC-SA-01-03-037 |
| 3.2 OTP-Based Second Factor | Rule: trusted-device skip role-gated | TC-SA-01-03-038 |
| 3.2 OTP-Based Second Factor | Rule: exhausted options → support-assisted recovery only | TC-SA-01-03-039 |
| 3.2 OTP-Based Second Factor | Rule: challenge events logged; code values never logged | TC-SA-01-03-040 |
| 3.3 Per-User 2FA Enable/Disable | Self-service 2FA toggle in profile settings | TC-SA-01-03-041 |
| 3.3 Per-User 2FA Enable/Disable | Identity re-verification to disable | TC-SA-01-03-042 |
| 3.3 Per-User 2FA Enable/Disable | Policy override: mandatory roles cannot self-disable | TC-SA-01-03-043 |
| 3.3 Per-User 2FA Enable/Disable | Admin force-enable | TC-SA-01-03-044 |
| 3.3 Per-User 2FA Enable/Disable | Admin reset with support-assisted verification | TC-SA-01-03-045 |
| 3.3 Per-User 2FA Enable/Disable | Admin view of any user's 2FA status without secrets | TC-SA-01-03-046 |
| 3.3 Per-User 2FA Enable/Disable | Notification to user on admin 2FA change | TC-SA-01-03-047 |
| 3.3 Per-User 2FA Enable/Disable | Audit logging of all actions with actor, target, reason | TC-SA-01-03-048 |
| 3.3 Per-User 2FA Enable/Disable | Rule: disable requires password + passing 2FA challenge | TC-SA-01-03-049 |
| 3.3 Per-User 2FA Enable/Disable | Rule: mandatory-role toggle greyed out with explanation | TC-SA-01-03-050 |
| 3.3 Per-User 2FA Enable/Disable | Rule: reset clears all channels and backup codes | TC-SA-01-03-051 |
| 3.3 Per-User 2FA Enable/Disable | Rule: admin actions require recorded reason, audit-logged | TC-SA-01-03-052 |
| 3.3 Per-User 2FA Enable/Disable | Rule: user always notified of admin 2FA changes | TC-SA-01-03-053 |
| 3.3 Per-User 2FA Enable/Disable | Rule: status visible to admins, secrets never exposed | TC-SA-01-03-054 |

## 3.1 2FA Setup and Management

### TC-SA-01-03-001 — Enrollment flow: choose channel, register, confirm
**Type:** Positive
**Covers:** 3.1 → Enrollment flow
**Preconditions:** A user account without 2FA; access to the enrollment screen.
**Steps:**
1. Open the 2FA enrollment screen.
2. Choose a channel (authenticator app or SMS/email).
3. Register the channel (scan QR / enter secret, or bind the verified contact).
4. Enter the test confirmation code from the new channel.
**Expected Result:** The channel is registered; the test code is accepted; 2FA is marked active; the enrollment is complete and logged; the user is returned to the management screen showing the active channel.
**Priority:** Critical

### TC-SA-01-03-002 — Authenticator app enrollment via QR code
**Type:** Positive
**Covers:** 3.1 → Authenticator app support: QR code
**Preconditions:** A TOTP authenticator app on a test device; the enrollment screen.
**Steps:**
1. Choose the authenticator app channel.
2. Scan the displayed QR code with the app.
3. Enter the 6-digit code the app generates as the test code.
**Expected Result:** The QR code encodes the TOTP secret correctly (the app shows a working code for the account); the generated code is accepted as the confirmation; the channel is active; time-sync guidance is available if the code is rejected for drift.
**Priority:** High

### TC-SA-01-03-003 — Authenticator app enrollment via manual secret entry
**Type:** Positive
**Covers:** 3.1 → Authenticator app support: manual secret entry
**Preconditions:** A TOTP authenticator app; the enrollment screen showing the manual secret.
**Steps:**
1. Choose the authenticator app channel.
2. Manually enter the displayed secret into the app.
3. Enter the app's generated code as the test code.
**Expected Result:** The manual secret matches the QR-encoded secret (both produce the same codes); the generated code is accepted; the channel is active; the manual path is functionally identical to the QR path.
**Priority:** Medium

### TC-SA-01-03-004 — SMS/email OTP channel bound to verified contact
**Type:** Positive
**Covers:** 3.1 → SMS/email OTP channel bound to the user's verified phone/email
**Preconditions:** A user with a verified phone and/or email; the enrollment screen.
**Steps:**
1. Choose the SMS/email OTP channel.
2. Observe which contact is bound (the verified phone/email).
3. Complete the test-code confirmation via the delivered OTP.
**Expected Result:** The channel is bound to the user's verified phone/email (not an arbitrary one); the test OTP is delivered to that verified contact; the channel is active after confirmation; an unverified contact cannot be used for this channel.
**Priority:** High

### TC-SA-01-03-005 — Backup codes generated, shown once, downloadable
**Type:** Positive
**Covers:** 3.1 → Backup codes
**Preconditions:** A 2FA enrollment in progress.
**Steps:**
1. Complete the enrollment to the backup-codes step.
2. Observe the displayed set of single-use recovery codes.
3. Download the codes.
4. Attempt to view the codes again later (profile/management screen).
**Expected Result:** A set of single-use recovery codes is generated and displayed exactly once at enrollment; they are downloadable; they cannot be re-displayed later (the system stores only their hashed form); the download and generation are logged.
**Priority:** High

### TC-SA-01-03-006 — Enrollment active only after successful confirmation
**Type:** Negative
**Covers:** 3.1 → Enrollment completion: active only after a successful confirmation code
**Preconditions:** A 2FA enrollment in progress; a wrong test code available.
**Steps:**
1. Register the channel but enter a wrong test confirmation code.
2. Observe the 2FA state on the account.
**Expected Result:** 2FA is NOT marked active; the enrollment is incomplete; the account's login behavior is unchanged (no second factor required yet); the failed confirmation is logged; the channel is not retained as active.
**Priority:** Critical

### TC-SA-01-03-007 — Management screen shows enrolled channels
**Type:** Positive
**Covers:** 3.1 → Management screen: view enrolled channels
**Preconditions:** An account with one or more enrolled 2FA channels.
**Steps:**
1. Open the 2FA management screen.
2. Verify the listed channels and their states.
**Expected Result:** All enrolled channels are listed with their type and active state; the display matches the actual enrollment; no secrets are shown.
**Priority:** Medium

### TC-SA-01-03-008 — Add a second channel
**Type:** Positive
**Covers:** 3.1 → Management screen: add a second channel
**Preconditions:** An account with one active channel; the current 2FA challenge passable.
**Steps:**
1. Open the management screen and select "Add channel".
2. Pass the current 2FA challenge.
3. Register and confirm the second channel.
**Expected Result:** The second channel is added after passing the current challenge; both channels are listed as active; the addition is audit-logged; login can use either channel.
**Priority:** High

### TC-SA-01-03-009 — Replace a lost channel with identity + current 2FA verification
**Type:** Edge
**Covers:** 3.1 → Management screen: replace a lost channel
**Preconditions:** An account whose primary channel is lost; a remaining backup code or support-assisted path available.
**Steps:**
1. Initiate a channel replacement.
2. Complete identity re-verification (password + backup code, or support-assisted verification).
3. Register and confirm the new channel.
4. Verify the old channel is revoked.
**Expected Result:** The replacement is allowed only after identity re-verification; the new channel is active; the lost/old channel is revoked; the replacement is audit-logged with the verification method.
**Priority:** High

### TC-SA-01-03-010 — Policy configuration: mandatory per role, optional for others
**Type:** Positive
**Covers:** 3.1 → Policy configuration
**Preconditions:** Super Admin access to System Settings → Security Policy → Two-Factor Authentication.
**Steps:**
1. Open the 2FA policy screen.
2. Set 2FA mandatory for selected roles (e.g., all admin and staff roles) and optional for others.
3. Save and verify the policy state.
**Expected Result:** The mandatory/optional designation per role is configurable and saved; the policy is visible on the screen; the change is audit-logged; the policy takes effect for login enforcement (see TC-SA-01-03-011/020).
**Priority:** Critical

### TC-SA-01-03-011 — Guided enrollment at login for mandatory-role unenrolled user
**Type:** Positive
**Covers:** 3.1 → Guided enrollment at login
**Preconditions:** A mandatory-2FA role; a user in that role who has not enrolled; valid credentials.
**Steps:**
1. Log in as the unenrolled mandatory-role user.
2. Observe the screen after password verification.
3. Complete the guided enrollment and finish the login.
**Expected Result:** Login does not dead-end; it presents the guided enrollment flow with clear steps; after enrollment completes, the login continues and the session is established; the enrollment and login are logged.
**Priority:** Critical

### TC-SA-01-03-012 — Admin force-enable 2FA for a user
**Type:** Positive
**Covers:** 3.1 → Admin enforcement: force-enable
**Preconditions:** A user of a mandatory role who has not enrolled; Super Admin access to the user record.
**Steps:**
1. Perform "Force-enable 2FA" on the user's record.
2. Have the user log in.
3. Observe the login behavior.
**Expected Result:** The force-enable is recorded; the user's next login is paused at the guided enrollment step until they complete it; the action is audit-logged with actor and reason; the user is notified.
**Priority:** High

### TC-SA-01-03-013 — Admin reset a user's 2FA enrollment
**Type:** Edge
**Covers:** 3.1 → Admin enforcement: reset enrollment
**Preconditions:** A user who cannot self-recover (lost channel and backup codes); a support request; support-assisted identity verification available.
**Steps:**
1. Complete the support-assisted identity verification for the user.
2. Perform "Reset 2FA" on the user's record with a reason.
3. Have the user log in and re-enroll.
**Expected Result:** The reset clears the user's channels and backup codes; the user is notified; at next login the guided enrollment presents automatically; the user re-enrolls successfully; the reset (actor, reason, timestamp) and the re-enrollment are audit-logged.
**Priority:** High

### TC-SA-01-03-014 — Adoption reporting: platform-wide and per-role
**Type:** Positive
**Covers:** 3.1 → Adoption reporting
**Preconditions:** Users enrolled and not enrolled across roles; Super Admin access to the adoption report.
**Steps:**
1. Open the 2FA adoption report.
2. Verify the platform-wide enrollment percentage.
3. Verify the per-role percentages and the list of mandatory-role users not yet enrolled.
4. Verify the recent enrollment activity.
**Expected Result:** The report shows platform-wide and per-role enrollment percentages matching the actual data; the pending list shows exactly the mandatory-role users not enrolled; recent enrollment activity is listed; the report is refreshable.
**Priority:** Medium

### TC-SA-01-03-015 — Audit logging of enrollment, channel, and policy changes
**Type:** Positive
**Covers:** 3.1 → Full audit logging
**Preconditions:** Enrollment, channel-change, and policy-change events produced; audit log access.
**Steps:**
1. Produce an enrollment, a channel change, and a policy change.
2. Locate all three in the audit log.
3. Inspect actor and timestamp on each.
**Expected Result:** All three event types are audit-logged with actor and timestamp; enrollments show the user, channel type, and confirmation success; the log is exportable.
**Priority:** High

### TC-SA-01-03-016 — Enrollment not complete until test code verified
**Type:** Negative
**Covers:** 3.1 → Rule: enrollment incomplete until the user verifies a test code
**Preconditions:** A 2FA enrollment where the channel is registered but the test code is not yet entered.
**Steps:**
1. Register the channel and stop before entering the test code.
2. Check the account's 2FA state.
3. Attempt a login and observe whether a second factor is required.
**Expected Result:** The 2FA state is not active; login does not require a second factor; the enrollment is in a pending/incomplete state; no partial enforcement occurs.
**Priority:** Critical

### TC-SA-01-03-017 — Failed confirmation discards the channel (no half-enrolled state)
**Type:** Negative
**Covers:** 3.1 → Rule: no half-enrolled state; failed confirmation discards the channel
**Preconditions:** A 2FA enrollment in progress; a wrong test code.
**Steps:**
1. Register the channel and enter a wrong test code.
2. Check the management screen for the channel.
3. Attempt to resume the same enrollment without redoing it.
**Expected Result:** The channel is discarded (not listed as active or pending-active); there is no "half-enrolled" state; enrollment must be redone from the start; the failed attempt is logged.
**Priority:** High

### TC-SA-01-03-018 — Backup codes shown exactly once; only hashed stored
**Type:** Negative
**Covers:** 3.1 → Rule: backup codes displayed once; system stores only hashed form
**Preconditions:** A completed enrollment with backup codes generated.
**Steps:**
1. After enrollment, attempt to re-view the backup codes in the UI.
2. Inspect the stored form of the backup codes (admin/system view).
**Expected Result:** The codes cannot be re-displayed in any UI (shown exactly once at enrollment); the stored form is hashed (the plaintext codes are not retrievable from any admin or system view); the one-time display is logged.
**Priority:** Critical

### TC-SA-01-03-019 — Lost channel requires identity re-verification to re-enroll
**Type:** Edge
**Covers:** 3.1 → Rule: lost channel → re-enroll after identity re-verification
**Preconditions:** A user whose channel is lost (phone changed/app wiped); no remaining backup code (support-assisted path).
**Steps:**
1. Initiate re-enrollment after the loss.
2. Complete identity re-verification (support-assisted, since no backup code remains).
3. Enroll the new channel and confirm.
**Expected Result:** Re-enrollment is gated behind identity re-verification (password + backup code, or support-assisted); the new channel is active after confirmation; the old channel is gone; the re-enrollment and verification are audit-logged.
**Priority:** High

### TC-SA-01-03-020 — Mandatory policy blocks login completion for unenrolled users
**Type:** Negative
**Covers:** 3.1 → Rule: mandatory policy blocks login completion, presenting guided enrollment
**Preconditions:** A mandatory-2FA role; an unenrolled user in that role.
**Steps:**
1. Log in as the unenrolled user with correct credentials.
2. Observe whether the login can complete without enrollment.
3. Verify the guided enrollment is the only path forward.
**Expected Result:** The login cannot complete without enrollment (no session is established); the guided enrollment flow is presented (not a dead end); completing enrollment allows the login to finish; the block and enrollment are logged.
**Priority:** Critical

### TC-SA-01-03-021 — Channel change/revoke requires passing the current 2FA challenge
**Type:** Negative
**Covers:** 3.1 → Rule: changing/revoking a channel requires the current 2FA challenge
**Preconditions:** An account with an active channel; a session without a recent 2FA challenge pass.
**Steps:**
1. Attempt to revoke the active channel without passing the current 2FA challenge.
2. Attempt to swap in a different channel without the challenge.
3. Pass the current challenge and repeat the revoke.
**Expected Result:** Both the revoke and the swap are blocked until the current 2FA challenge is passed (preventing an attacker from swapping in their own channel); after passing the challenge the action succeeds; all attempts are audit-logged.
**Priority:** Critical

### TC-SA-01-03-022 — All 2FA changes audit-logged with actor and timestamp
**Type:** Positive
**Covers:** 3.1 → Rule: enrollment, channel-change, and policy changes audit-logged
**Preconditions:** Enrollment, channel-change, and policy-change events produced; audit log access.
**Steps:**
1. Produce each event type.
2. Inspect each audit entry's actor and timestamp.
**Expected Result:** Every entry records the actor (user or admin) and an accurate timestamp; no entry lacks either field; the entries are exportable for the security audit.
**Priority:** High

## 3.2 OTP-Based Second Factor

### TC-SA-01-03-023 — TOTP verification within the 30-second window
**Type:** Positive
**Covers:** 3.2 → TOTP verification: 6-digit code valid for a 30-second window
**Preconditions:** An account enrolled with an authenticator app; valid credentials.
**Steps:**
1. Log in and reach the second-factor step.
2. Enter the current 6-digit TOTP code from the app.
3. Observe the verification and redirect.
**Expected Result:** The current-window code is accepted; the session is established; the user is redirected to their panel; the verification is logged.
**Priority:** Critical

### TC-SA-01-03-024 — TOTP skew tolerance for clock drift
**Type:** Edge
**Covers:** 3.2 → TOTP skew tolerance (±1 window) for clock drift
**Preconditions:** An authenticator device with a small clock drift (within ±1 window); valid credentials.
**Steps:**
1. Log in and reach the second-factor step.
2. Enter the code from the drifted device (previous or next window within the tolerance).
3. Observe the verification.
**Expected Result:** A code within the ±1 window skew tolerance is accepted (clock drift handled); a code outside the tolerance (older than ±1 window) is rejected; both outcomes are logged.
**Priority:** High

### TC-SA-01-03-025 — SMS/email OTP second factor with validity window
**Type:** Positive
**Covers:** 3.2 → SMS/email OTP: 6-digit code with validity window
**Preconditions:** An account enrolled with an SMS/email delivery channel; valid credentials.
**Steps:**
1. Log in and reach the second-factor step.
2. Receive the 6-digit OTP on the enrolled channel.
3. Enter it within the validity window.
**Expected Result:** The OTP is delivered to the enrolled channel; the entry screen shows the validity countdown; the code verifies within the window; the session is established; the verification is logged.
**Priority:** Critical

### TC-SA-01-03-026 — Second-factor entry screen: auto-advance and paste
**Type:** Positive
**Covers:** 3.2 → Entry screen: auto-advance digit fields, paste support
**Preconditions:** A second-factor challenge presented; a valid code available.
**Steps:**
1. Type the code digit by digit; observe focus movement.
2. Clear the fields, then paste the full code.
3. Submit in both cases.
**Expected Result:** Focus auto-advances per digit; backspace moves back; pasting distributes the digits correctly; both entry methods verify successfully; the entry screen shows a clear expiry countdown.
**Priority:** Medium

### TC-SA-01-03-027 — Expiry countdown shown on the entry screen
**Type:** Positive
**Covers:** 3.2 → Entry screen: clear expiry countdown
**Preconditions:** A second-factor challenge presented (delivery channel).
**Steps:**
1. Observe the entry screen from the moment the challenge appears.
2. Watch the countdown through the validity window.
**Expected Result:** A clear expiry countdown is visible from the start of the challenge; it ticks in real time and reaches zero at the window end; the user can always tell when to resend.
**Priority:** Medium

### TC-SA-01-03-028 — Attempt limit invalidates the current challenge
**Type:** Negative
**Covers:** 3.2 → Attempt limit: fixed number of wrong entries invalidates the challenge
**Preconditions:** A second-factor challenge presented; the documented limit known (e.g., 5).
**Steps:**
1. Enter wrong codes until the limit is reached, reading the message each time.
2. Observe the challenge state after the limit.
3. Start a new login attempt and observe the fresh challenge.
**Expected Result:** Each wrong entry decrements the visible count; after the limit the current challenge is invalidated; the login is blocked for that attempt with a "try again with a new code" message; a new login attempt issues a fresh challenge; all attempts are logged.
**Priority:** Critical

### TC-SA-01-03-029 — Resend for delivery channels with cooldown and maximum
**Type:** Positive
**Covers:** 3.2 → Resend (delivery channels only) with cooldown and maximum per login
**Preconditions:** A delivery-channel second-factor challenge; cooldown and maximum known.
**Steps:**
1. Observe the resend control state (disabled during cooldown with countdown).
2. Resend after the cooldown.
3. Resend until the per-login maximum; attempt one more.
**Expected Result:** Resend is available only for delivery channels (not for TOTP); the cooldown disables the control with a countdown; resends succeed after it; the per-login maximum caps resends; all resends are logged.
**Priority:** High

### TC-SA-01-03-030 — Trusted-device skip for a trust window
**Type:** Positive
**Covers:** 3.2 → Trusted-device option: skip the second factor for a trust window
**Preconditions:** A role where trusted-device skip is allowed by policy; a new device.
**Steps:**
1. Log in from the new device and complete password + second factor.
2. Accept the "Trust this device for 30 days?" offer.
3. Log out and log in again from the same device within the window.
4. Inspect the session view for the trust record.
**Expected Result:** The trust offer is presented after a successful second factor; within the 30-day window, logins from that device skip the second factor; the trust is recorded and visible in the session view; the skip is logged.
**Priority:** High

### TC-SA-01-03-031 — Backup code accepted when primary channel unavailable
**Type:** Edge
**Covers:** 3.2 → Fallback: backup codes accepted; each single-use
**Preconditions:** An account whose primary channel is unavailable (lost phone); remaining backup codes.
**Steps:**
1. Log in and reach the second-factor step.
2. Enter a backup code instead of a channel code.
3. Observe the acceptance and the remaining-code count.
4. Reuse the same backup code in a later login.
**Expected Result:** The backup code is accepted and marked used; the remaining-code count drops; the reused code is rejected (single-use); the usage is logged.
**Priority:** Critical

### TC-SA-01-03-032 — Exhausted-recovery path blocks login
**Type:** Edge
**Covers:** 3.2 → Exhausted-recovery path: all options fail → login blocked, support-assisted recovery
**Preconditions:** An account with no available channel and no remaining backup codes.
**Steps:**
1. Log in and reach the second-factor step.
2. Exhaust all options (no channel code, no backup code).
3. Observe the login state and the offered path.
**Expected Result:** The login is blocked (no session established); the support-assisted recovery path is presented (identity verification by support); no self-service bypass exists; the block and recovery request are logged.
**Priority:** Critical

### TC-SA-01-03-033 — All 2FA challenge events logged
**Type:** Positive
**Covers:** 3.2 → Full logging: issued, verified, failed, expired, skipped
**Preconditions:** Scenarios producing each event type; log access.
**Steps:**
1. Produce an issuance, a successful verification, a failure, an expiry, and a trusted-device skip.
2. Locate all five events in the 2FA event log.
3. Inspect status, channel, and timestamp on each.
**Expected Result:** All five event types are present with status, channel, and timestamp; the trusted-device skip is explicitly recorded; the sequence matches the actual operations.
**Priority:** High

### TC-SA-01-03-034 — TOTP code single-use per window; skew tolerance only
**Type:** Negative
**Covers:** 3.2 → Rule: TOTP single-use per window; previous window accepted only within skew
**Preconditions:** An authenticator account; a code from the previous window.
**Steps:**
1. Verify a current-window code successfully.
2. Immediately attempt to reuse a code from outside the ±1 window skew.
3. Observe the rejection.
**Expected Result:** A code outside the current window and the ±1 skew tolerance is rejected; the single-use-per-window behavior holds; the rejection is logged; only within-tolerance codes are accepted.
**Priority:** High

### TC-SA-01-03-035 — Delivery OTP single-use and expiring with expired message
**Type:** Negative
**Covers:** 3.2 → Rule: delivery OTPs single-use, expire with "expired" message + resend
**Preconditions:** A delivery-channel OTP that has been verified once; a separate expired OTP.
**Steps:**
1. Attempt to reuse the verified OTP in a new login.
2. Submit an expired OTP.
3. Observe both rejections and the resend option.
**Expected Result:** The reused OTP is rejected (single-use); the expired OTP is rejected with the specific "expired" message and a resend option (not a generic error); both are logged.
**Priority:** High

### TC-SA-01-03-036 — Five wrong entries invalidate the challenge
**Type:** Negative
**Covers:** 3.2 → Rule: five wrong entries invalidate the current challenge
**Preconditions:** A second-factor challenge; the limit = 5.
**Steps:**
1. Enter 5 wrong codes, reading the counter each time.
2. Enter the correct code after the 5th wrong entry.
**Expected Result:** The counter decrements 4→3→2→1→0; after the 5th wrong entry the challenge is invalidated; the correct code is now rejected; a new login attempt issues a fresh challenge; all entries are logged.
**Priority:** Critical

### TC-SA-01-03-037 — Low backup-code count prompts regeneration
**Type:** Edge
**Covers:** 3.2 → Rule: remaining count low (≤2) prompts regeneration (requires a 2FA challenge)
**Preconditions:** An account with 2 or fewer remaining backup codes.
**Steps:**
1. Log in and complete a second-factor verification.
2. Observe the low-count prompt.
3. Pass a 2FA challenge and regenerate the set.
4. Verify the old codes are invalidated and the new set is shown once.
**Expected Result:** When the remaining count is ≤2, the user is prompted to regenerate; regeneration requires passing a 2FA challenge; the new set is shown exactly once (hashed stored); the old codes stop working; the regeneration is logged.
**Priority:** High

### TC-SA-01-03-038 — Trusted-device skip is role-gated
**Type:** Negative
**Covers:** 3.2 → Rule: trusted-device skip role-gated; privileged roles may be excluded
**Preconditions:** A privileged role excluded from trusted-device skip by policy; a new device.
**Steps:**
1. Log in from the new device as the privileged-role user.
2. Observe whether the trust offer is presented.
3. Log out and log in again from the same device.
**Expected Result:** No trust offer is presented for the excluded role; the second factor is required at every login from any device; the role-gating matches the policy; the enforced second factors are logged.
**Priority:** Critical

### TC-SA-01-03-039 — Exhausted options allow only support-assisted recovery
**Type:** Negative
**Covers:** 3.2 → Rule: all recovery exhausted → only support-assisted recovery restores access
**Preconditions:** An account with no channel and no backup codes.
**Steps:**
1. Attempt every self-service recovery option.
2. Observe that all are unavailable/exhausted.
3. Complete the support-assisted recovery (identity verification by support).
4. Verify access is restored.
**Expected Result:** No self-service path restores access when all options are exhausted; only the support-assisted recovery (with identity verification by support) restores access; the exhaustion and the recovery are logged.
**Priority:** Critical

### TC-SA-01-03-040 — 2FA code values never logged
**Type:** Positive
**Covers:** 3.2 → Rule: challenge events logged; code values never logged
**Preconditions:** Multiple 2FA challenge events produced; log access.
**Steps:**
1. Produce several challenge events (TOTP and delivery).
2. Search the full text of the 2FA/security logs for any 6-digit code values.
3. Inspect the recorded fields of each event.
**Expected Result:** No log entry contains an actual code value; each entry records only the event status, channel, and timestamp; a full log review reveals zero code values.
**Priority:** Critical

## 3.3 Per-User 2FA Enable/Disable

### TC-SA-01-03-041 — Self-service 2FA toggle in profile settings
**Type:** Positive
**Covers:** 3.3 → Self-service 2FA toggle in profile settings (Security section)
**Preconditions:** A user account in a role where 2FA is optional; profile settings access.
**Steps:**
1. Open profile settings → Security.
2. Observe the 2FA toggle state.
3. Toggle 2FA on (complete enrollment) and verify the state.
**Expected Result:** The toggle is present and reflects the actual 2FA state; toggling on starts the enrollment flow; after completion the toggle shows enabled; the change is logged.
**Priority:** High

### TC-SA-01-03-042 — Disabling requires identity re-verification
**Type:** Positive
**Covers:** 3.3 → Identity re-verification required to disable
**Preconditions:** An account with 2FA enabled; a session in profile settings.
**Steps:**
1. Toggle 2FA off in profile settings.
2. Complete the current password prompt.
3. Complete the passing 2FA challenge.
4. Verify the 2FA state.
**Expected Result:** Disabling requires BOTH the current password AND a passing 2FA challenge; only after both is 2FA disabled; the state updates; the disable is audit-logged.
**Priority:** Critical

### TC-SA-01-03-043 — Mandatory-role users cannot self-disable
**Type:** Negative
**Covers:** 3.3 → Policy override: mandatory roles cannot self-disable
**Preconditions:** A user in a mandatory-2FA role with 2FA enabled.
**Steps:**
1. Open profile settings → Security as the mandatory-role user.
2. Observe the disable toggle.
3. Attempt to disable 2FA.
**Expected Result:** The disable toggle is shown disabled (greyed out) with the explanation "Two-factor authentication is required for your role"; the self-disable is impossible; any attempt is blocked and logged.
**Priority:** Critical

### TC-SA-01-03-044 — Admin force-enable 2FA for a user
**Type:** Positive
**Covers:** 3.3 → Admin action: force-enable
**Preconditions:** A user of a mandatory role who has not enrolled; Super Admin access.
**Steps:**
1. Perform "Force-enable 2FA" on the user's record with a reason.
2. Have the user log in.
3. Observe the guided enrollment and completion.
**Expected Result:** The force-enable is recorded with actor and reason; the user's next login is paused at the guided enrollment step; after enrollment the login completes; the user is notified; the action is audit-logged.
**Priority:** High

### TC-SA-01-03-045 — Admin reset with support-assisted identity verification
**Type:** Edge
**Covers:** 3.3 → Admin action: reset enrollment with support-assisted verification
**Preconditions:** A user who cannot self-recover; a support request; Super Admin access.
**Steps:**
1. Confirm the account identity through the support-assisted verification process (registered details + OTP to the registered phone).
2. Perform "Reset 2FA" with a recorded reason.
3. Verify the channels and backup codes are cleared.
4. Have the user re-enroll at next login.
**Expected Result:** The reset is allowed only after the support-assisted identity verification; all channels and backup codes are cleared; the user is notified; the guided enrollment presents at next login; the reset (actor, reason, timestamp) and re-enrollment are audit-logged.
**Priority:** Critical

### TC-SA-01-03-046 — Admin view of any user's 2FA status without secrets
**Type:** Positive
**Covers:** 3.3 → Admin action: view any user's 2FA status without seeing secrets
**Preconditions:** Users with various 2FA states; Super Admin access to the status view.
**Steps:**
1. Open the 2FA status view for several users.
2. Verify the displayed fields (enabled/disabled, channel types, last used).
3. Attempt to locate any channel secret or backup code in the view.
**Expected Result:** The status view shows enabled/disabled, channel types, and last-used time for any user; no channel secrets or backup codes are exposed in any admin view; the data matches the actual state.
**Priority:** High

### TC-SA-01-03-047 — User notified when an admin changes their 2FA state
**Type:** Positive
**Covers:** 3.3 → Notification to the user when an admin changes their 2FA state
**Preconditions:** A user account; an admin 2FA action to perform (force-enable or reset).
**Steps:**
1. Perform an admin 2FA action on the user's record.
2. Observe the notification delivered to the user.
3. Verify the notification content.
**Expected Result:** The user is notified immediately (e.g., "Your two-factor authentication was reset by an administrator. You will be asked to set it up again at your next login."); the notification identifies the change; the notification is logged; unauthorized changes are visible to the account owner.
**Priority:** High

### TC-SA-01-03-048 — Audit logging of all enable/disable/reset actions
**Type:** Positive
**Covers:** 3.3 → Audit logging of all actions with actor, target, and reason
**Preconditions:** Enable, disable, and reset actions produced; audit log access.
**Steps:**
1. Produce a self-disable, an admin force-enable, and an admin reset.
2. Locate all three in the audit log.
3. Inspect actor, target, and reason on each.
**Expected Result:** All three actions are audit-logged with actor (user or admin), target (the account), and reason (for admin actions); no action lacks any field; the log is exportable.
**Priority:** High

### TC-SA-01-03-049 — Attacker with only the password cannot remove the second factor
**Type:** Negative
**Covers:** 3.3 → Rule: disabling always requires the current 2FA challenge in addition to the password
**Preconditions:** An account with 2FA enabled; a session with the password known but no 2FA challenge passed.
**Steps:**
1. With only the password (no 2FA challenge), attempt to disable 2FA.
2. Observe the block at the challenge step.
**Expected Result:** The disable is blocked at the 2FA challenge step; an attacker with only the password cannot remove the second factor; the blocked attempt is logged; the 2FA state is unchanged.
**Priority:** Critical

### TC-SA-01-03-050 — Mandatory-role disable toggle greyed out with explanation
**Type:** Negative
**Covers:** 3.3 → Rule: mandatory-role users see the toggle greyed out with the explanation
**Preconditions:** A mandatory-2FA role user.
**Steps:**
1. Open the Security section of profile settings.
2. Read the disable toggle's state and explanation text.
**Expected Result:** The toggle is greyed out (disabled) and displays exactly "Two-factor authentication is required for your role"; the control is not actionable; the state matches the policy.
**Priority:** High

### TC-SA-01-03-051 — Reset clears all channels and backup codes
**Type:** Edge
**Covers:** 3.3 → Rule: a reset clears all channels and backup codes; re-enroll from scratch
**Preconditions:** An account with multiple channels and backup codes; an admin reset performed.
**Steps:**
1. Perform the admin reset (with verification and reason).
2. Inspect the account's channels and backup codes.
3. Have the user log in and observe the enrollment requirement.
**Expected Result:** All channels are cleared and all backup codes are invalidated; the user must re-enroll from scratch at next login (guided flow); no prior channel or code works after the reset; the reset is audit-logged.
**Priority:** Critical

### TC-SA-01-03-052 — Admin 2FA actions require a recorded reason
**Type:** Negative
**Covers:** 3.3 → Rule: admin actions always require a recorded reason
**Preconditions:** Super Admin access; an admin 2FA action to perform.
**Steps:**
1. Attempt to perform "Force-enable 2FA" or "Reset 2FA" without entering a reason.
2. Observe whether the action can complete.
3. Complete the action with a reason and inspect the audit entry.
**Expected Result:** The action cannot complete without a recorded reason (the reason field is mandatory); with a reason, the action completes and the audit entry carries the reason, actor, target, and timestamp; no admin 2FA action is recorded without a reason.
**Priority:** High

### TC-SA-01-03-053 — User always notified of admin 2FA changes
**Type:** Positive
**Covers:** 3.3 → Rule: the user is always notified when an admin changes their 2FA state
**Preconditions:** Multiple admin 2FA actions to perform (force-enable and reset).
**Steps:**
1. Perform a force-enable on user A; observe the notification.
2. Perform a reset on user B; observe the notification.
3. Verify both notifications were delivered and logged.
**Expected Result:** Both users are notified of the change to their 2FA state; the notifications are delivered through the user's registered channels; both are logged; no admin 2FA change occurs without a user notification.
**Priority:** High

### TC-SA-01-03-054 — Admin views expose status but never secrets
**Type:** Negative
**Covers:** 3.3 → Rule: status visible to admins; channel secrets and backup codes never exposed
**Preconditions:** Users with enrolled channels and backup codes; Super Admin access to all admin views.
**Steps:**
1. Review every admin view that shows 2FA information (status view, user record, audit log).
2. Search for any channel secret, TOTP secret, or backup code value.
3. Verify only status-level data is present.
**Expected Result:** No admin view exposes channel secrets, TOTP secrets, or backup code values; only status-level data (enabled/disabled, channel types, last used) is visible; the secret values are absent from all admin surfaces and logs.
**Priority:** Critical
