Gestion 2FA depuis le backoffice (TLR-004)
Contexte :
scheb/2fa-bundlev6 actif surtelaria-app(scheb/2fa-email+scheb/2fa-trusted-device). Les trusted devices ne sont actuellement stockĂ©s qu'en cookie â aucune rĂ©vocation serveur possible. Mathieu demande trois capacitĂ©s administratives.
Spec de référence auth : auth-compte.md.
1. Switch global 2FA
Un toggle dans le BO qui active/désactive la 2FA pour tous les utilisateurs sans redéploiement.
Contrainte : scheb_two_factor.email.enabled est compile-time. Pour le rendre runtime-switchable, implémenter TwoFactorConditionInterface :
// src/Security/TwoFactor/GlobalTwoFactorCondition.php final class GlobalTwoFactorCondition implements TwoFactorConditionInterface { public function shouldPerformTwoFactorAuthentication(TokenInterface $token): bool { return $this->appSettings->getBool('2fa.global_enabled', true); } }
Wiring dans config/packages/scheb_2fa.yaml :
scheb_two_factor: conditions: - App\Security\TwoFactor\GlobalTwoFactorCondition
AppSetting 2fa.global_enabled (bool, default true) â gĂ©rĂ© depuis le BO (table app_setting).
UI : bouton toggle dans /admin/config (section sĂ©curitĂ©) ou en tĂȘte de /admin/utilisateurs. Route : POST /admin/config/2fa-toggle-global. CSRF obligatoire.
2. Toggle 2FA par utilisateur (action admin)
L'admin peut activer/désactiver la 2FA d'un utilisateur tiers (distinct du toggle self-service /2fa/toggle dans ProfileController).
Route : POST /admin/utilisateurs/{id}/2fa-toggle
Action : flip User::is2faEnabled. MĂȘme champ que le self-service, nouvelle route admin.
UI :
- Listing
/admin/utilisateurs(_list.html.twig) : colonne "2FA" avec badge on/off + bouton POST CSRF-protĂ©gĂ© par ligne - Fiche user (formulaire existant ou Ă crĂ©er) : mĂȘme toggle
3. Reset trusted devices
3.1 Entité TrustedDevice
id int PK user ManyToOne(User) onDelete=CASCADE token string(64) unique â valeur cookie _trusted_device created_at datetime expires_at datetime
Pas d'IP ni de user_agent â dĂ©cision RGPD Mathieu (inutile + minimisation).
3.2 Service DatabaseTrustedDeviceManager
// src/Security/TwoFactor/DatabaseTrustedDeviceManager.php final class DatabaseTrustedDeviceManager implements TrustedDeviceManagerInterface { public function addTrustedDevice(int $userId, string $version, string $token): void; public function isTrustedDevice(int $userId, string $version, string $token): bool; public function clearTrustedDevices(int $userId): void; // reset par user public function clearAllTrustedDevices(): void; // reset global }
Wiring dans config/packages/scheb_2fa.yaml :
scheb_two_factor: trusted_device: enabled: true manager: App\Security\TwoFactor\DatabaseTrustedDeviceManager cookie_name: _trusted_device lifetime: 2592000 extend_lifetime: true
3.3 Actions BO
POST /admin/utilisateurs/{id}/reset-trusted-devicesâclearTrustedDevices($user->getId())POST /admin/utilisateurs/reset-all-trusted-devicesâclearAllTrustedDevices()
UI : bouton "Reset devices" par ligne dans le listing + bouton global "Reset tous les appareils". CSRF obligatoire sur les deux.
3.4 Migration
Nouvelle table trusted_device (voir schéma §3.1). Convention nommage : Version20260618XXXXXX.
4. Tests
GlobalTwoFactorConditionTest:getBool('2fa.global_enabled', true)â condition respectĂ©e- Fonctionnel
/admin/utilisateurs/{id}/2fa-toggle: flipis2faEnabled, CSRF invalide â 403 DatabaseTrustedDeviceManagerTest: add â isTrusted â â clear â isTrusted â- Fonctionnel reset :
clearTrustedDevices+clearAllTrustedDevicesâ vĂ©rifier table vide aprĂšs
5. Ordre d'implémentation
AppSetting2fa.global_enabled+GlobalTwoFactorCondition+ wiring + toggle BO globalTrustedDeviceentité + migration +DatabaseTrustedDeviceManager+ wiring scheb- Actions BO reset trusted devices (par user + global)
- Toggle admin par user (listing + fiche)
- PHPUnit vert â poseidon â staging â rĂ©cap Chef
Références
- Spec auth complĂšte : auth-compte.md
- Tuto 2FA Symfony (scheb) : tutos/ia/2fa-symfony-scheb.md
- Gouvernance BO : admin-mcp.md (modĂšle de structure pour les pages admin)