This commit is contained in:
PTA
2026-08-20 17:00:06 +02:00
parent 5d8c0993a6
commit 94e7f09eb4
58 changed files with 5605 additions and 615 deletions

View File

@@ -0,0 +1,91 @@
-- ============================================================================
-- PTA V7.12 — Mot de passe des comptes privilégiés (Service Enfance et DSI)
-- ============================================================================
-- Le jeton reste le seul facteur pour les agents et les responsables de lieu.
-- Les comptes qui VALIDENT (Service Enfance) et ceux qui DISTRIBUENT LES ACCÈS
-- (DSI) en réclament un second : un mot de passe, connu du seul titulaire.
--
-- Deux facteurs de nature différente : le jeton est remis par la DSI et peut
-- circuler par courriel ; le mot de passe est choisi par le titulaire à sa
-- première connexion et n'est jamais affiché nulle part. Un jeton intercepté ne
-- suffit donc plus à valider un planning ni à créer un compte.
--
-- CONTRAIREMENT AU JETON, le mot de passe est haché avec password_hash()
-- (bcrypt) et non SHA-256 : il est choisi par un humain, donc attaquable par
-- dictionnaire, et c'est précisément ce que le hachage lent rend coûteux. La
-- vérification se fait sur un compte déjà identifié par son jeton, l'absence
-- d'index sur le mot de passe n'a donc aucune importance.
--
-- POURQUOI « v7_9f » : les migrations sont jouées dans l'ORDRE ALPHABÉTIQUE
-- (docker/db/apply-migrations.sh). Le préfixe suit la dernière migration en date
-- (v7_9e), pas le numéro de version fonctionnelle. Voir CLAUDE.md.
--
-- Prérequis : migration_v7_9e_dsi_comptes_journal.sql.
-- ============================================================================
-- ----------------------------------------------------------------------------
-- 1. DEUX COLONNES SUR LE COMPTE
-- ----------------------------------------------------------------------------
-- `IF NOT EXISTS` est une extension MariaDB : elle rend l'ALTER idempotent, ce
-- qu'exige le rejeu des migrations.
--
-- Le hachage est NULLABLE, et cet état porte du sens : « mot de passe pas encore
-- défini ». C'est l'état d'un compte fraîchement créé, et c'est aussi ce que
-- produit une réinitialisation par la DSI. Un compte privilégié dans cet état ne
-- peut pas ouvrir de session : la connexion impose d'abord d'en choisir un.
ALTER TABLE compte_acces
ADD COLUMN IF NOT EXISTS mot_de_passe_hash VARCHAR(255) NULL
COMMENT 'password_hash() du mot de passe ; NULL = à définir à la prochaine connexion',
ADD COLUMN IF NOT EXISTS date_mot_de_passe DATETIME NULL
COMMENT 'Dernière définition ou modification du mot de passe par le titulaire';
-- ----------------------------------------------------------------------------
-- 2. LA VUE PORTE LA RÈGLE « QUI DOIT AVOIR UN MOT DE PASSE »
-- ----------------------------------------------------------------------------
-- Comme pour les droits depuis la V7.8, la règle descend en base : le PHP
-- demande à la vue si ce compte réclame un second facteur, il ne rejoue pas la
-- liste des rôles concernés de son côté.
CREATE OR REPLACE VIEW v_acces_compte AS
SELECT
c.id_compte,
c.role,
c.libelle,
c.id_agent,
c.id_structure,
c.jeton_empreinte,
c.jeton_prefixe,
c.actif,
c.commentaire,
c.date_creation,
c.date_rotation,
c.date_derniere_connexion,
c.nombre_connexions,
c.mot_de_passe_hash,
c.date_mot_de_passe,
-- Les deux rôles qui engagent l'application : celui qui valide les plannings
-- de toute la collectivité, et celui qui distribue les accès.
CASE WHEN c.role IN ('SERVICE_ENFANCE', 'DSI') THEN 1 ELSE 0 END AS mot_de_passe_requis,
CASE WHEN c.mot_de_passe_hash IS NULL THEN 0 ELSE 1 END AS mot_de_passe_defini,
a.matricule,
a.nom AS agent_nom,
a.prenom AS agent_prenom,
s.code AS structure_code,
s.nom AS structure_nom,
-- Libellé affiché : l'identité VIVE pour un agent ou un lieu (un agent
-- renommé doit apparaître sous son nouveau nom), le libellé saisi pour les
-- comptes Service Enfance et DSI, qui ne pointent vers rien.
CASE c.role
WHEN 'AGENT' THEN CONCAT(a.prenom, ' ', a.nom)
WHEN 'RESPONSABLE_STRUCTURE' THEN s.nom
ELSE c.libelle
END AS identite_libelle,
-- Un compte reste utilisable tant que l'identité qu'il porte est active :
-- désactiver un agent coupe son accès sans avoir à toucher à son compte.
CASE c.role
WHEN 'AGENT' THEN COALESCE(a.actif, 0)
WHEN 'RESPONSABLE_STRUCTURE' THEN COALESCE(s.actif, 0)
ELSE 1
END AS identite_active
FROM compte_acces c
LEFT JOIN agent a ON a.id_agent = c.id_agent
LEFT JOIN structure s ON s.id_structure = c.id_structure;