Aller au contenu

PD-107 — Tests & Validation Authentification Biométrique iOS

1. Matrice de traçabilité (CA -> tests)

Critère Description Tests liés (ID global) Type
CA-107-01 Activation nécessite confirmation mot de passe TC-107-001, TC-107-021, TC-107-041 unit, integration, e2e/manual
CA-107-02 Déverrouillage Face ID/Touch ID < 1s TC-107-004, TC-107-042, TC-107-081 unit, e2e, performance
CA-107-03 Fallback mot de passe toujours disponible TC-107-013, TC-107-043 unit, e2e/manual
CA-107-04 Après 3 échecs -> mot de passe obligatoire TC-107-010, TC-107-043 unit, e2e
CA-107-05 Modification biométrie système -> révocation TC-107-006, TC-107-071 unit, manual (device réel)
CA-107-06 Réinstallation -> réactivation manuelle requise TC-107-072 manual (device réel)
CA-107-07 Inactivité 30 min -> mot de passe obligatoire TC-107-019, TC-107-044 unit, e2e
CA-107-08 Changement MDP -> biométrie révoquée TC-107-024, TC-107-045 integration, e2e
CA-107-09 Aucun secret en clair dans storage TC-107-011, TC-107-051 unit, security
CA-107-10 Journalisation complète de tous les événements TC-107-026, TC-107-052, TC-107-031 integration, security, integration
CA-107-11 Pas de contournement SRP-6a TC-107-053, TC-107-055 security
CA-107-12 Logs signés et append-only TC-107-032, TC-107-054 integration, security

Note: les scénarios Detox demandés sont couverts par TC-107-041 a TC-107-045, avec alias TC-E2E-107-01 a TC-E2E-107-05.

2. Tests unitaires (Jest)

2.1 BiometricService.test.ts

describe('BiometricService', () => {
  describe('enableBiometrics', () => {
    it('TC-107-001: should require valid password confirmation before enabling', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-002: should return ERR-107-001 when password confirmation fails', () => {
      // Arrange
      // Act
      // Assert
    });
  });

  describe('authenticate', () => {
    it('TC-107-003: should authenticate successfully with enrolled biometrics', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-004: should resolve biometric flow under 1000ms in nominal path', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-005: should map native cancellation to ERR-107-020', () => {
      // Arrange
      // Act
      // Assert
    });
  });

  describe('handleBiometricSetChanged', () => {
    it('TC-107-006: should revoke biometric eligibility when iOS biometric set changes', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-007: should emit audit event BIOMETRIC_REVOKED_SYSTEM_CHANGE', () => {
      // Arrange
      // Act
      // Assert
    });
  });
});

2.2 KeychainService.test.ts

describe('KeychainService', () => {
  describe('storeEncryptedToken', () => {
    it('TC-107-008: should store only encrypted payload with biometryCurrentSet access control', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-009: should return ERR-107-040 when keychain write fails', () => {
      // Arrange
      // Act
      // Assert
    });
  });

  describe('readToken', () => {
    it('TC-107-010: should increment failed biometric counter on LAContext auth failure', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-011: should never expose clear secret in returned object or logs', () => {
      // Arrange
      // Act
      // Assert
    });
  });

  describe('clearBiometricArtifacts', () => {
    it('TC-107-012: should delete biometric-bound entries and keep password login path intact', () => {
      // Arrange
      // Act
      // Assert
    });
  });
});

2.3 UnlockOrchestrator.test.ts

describe('UnlockOrchestrator', () => {
  describe('unlock', () => {
    it('TC-107-013: should fallback to password challenge when biometric unavailable', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-014: should force password mode after 3 consecutive biometric failures', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-015: should return ERR-107-060 when policy denies biometric unlock', () => {
      // Arrange
      // Act
      // Assert
    });
  });

  describe('recordAttempt', () => {
    it('TC-107-016: should write audit log for each unlock attempt with outcome and reason', () => {
      // Arrange
      // Act
      // Assert
    });
  });
});

2.4 useBiometricSettings.test.ts

describe('useBiometricSettings', () => {
  describe('toggleBiometrics', () => {
    it('TC-107-017: should request password confirmation on enable action', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-018: should show deterministic error message mapped from ERR-107-001..090', () => {
      // Arrange
      // Act
      // Assert
    });
  });
});

2.5 useAppUnlock.test.ts

describe('useAppUnlock', () => {
  describe('onAppForeground', () => {
    it('TC-107-019: should require password after 30 minutes inactivity timeout', () => {
      // Arrange
      // Act
      // Assert
    });

    it('TC-107-020: should trigger biometric prompt only when policy and session state are valid', () => {
      // Arrange
      // Act
      // Assert
    });
  });
});

3. Tests d'intégration

ID Type Intégration Objectif Préconditions Résultat attendu
TC-107-021 integration Keychain <-> BiometricService Vérifier activation biométrie après confirmation MDP Session authentifiée + Face ID disponible Clé biométrique créée et token chiffré stocké
TC-107-022 integration Keychain <-> BiometricService Vérifier révocation automatique après changement set biométrique Biométrie active puis empreinte ajoutée côté iOS Entrée keychain invalide + flag biometricRevoked=true
TC-107-023 integration Policy engine <-> UnlockOrchestrator Valider politique 3 échecs -> password-only Compteur à 2, puis 1 échec Biometric désactivé temporairement + challenge MDP
TC-107-024 integration Policy engine <-> UnlockOrchestrator Changement mot de passe révoque biométrie Biométrie active + événement password_changed Révocation immédiate + nouvel opt-in requis
TC-107-025 integration Audit logs <-> backend API Vérifier livraison fiable des événements unlock File d'événements locale non vide 200 backend, ack signé, retries stop
TC-107-026 integration Audit logs <-> backend API Vérifier complétude des événements (success, fail, fallback, revoke) Simuler 4 types d'actions 4 événements reçus avec corrélation ID
TC-107-031 integration Logs signés <-> backend verifier Vérifier signature serveur et chaîne append-only Clef de signature backend valide Rejet de toute altération intermédiaire
TC-107-032 integration Logs append-only Vérifier impossibilité d'update/delete d'un event existant Event déjà persisté API retourne conflit/forbidden, audit d'anomalie émis

4. Tests E2E (Detox)

ID global Alias scénario Type Scénario Assertions clés
TC-107-041 TC-E2E-107-01 e2e Activation biométrie (flux complet) Activation demande MDP, succès active toggle, log BIOMETRIC_ENABLED
TC-107-042 TC-E2E-107-02 e2e Déverrouillage biométrique nominal App lockée -> prompt biométrique -> home < 1s
TC-107-043 TC-E2E-107-03 e2e Fallback après 3 échecs 3 refus biométriques -> écran MDP obligatoire, pas de 4e prompt bio
TC-107-044 TC-E2E-107-04 e2e Timeout 30 min Avancer timer 30 min -> retour app -> MDP obligatoire
TC-107-045 TC-E2E-107-05 e2e Révocation après changement MDP MDP changé -> biométrie OFF -> réactivation manuelle exigée

Notes d'exécution Detox

  • Utiliser device.setBiometricEnrollment(true) et device.matchFace() / device.unmatchFace() selon API iOS Simulator.
  • Pour CA-107-05 et CA-107-06, compléter sur device réel (non fiabilisé en simulateur).
  • Capturer métriques de temps via instrumentation custom Hermes + marker JS.

5. Tests de sécurité

ID Type Contrôle Méthode Résultat attendu
TC-107-051 security Aucun secret en clair en storage Audit automatique Keychain payload + AsyncStorage dump + grep patterns secrets Aucun token/secret lisible en clair
TC-107-052 security Journalisation complète sans fuite Revue des champs loggés + test intégration de tous événements Logs complets, sans secret brut
TC-107-053 security Pas de bypass SRP-6a (unlock biométrique) Forcer appel API sans challenge SRP, puis via token altéré Rejet systématique côté backend
TC-107-054 security Logs signés, append-only Tentative de modification locale d'un log signé puis envoi Signature invalide détectée, événement rejeté
TC-107-055 security Anti-replay session unlock Rejouer nonce/session proof ancien Réponse refusée + alerte sécurité
TC-107-056 security Zeroization mémoire Tests natifs + JS heap snapshots post-unlock Buffers sensibles nettoyés, non récupérables

6. Tests de performance

ID Type Mesure Protocole Seuil
TC-107-081 performance Latence unlock biométrique (P95) 200 unlocks sur iPhone réel (A15+), collecte percentile P95 < 1000ms
TC-107-082 performance Latence accès Keychain lecture 500 lectures séquentielles et concurrentes P95 < 150ms
TC-107-083 performance Overhead audit log à l'unlock Unlock avec/without audit signing Surcoût median < 50ms

7. Tests manuels (device réel)

Checklist exécutable en recette iOS réelle (Face ID/Touch ID actif).

ID Type Scénario manuel Étapes Résultat attendu
TC-107-071 manual Changement empreinte/visage système Activer biométrie app -> ajouter empreinte dans iOS -> relancer app Biométrie révoquée, MDP demandé, événement d'audit présent
TC-107-072 manual Réinstallation application Activer biométrie -> désinstaller -> réinstaller -> login Biométrie inactive par défaut, réactivation manuelle requise
TC-107-073 manual Redémarrage device Activer biométrie -> redémarrer iPhone -> ouvrir app Premier unlock exige MDP iOS/app selon politique, puis biométrie possible
TC-107-074 manual Capteur indisponible temporairement Simuler capteur indisponible (doigt humide/masque) Fallback MDP visible immédiatement

8. Mocks et fixtures

8.1 Mock LAContext (biométrie simulée)

  • MockLAContextSuccess: canEvaluatePolicy=true, evaluatePolicy -> success.
  • MockLAContextFail: evaluatePolicy -> error (codes mappés vers ERR-107-020, ERR-107-030).
  • MockLAContextChangedSet: renvoie invalidation biometryCurrentSet.

8.2 Mock Keychain

  • MockKeychainOk: setGenericPassword/getGenericPassword/resetGenericPassword succès.
  • MockKeychainWriteError: échec write -> ERR-107-040.
  • MockKeychainReadCorrupted: payload corrompu -> révocation et fallback MDP.

8.3 Fixture utilisateur authentifié

  • fixtureUserAuthenticated: utilisateur avec SRP-6a session valide, device trusté.
  • fixtureUserBiometricsEnabled: utilisateur avec opt-in biométrie actif et clés dérivées présentes.
  • fixtureUserPostPasswordChange: utilisateur après rotation MDP (doit invalider biométrie).

9. Couverture des erreurs et invariants (synthèse)

  • ERR-107-001 a ERR-107-090: couverts via tests unitaires de mapping erreurs (TC-107-018) + e2e négatifs (TC-107-043) + sécurité (TC-107-053, TC-107-055).
  • INV-107-01 a INV-107-10: couverts par combinaisons unit/integration/security ci-dessus, avec focus fort sur non-régression sécurité (TC-107-051 a TC-107-056) et politique d'orchestration (TC-107-014, TC-107-023, TC-107-024).

10. Stratégie d'exécution CI/CD + device réel

  • Pipeline PR: exécuter unit + integration + security statique (TC-107-001 a TC-107-056, hors device-only).
  • Pipeline nightly iOS simulator: exécuter E2E Detox (TC-107-041 a TC-107-045) + perf smoke (TC-107-082).
  • Campagne release candidate sur device réel: exécuter TC-107-071 a TC-107-074 + perf complète TC-107-081.
  • Critère de sortie QA: 100% des CA-107-01..12 couverts et passants; aucun test sécurité en warning; P95 unlock < 1s validé sur device réel.