02-ce-que-je-construis/specs/admin-2fa.md

Gestion 2FA depuis le backoffice (TLR-004)

Contexte : scheb/2fa-bundle v6 actif sur telaria-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 : flip is2faEnabled, CSRF invalide → 403
  • DatabaseTrustedDeviceManagerTest : add → isTrusted ✅ → clear → isTrusted ❌
  • Fonctionnel reset : clearTrustedDevices + clearAllTrustedDevices — vĂ©rifier table vide aprĂšs

5. Ordre d'implémentation

  1. AppSetting 2fa.global_enabled + GlobalTwoFactorCondition + wiring + toggle BO global
  2. TrustedDevice entité + migration + DatabaseTrustedDeviceManager + wiring scheb
  3. Actions BO reset trusted devices (par user + global)
  4. Toggle admin par user (listing + fiche)
  5. PHPUnit vert → poseidon → staging → rĂ©cap Chef

Références

Assistant documentaire

Posez une question sur la documentation. Les rĂ©ponses citent leurs sources — un clic ouvre le document Ă  gauche.

Loading…
Loading the web debug toolbar…
Attempt #