Problema SSO: parametri SSO o SIG mancanti

Ciao, ho un problema con Discourse SSO. Cosa sto sbagliando? Il mio codice estrae dalla mia altra piattaforma senza problemi. Tuttavia, non ricevo alcun nonce.


// Abilita il logging degli errori per il debug
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Carica il file init
require_once '/init.php'; // Aggiorna questo percorso in base alla configurazione della tua piattaforma

// Chiave segreta di Discourse Connect e URL per restituire il payload
$sso_secret = 'keyhere'; // Sostituisci con la tua chiave segreta condivisa di Discourse
$discourse_url = 'https://urlhere.com/session/sso_login'; // Sostituisci con il tuo URL di Discourse

// Avvia la sessione per controllare lo stato di accesso dell'utente della piattaforma
session_start();

// Controlla se l'utente è loggato
if (!isset($_SESSION['uid'])) {
    // Se l'utente non è loggato, reindirizza alla pagina di accesso della piattaforma
    header('Location: /clientarea.php');
    exit;
}

// Debug: registra i parametri della richiesta in arrivo
error_log("Parametri GET ricevuti: " . print_r($_GET, true));

// Controlla se abbiamo ricevuto i parametri 'sso' e 'sig' da Discourse
if (!isset($_GET['sso']) || !isset($_GET['sig'])) {
    error_log("Parametri SSO o SIG mancanti.");
    header('Location: /clientarea.php');
    exit;
}

// Valida la firma SSO utilizzando la chiave segreta
$sso = $_GET['sso'];
$sig = $_GET['sig'];
$expected_sig = hash_hmac('sha256', $sso, $sso_secret);

if ($sig !== $expected_sig) {
    error_log("Firma SSO non valida. Prevista: $expected_sig, Ricevuta: $sig");
    header('Location: /clientarea.php');
    exit;
}

// Recupera i dettagli del client della piattaforma
$clientDetails = localAPI('getclientsdetails', ['clientid' => $_SESSION['uid']], 'admin');
if ($clientDetails['result'] !== 'success' || !isset($clientDetails['userid'])) {
    error_log("Impossibile recuperare i dettagli del client della piattaforma.");
    header('Location: /clientarea.php');
    exit;
}

// Estrai i dettagli dell'utente
$userId = $clientDetails['userid'];
$email = $clientDetails['email'];
$firstName = $clientDetails['firstname'];
$lastName = $clientDetails['lastname'];
$username = $firstName . ' ' . $lastName;

// Decodifica il payload SSO
$sso_payload = base64_decode($sso);
parse_str($sso_payload, $sso_params);

if (!isset($sso_params['nonce'])) {
    error_log("Nonce mancante dal payload SSO.");
    header('Location: /clientarea.php');
    exit;
}

// Prepara il payload SSO di ritorno con i dettagli dell'utente
$return_payload = [
    'nonce' => $sso_params['nonce'],
    'email' => $email,
    'external_id' => $userId,
    'username' => $username,
    'name' => $firstName . ' ' . $lastName,
    'admin' => 0, // Imposta a 1 se l'utente è un amministratore, altrimenti lascia 0
    'moderator' => 0 // Imposta a 1 se l'utente è un moderatore, altrimenti lascia 0
];

// Codifica il payload di ritorno in Base64
$query_string = http_build_query($return_payload);
$encoded_payload = base64_encode($query_string);

// Firma il payload codificato con la chiave segreta di Discourse
$return_sig = hash_hmac('sha256', $encoded_payload, $sso_secret);

// Debug: registra il payload e la firma
error_log("Payload di ritorno: " . print_r($return_payload, true));
error_log("Payload codificato: $encoded_payload");
error_log("Firma di ritorno: $return_sig");

// Reindirizza a Discourse con il payload firmato
header("Location: $discourse_url?sso=" . urlencode($encoded_payload) . "&sig=" . urlencode($return_sig));
exit;

Log degli errori:

[25-Sep-2024 14:50:17 UTC] Parametri SSO o SIG mancanti.
[25-Sep-2024 14:53:59 UTC] Parametri GET ricevuti: Array
(
[sso] => nonce_from_discourse
)

[25-Sep-2024 14:53:59 UTC] Parametri SSO o SIG mancanti.

Non sono sicuro del perché?

Non sono sicuro neanche io. DiscourseConnect è configurato sul tuo sito Discourse? Come arrivano gli utenti all’URL gestito da questo codice?

Seguire il processo di autenticazione con l’ispettore del browser aperto sulla scheda Rete potrebbe fornire alcuni dettagli su cosa sta succedendo.

Grazie per la risposta.

Sto cercando di integrare con WHMCS. Ho impostato tutto nel codice in modo appropriato e le impostazioni abilitate all’interno di Discourse.

Ottengo una risposta parziale ma manca la firma, stavo pensando che potesse essere un errore di decodifica poiché sembra esserci una discrepanza tra i due sistemi.

In realtà, questo non è il mio campo di competenza, sto solo facendo del mio meglio per metterlo insieme, ma mi sono grattato la testa per due giorni. Non riesco a vedere l’errore nelle mie azioni.

Ho provato a fare il debug il più possibile, ho ricostruito Discourse. Registrazione passo dopo passo. Ho provato ChatGPT. Ho confrontato il codice del plugin di WordPress. Sono bloccato.

Sembra probabile che qualcosa non sia configurato correttamente. Forse prova a fare un passo indietro. Al momento non ho un sito provider SSO configurato nella mia installazione locale, ma questo potrebbe aiutarti in parte.

Su Discourse, assicurati che le seguenti impostazioni siano configurate:

L’impostazione discourse connect url dovrebbe essere impostata sull’URL che gestisce il codice che hai pubblicato.

Imposta l’impostazione discourse connect secret su una stringa di testo lunga almeno 10 caratteri. Nota che hai la stringa di 7 caratteri keyhere codificata in modo fisso nel codice che hai pubblicato. Presumo che tu stia modificando quel valore quando esegui il codice. Impostalo sullo stesso valore che hai inserito su Discourse.

Ora disconnettiti dal tuo sito Discourse. Apri l’ispettore web del tuo browser nella scheda di rete. Fai clic sul pulsante “Login” su Discourse. Dovresti vedere richieste simili alle prime due richieste nello screenshot qui sotto:

La prima richiesta sarà a http://forum.example.com/session/sso?return_path=%2F

La richiesta successiva dovrebbe essere a https://example.com/?sso=<payload_sso_inviato_da_discourse>&sig=<firma_sso>

example.com e forum.example.com dovrebbero essere impostati sui domini effettivi che stai utilizzando.

Se tutto è configurato correttamente, mi aspetterei che questo assegni i valori dei parametri sso e sig alle variabili che hai impostato qui:

$sso = $_GET['sso'];
$sig = $_GET['sig'];

Se fossi io, probabilmente commenterei il resto del codice e mi limiterei a confermare che puoi ricevere il payload e assegnarlo alle variabili.

Con DiscourseConnect abilitato, puoi accedere nuovamente al tuo sito Discourse visitando il percorso /u/admin-login. Se hai accesso alla console Rails del sito Discourse, puoi anche accedere disabilitando DiscourseConnect dalla console Rails:

SiteSetting.enable_discourse_connect = false

È possibile che ci siano errori più avanti nel codice che hai pubblicato. Ad esempio, penso che tu debba chiamare urldecode sul valore del parametro sso prima di generare la firma prevista. Dai un’occhiata a come lo gestisce il plugin WP Discourse:

$payload nella funzione sopra è solo il valore del parametro di query sso, dopo che è stato sanificato qui: wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub.

1 Mi Piace