[FIX] Auth CRITICI da test multi-agente: register senza jti + revoca sessione singola

CRITICO #2 — register() generava il token SENZA jti, ma requireAuth lo rifiuta
(JWT_NO_JTI): l'utente appena registrato veniva sbattuto fuori al primo
getMe/completeOnboarding e doveva rifare login. Ora register crea una riga
active_sessions con jti e genera access+refresh token col jti, come login().

CRITICO #1 — DELETE /auth/sessions/<jti> (revoca sessione singola) tornava 404:
il jti è esadecimale (non numerico), il router cadeva nel ramo "nome composto"
e generava solo {action}/{camelResource}, mai {action}/{id}. Aggiunto fallback
{action}/{id} con id passato come STRINGA (revokeSession(string $id) lo accetta).
Il candidato composito resta primo, quindi evidence/upload ecc. non si rompono.

php -l OK su entrambi. version 1.10.4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile 2026-05-31 15:01:22 +02:00
parent 2037cecaba
commit c134a2d52a
3 changed files with 24 additions and 4 deletions

View File

@ -91,9 +91,25 @@ class AuthController extends BaseController
'is_active' => 1, 'is_active' => 1,
]); ]);
// Genera tokens // --- Sessione tracciata (jti) come nel login: requireAuth rifiuta i token
$accessToken = $this->generateJWT($userId); // senza jti, quindi senza questo l'utente appena registrato verrebbe
$refreshToken = $this->generateRefreshToken($userId); // sbattuto fuori al primo getMe/completeOnboarding (401 JWT_NO_JTI). ---
$jti = bin2hex(random_bytes(16));
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$ip = $this->getClientIP();
Database::insert('active_sessions', [
'id' => $jti,
'user_id' => (int) $userId,
'organization_id' => null,
'ip_address' => $ip,
'user_agent' => substr($ua, 0, 512),
'device_label' => $this->parseDeviceLabel($ua),
'expires_at' => date('Y-m-d H:i:s', time() + JWT_REFRESH_EXPIRES_IN),
]);
// Genera tokens (con jti, come login)
$accessToken = $this->generateJWT($userId, ['jti' => $jti]);
$refreshToken = $this->generateRefreshToken($userId, $jti);
// Audit log // Audit log
$this->currentUser = ['id' => $userId]; $this->currentUser = ['id' => $userId];

View File

@ -557,6 +557,10 @@ if (is_numeric($actionName)) {
// /controller/action/subAction → nome composto (es: evidence/upload) // /controller/action/subAction → nome composto (es: evidence/upload)
$camelResource = $toCamel($resourceId); $camelResource = $toCamel($resourceId);
$candidates[] = ['p' => "{$method}:{$actionName}/{$camelResource}", 'a' => []]; $candidates[] = ['p' => "{$method}:{$actionName}/{$camelResource}", 'a' => []];
// Fallback: id NON numerico (es. jti esadecimale di una sessione,
// token) passato come STRINGA → match su {method}:{action}/{id}.
// Necessario per DELETE /auth/sessions/<jti-hex> (revoca sessione singola).
$candidates[] = ['p' => "{$method}:{$actionName}/{id}", 'a' => [$resourceId]];
} }
} }

View File

@ -1 +1 @@
{"version":"1.10.3","build":"2026-05-31-v1.10.3","date":"2026-05-31","changelog":"Fix da test multi-agente: dashboard gauge compliance (fallback overall_score quando 0 controlli, ora il backend ritorna score), risks.html backToList ripristina la vista corretta tra le 4 viste (table/matrix/fair/kri) e loadFair legge data.items. Selettore modali categorie/template corretto."} {"version":"1.10.4","build":"2026-05-31-v1.10.4","date":"2026-05-31","changelog":"Fix auth da test multi-agente: registrazione ora crea sessione tracciata (jti) come il login (prima l'utente registrato veniva sbattuto fuori al primo accesso, 401 JWT_NO_JTI); revoca sessione singola (Disconnetti dispositivo) ora funziona con jti esadecimale (routing {id} stringa). Dashboard gauge, risks viste e modali fornitori gia' corretti."}