-- Migration 015: SSO Federation columns -- Progetto allineamento NIS2 ↔ TRPG — Fase 1 / G01 -- Data: 2026-05-29 -- -- Aggiunge le colonne necessarie a collegare gli utenti NIS2 alle identità SSO -- centralizzate in `nexus_tenant_db.sso_identities` (gestito da agile-services). -- -- - sso_identity_id: FK logica verso nexus_tenant_db.sso_identities.id. -- NULL = utente non ancora linkato (sarà popolato lazy al primo -- login post-SSO se l'email matcha — decisione utente 2026-05-29). -- - password_version: contatore monotono incrementato a ogni cambio password SSO; -- usato dal cron sync `sso-password-sync.sh` per decidere quando -- riallineare password_hash locale. -- -- Comportamento atteso post-migration: -- * Utenti esistenti: sso_identity_id=NULL, password_version=1 -- * Login locale continua a funzionare senza modifiche (SSO_MODE=local di default) -- * Nessun controller esistente si rompe (campi additivi) -- -- Rollback: -- ALTER TABLE users -- DROP INDEX idx_sso_identity, -- DROP COLUMN sso_identity_id, -- DROP COLUMN password_version; -- -- Note MySQL 8.x: -- * `ADD COLUMN IF NOT EXISTS` non standard → controllo via information_schema. -- * Eseguire come utente con privilegio ALTER su nis2_agile_db. SET @col_sso := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'sso_identity_id' ); SET @sql_sso := IF(@col_sso = 0, 'ALTER TABLE users ADD COLUMN sso_identity_id INT NULL COMMENT ''FK logica verso nexus_tenant_db.sso_identities.id'' AFTER email_verified_at', 'SELECT ''sso_identity_id già presente — skip'' AS info' ); PREPARE stmt FROM @sql_sso; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @col_ver := ( SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'password_version' ); SET @sql_ver := IF(@col_ver = 0, 'ALTER TABLE users ADD COLUMN password_version INT NOT NULL DEFAULT 1 COMMENT ''Contatore versione password SSO — bumpato a ogni change-password'' AFTER sso_identity_id', 'SELECT ''password_version già presente — skip'' AS info' ); PREPARE stmt FROM @sql_ver; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @idx_sso := ( SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND INDEX_NAME = 'idx_sso_identity' ); SET @sql_idx := IF(@idx_sso = 0, 'CREATE INDEX idx_sso_identity ON users (sso_identity_id)', 'SELECT ''idx_sso_identity già presente — skip'' AS info' ); PREPARE stmt FROM @sql_idx; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Verifica finale SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME IN ('sso_identity_id', 'password_version');