2FA-Reife: Recovery-Codes, Enforce-Policy für Admins, Admin-Reset

- Recovery-/Backup-Codes (8x, einmalig nutzbar) bei Aktivierung + Regenerieren;
  Login akzeptiert TOTP ODER Recovery-Code
- Setting enforce_2fa_admins: Admins ohne 2FA werden zur Einrichtung geleitet
- Admin kann 2FA eines Nutzers zurücksetzen (admin/users.php)
- Schema 0003 (users.totp_backup_codes); security.php zeigt Codes & Restanzahl
This commit is contained in:
Claude 2026-06-05 20:45:28 +00:00
parent dce10a8a08
commit ba121d60e6
No known key found for this signature in database
7 changed files with 179 additions and 12 deletions

View file

@ -148,6 +148,14 @@ if (isset($_GET['toggle']) && isset($_GET['token'])) {
} else { $error = __('error_csrf'); }
}
// 2FA eines Benutzers zurücksetzen (Admin-Hilfe bei verlorenem Authenticator)
if (isset($_GET['reset_2fa']) && isset($_GET['token'])) {
if ($auth->validateCsrfToken($_GET['token'])) {
$auth->disableTotp((int)$_GET['reset_2fa']);
$success = '2FA des Benutzers wurde zurückgesetzt.';
} else { $error = __('error_csrf'); }
}
$users = $db->fetchAll("SELECT * FROM users ORDER BY name");
$sites = $db->fetchAll("SELECT * FROM sites WHERE is_active=1 ORDER BY name");
$userSiteAccess = [];
@ -304,6 +312,13 @@ $currentPage = 'users';
<i class="fas fa-key"></i>
</a>
<?php endif; ?>
<?php if (!empty($user['totp_enabled'])): ?>
<a href="?reset_2fa=<?= $user['id'] ?>&token=<?= $auth->getCsrfToken() ?>"
class="btn btn-secondary btn-sm" title="2FA zurücksetzen"
onclick="return confirm('2FA für <?= htmlspecialchars($user['email'], ENT_QUOTES) ?> zurücksetzen?')">
<i class="fas fa-user-shield"></i>
</a>
<?php endif; ?>
<a href="?delete=<?= $user['id'] ?>&token=<?= $auth->getCsrfToken() ?>"
class="btn btn-danger btn-sm" title="<?= __('btn_delete') ?>"
onclick="return confirm('Benutzer wirklich löschen?')">