Files
DevEnv nis2-agileandClaude Opus 4.8 4d89b1e04b [FEAT] TLS-DB pre-equip nis2: PDO SSL gated default-OFF + CA (VIGILE 2026-06-10)
database.php: Database::sslOptions() — TLS verso MySQL gated (env DB_SSL=true o
flag-file application/config/.db_ssl_on), DEFAULT OFF. PDO::MYSQL_ATTR_SSL_CA +
VERIFY_SERVER_CERT=false; fail-safe se CA assente (resta in chiaro + log: un
VERIFY=false senza CA connetterebbe in chiaro silenziosamente). Merge con '+'
(preserva chiavi-intere PDO). Default-OFF provato inerte (base + [] === base).

Validato da 2 agenti: runtime app coperto 100% da Database::getInstance (0 raw PDO
in application/); review adversariale = SICURO default-OFF, nessun bug.

.gitignore: flag-file + db-ca.pem. Runbook: docs/TLS_DB_PREEQUIP_NIS2.md.
NB topologia verificata: l'app usa il DB CONTAINER (db->172.21.0.4, 8.0.45), non il
MySQL host -> CA + enforce vanno sul container db (a cura VIGILE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:36:52 +02:00

86 lines
3.9 KiB
PHP

<?php
/**
* One-off idempotente: aggiunge un utente all'organizzazione Agile Technology SRL (org 129).
* Sicuro/rilanciabile: se l'email esiste NON duplica; aggiunge solo la membership mancante.
* Eseguire sull'HOST Hetzner: php /var/www/nis2-agile/scripts/add-agile-user.php
*/
if (!defined('BASE_PATH')) define('BASE_PATH', dirname(__DIR__));
if (!defined('APP_PATH')) define('APP_PATH', BASE_PATH . '/application');
require_once APP_PATH . '/config/env.php';
require_once APP_PATH . '/config/config.php';
require_once APP_PATH . '/config/database.php';
// ── Parametri richiesta ──────────────────────────────────────────────
const EMAIL = 'cristiano.benassati@gmail.com';
const PASSWORD = 'Silvia1978!@';
const FULL_NAME = 'Cristiano Benassati';
const ORG_ID = 129; // Agile Technology SRL
const ORG_ROLE = 'org_admin'; // ruolo nell'organizzazione
const GLOBAL_ROLE= 'org_admin'; // ruolo globale (enum users.role)
const FIRM_ID = null; // null = NESSUN accesso firm-wide (least privilege). Mettere 1 per parità con Fattori/Tagliavini.
const IS_PRIMARY = 0;
$pdo = Database::getInstance();
$report = [];
// 1) Utente esiste già?
$u = Database::fetchOne('SELECT id, email, full_name, role, is_active, sso_identity_id, consulting_firm_id FROM users WHERE email = ?', [EMAIL]);
if ($u) {
$report['user'] = "ESISTE GIÀ (id={$u['id']}, role={$u['role']}, " . ($u['sso_identity_id'] ? "SSO#{$u['sso_identity_id']}" : 'locale') . ')';
$userId = (int) $u['id'];
// Aggiorna password SOLO se locale (su utenti SSO verrebbe sovrascritta dal cron sync)
if (empty($u['sso_identity_id'])) {
$hash = password_hash(PASSWORD, PASSWORD_DEFAULT);
Database::query('UPDATE users SET password_hash = ?, is_active = 1 WHERE id = ?', [$hash, $userId]);
$report['password'] = 'aggiornata (utente locale)';
} else {
$report['password'] = 'NON toccata (utente SSO: la password è gestita dal sync SSO)';
}
} else {
$hash = password_hash(PASSWORD, PASSWORD_DEFAULT);
$userId = Database::insert('users', [
'email' => EMAIL,
'password_hash' => $hash,
'full_name' => FULL_NAME,
'role' => GLOBAL_ROLE,
'consulting_firm_id' => FIRM_ID,
'is_active' => 1,
'email_verified_at' => date('Y-m-d H:i:s'),
'password_version' => 1,
]);
$report['user'] = "CREATO (id={$userId}, role=" . GLOBAL_ROLE . ', locale)';
$report['password'] = 'impostata';
}
// Verifica hash
$chk = Database::fetchOne('SELECT password_hash FROM users WHERE id = ?', [$userId]);
$report['password_verify'] = password_verify(PASSWORD, $chk['password_hash']) ? 'OK ✓' : 'FALLITO ✗';
// 2) Membership org 129
$m = Database::fetchOne('SELECT id, role FROM user_organizations WHERE user_id = ? AND organization_id = ?', [$userId, ORG_ID]);
if ($m) {
$report['membership'] = "già presente (role={$m['role']})";
} else {
Database::insert('user_organizations', [
'user_id' => $userId,
'organization_id' => ORG_ID,
'role' => ORG_ROLE,
'is_primary' => IS_PRIMARY,
]);
$report['membership'] = 'AGGIUNTA (org 129, role=' . ORG_ROLE . ')';
}
echo "=== Risultato ===\n";
foreach ($report as $k => $v) printf(" %-16s %s\n", $k . ':', $v);
// 3) Stato finale membri org 129
echo "\n=== Membri attuali org 129 ===\n";
$rows = Database::fetchAll(
'SELECT uo.user_id, u.full_name, u.email, uo.role, uo.is_primary
FROM user_organizations uo JOIN users u ON u.id = uo.user_id
WHERE uo.organization_id = ? ORDER BY uo.is_primary DESC, uo.user_id', [ORG_ID]);
foreach ($rows as $r) {
printf(" #%d %-22s %-32s %-14s %s\n", $r['user_id'], $r['full_name'], $r['email'], $r['role'], $r['is_primary'] ? '(primario)' : '');
}