Nessun oggetto della modifica
Nessun oggetto della modifica
Riga 194: Riga 194:
   <code>/oauth/linkedin-login.php</code>
   <code>/oauth/linkedin-login.php</code>
3. Verifica nei log se la creazione dell’utente avviene correttamente.
3. Verifica nei log se la creazione dell’utente avviene correttamente.
4. Controlla la pagina <code>Special:Users</code> per vedere se l’utente è stato registrato.
4. Controlla la pagina <code>Special:Users</code> per vedere se l’utente è stato registrato.


Riga 206: Riga 207:


----
----
\= Documentazione tecnica completa - SSO LinkedIn su MediaWiki (Masticationpedia)


\== 🧠 Obiettivo del sistema SSO LinkedIn ==
== Documentazione tecnica completa - SSO LinkedIn su MediaWiki (Masticationpedia) ==
🧠 Obiettivo del sistema SSO LinkedIn  
 
Consentire agli utenti di Masticationpedia di accedere direttamente al sito tramite il proprio profilo LinkedIn, senza registrazione manuale. L’utente viene autenticato tramite OAuth2 (OpenID Connect) e, se non esiste già, viene creato automaticamente nel database MediaWiki e visibile su `Special:Users`.
Consentire agli utenti di Masticationpedia di accedere direttamente al sito tramite il proprio profilo LinkedIn, senza registrazione manuale. L’utente viene autenticato tramite OAuth2 (OpenID Connect) e, se non esiste già, viene creato automaticamente nel database MediaWiki e visibile su `Special:Users`.


\== ✅ Risultati ottenuti ==
✅ Risultati ottenuti  
 
Al momento attuale (luglio 2025), il sistema ha raggiunto diversi traguardi fondamentali:
Al momento attuale (luglio 2025), il sistema ha raggiunto diversi traguardi fondamentali:


Riga 220: Riga 223:
* I log di debug sono ben strutturati (incoming\_user\_debug.json, mw\_user\_creation.log)
* I log di debug sono ben strutturati (incoming\_user\_debug.json, mw\_user\_creation.log)


\== ❌ Problema attuale (blocco finale) ==
❌ Problema attuale (blocco finale)  


Nonostante il flusso OAuth appaia corretto:
Nonostante il flusso OAuth appaia corretto:


1. **L’utente non compare in `Special:Users`**, né risulta registrato in modo persistente da MediaWiki.
1. **L’utente non compare in `Special:Users`**, né risulta registrato in modo persistente da MediaWiki.
2. I file di debug non vengono più scritti (es: `incoming_user_debug.json` è vuoto), anche se fino a poco prima funzionavano.
2. I file di debug non vengono più scritti (es: `incoming_user_debug.json` è vuoto), anche se fino a poco prima funzionavano.
3. In alcuni tentativi recenti, **LinkedIn ha bloccato il flusso** reindirizzando su una pagina interna di errore: `challenge_global_internal_error`.
3. In alcuni tentativi recenti, **LinkedIn ha bloccato il flusso** reindirizzando su una pagina interna di errore: `challenge_global_internal_error`.


\== 🧪 Possibili cause analizzate ==
🧪 Possibili cause analizzate  


\=== 🔹 1. LinkedIn blocca il flusso con errore interno ===
🔹 1. LinkedIn blocca il flusso con errore interno ===


* Dopo numerosi tentativi ravvicinati, LinkedIn ha mostrato CAPTCHA e poi un errore generico con redirect su `/checkpoint/lg/login?errorKey=challenge_global_internal_error`.
* Dopo numerosi tentativi ravvicinati, LinkedIn ha mostrato CAPTCHA e poi un errore generico con redirect su `/checkpoint/lg/login?errorKey=challenge_global_internal_error`.
Riga 236: Riga 241:
* Tuttavia, il login classico sul sito LinkedIn funziona, quindi l'account **non è bannato**.
* Tuttavia, il login classico sul sito LinkedIn funziona, quindi l'account **non è bannato**.


\=== 🔹 2. Il file `create_mw_user_direct.php` non viene nemmeno raggiunto ===
🔹 2. Il file `create_mw_user_direct.php` non viene nemmeno raggiunto ===


* Potrebbe essere dovuto a un errore nella `curl_exec` finale nel callback.
* Potrebbe essere dovuto a un errore nella `curl_exec` finale nel callback.
Riga 242: Riga 247:
* Nessuna scrittura su `incoming_user_debug.json` è un forte indizio che l'esecuzione si ferma prima.
* Nessuna scrittura su `incoming_user_debug.json` è un forte indizio che l'esecuzione si ferma prima.


\=== 🔹 3. La fase di scrittura su MediaWiki fallisce silenziosamente ===
🔹 3. La fase di scrittura su MediaWiki fallisce silenziosamente  


* Anche quando tutto sembra completarsi, l’utente non è visibile.
* Anche quando tutto sembra completarsi, l’utente non è visibile.
* MediaWiki potrebbe accettare la richiesta ma non completare il commit nel database.
* MediaWiki potrebbe accettare la richiesta ma non completare il commit nel database.


\== 🧰 Diagnostica svolta ==
🧰 Diagnostica svolta  


* Test del singolo script `create_mw_user_direct.php` → funzionante in locale.
* Test del singolo script `create_mw_user_direct.php` → funzionante in locale.
Riga 254: Riga 259:
* Permessi `755` per i file PHP confermati.
* Permessi `755` per i file PHP confermati.


\== 📌 Prossimi tentativi suggeriti ==
📌 Prossimi tentativi suggeriti ==


1. **Verificare i permessi su tutta la cartella `/oauth/`**, specialmente se `www-data` ha accesso in scrittura.
1. **Verificare i permessi su tutta la cartella `/oauth/`**, specialmente se `www-data` ha accesso in scrittura.
2. **Inserire `var_dump()` o `echo` diagnostici in cima ai file** per vedere se si attivano realmente.
2. **Inserire `var_dump()` o `echo` diagnostici in cima ai file** per vedere se si attivano realmente.
3. **Ripristinare uno script minimo** che scriva sempre qualcosa, anche senza passaggi LinkedIn, per confermare che la `curl` arrivi.
3. **Ripristinare uno script minimo** che scriva sempre qualcosa, anche senza passaggi LinkedIn, per confermare che la `curl` arrivi.
4. **Pulire cache LinkedIn** o aspettare 24-48h dopo l’errore `challenge_global_internal_error`.
4. **Pulire cache LinkedIn** o aspettare 24-48h dopo l’errore `challenge_global_internal_error`.
5. **Verificare la variabile `client_id` e `client_secret`**: in uno degli ultimi tentativi era errata e ha mandato in confusione il flusso.
5. **Verificare la variabile `client_id` e `client_secret`**: in uno degli ultimi tentativi era errata e ha mandato in confusione il flusso.


\== 🧩 Conclusione provvisoria ==
🧩 Conclusione provvisoria  
 
Il sistema è quasi completo. La parte più difficile (flusso OAuth, access token, lettura dati utente) è superata con successo.
Il sistema è quasi completo. La parte più difficile (flusso OAuth, access token, lettura dati utente) è superata con successo.


Riga 271: Riga 281:
* Il logging per capire il vero punto di blocco.
* Il logging per capire il vero punto di blocco.


\== 🔐 Nota finale ==
🔐 Nota finale  
 
Si raccomanda di:
Si raccomanda di:



Versione delle 22:57, 4 lug 2025

Documentazione Tecnica SSO LinkedIn per Masticationpedia

Questa pagina descrive la struttura tecnica per integrare il login Single Sign-On (SSO) tramite LinkedIn, con creazione automatica dell’utente su MediaWiki.

Tutti i file sono caricati nella cartella: /oauth/

📁 1. linkedin-login.php

<?php
// linkedin-login.php

$client_id = 'TUO_CLIENT_ID';
$redirect_uri = 'https://staging.masticationpedia.org/oauth/linkedin-callback.php';
$scope = 'openid email profile';
$state = bin2hex(random_bytes(16));

$url = "https://www.linkedin.com/oauth/v2/authorization?response_type=code"
     . "&client_id={$client_id}"
     . "&redirect_uri=" . urlencode($redirect_uri)
     . "&state={$state}"
     . "&scope=" . urlencode($scope);

header("Location: $url");
exit;

Funzione: Genera l'URL di richiesta login e consensi a LinkedIn. Avvia il flusso OAuth2.


📁 2. linkedin-callback.php

<?php
// linkedin-callback.php

ini_set('display_errors', 1);
error_reporting(E_ALL);
$log = __DIR__ . '/linkedin_callback.log';
function log_debug($msg) {
    global $log;
    file_put_contents($log, "[".date('Y-m-d H:i:s')."] $msg\n", FILE_APPEND);
}

if (!isset($_GET['code'], $_GET['state'])) exit('Errore: code/state mancanti');
$code = $_GET['code'];

$token_url = 'https://www.linkedin.com/oauth/v2/accessToken';
$post = [
    'grant_type' => 'authorization_code',
    'code' => $code,
    'redirect_uri' => 'https://staging.masticationpedia.org/oauth/linkedin-callback.php',
    'client_id' => 'TUO_CLIENT_ID',
    'client_secret' => 'TUO_CLIENT_SECRET'
];
$ch = curl_init($token_url);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($post),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => false
]);
$resp = curl_exec($ch);
curl_close($ch);
$data = json_decode($resp, true);
$token = $data['access_token'] ?? '';
if (!$token) exit('Errore token');

$ch2 = curl_init('https://api.linkedin.com/v2/userinfo');
curl_setopt_array($ch2, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"],
    CURLOPT_SSL_VERIFYPEER => false
]);
$userinfo = curl_exec($ch2);
curl_close($ch2);
$user = json_decode($userinfo, true);
$sub = $user['sub'] ?? '';
$name = $user['name'] ?? '';
$email = $user['email'] ?? '';

if (!$sub || !$name) exit('Errore dati incompleti');

$ch3 = curl_init('https://staging.masticationpedia.org/oauth/create_mw_user_direct.php');
curl_setopt_array($ch3, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'sub' => $sub,
        'name' => $name,
        'email' => $email
    ]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => false
]);
curl_exec($ch3);
curl_close($ch3);

header("Location: https://staging.masticationpedia.org/wiki/Main_Page");
exit;
?>

Funzione: Scambia il code con un token, ottiene i dati da LinkedIn e li invia al file che crea l'utente.


📁 3. create_mw_user_direct.php

<?php
use MediaWiki\MediaWikiServices;

ini_set('display_errors', 1);
error_reporting(E_ALL);
$log = __DIR__ . '/mw_user_creation.log';
function log_debug($m) {
    global $log;
    file_put_contents($log, "[".date('Y-m-d H:i:s')."] $m\n", FILE_APPEND);
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('❌ Metodo non consentito.');
}

$sub = $_POST['sub']   ?? 'no-sub';
$name = $_POST['name'] ?? 'Anon';
$email = $_POST['email'] ?? 'noemail@mpedia';

file_put_contents(__DIR__.'/incoming_user_debug.json',
    json_encode(['ts'=>date('c'),'sub'=>$sub,'name'=>$name,'email'=>$email], JSON_PRETTY_PRINT)."\n", FILE_APPEND);

if (!$sub || !$name) {
    log_debug("Missing user data");
    http_response_code(400);
    exit;
}

require_once __DIR__ . '/../includes/WebStart.php';
$services = MediaWikiServices::getInstance();
$userFactory = $services->getUserFactory();
$userLookup = $services->getUserLookup();

$username = substr(preg_replace('/[^A-Za-z0-9]/','_',$name . '_' . substr($sub,0,6)), 0, 50);

$userObj = \User::newFromName($username);
if ($userObj && $userObj->getId() !== 0) {
    log_debug("User exists: $username");
    exit;
}

$userObj = $userFactory->newFromName($username);
$userObj->addToDatabase();
$userObj->setEmail($email);
$userObj->setRealName($name);
$userObj->setToken();
$userObj->saveSettings();

$services->getDBLoadBalancerFactory()->commitMasterChanges(__METHOD__);
$entry = new \ManualLogEntry('newusers','create');
$entry->setPerformer($userObj);
$entry->setTarget($userObj->getUserPage());
$entry->setComment('Created via LinkedIn SSO');
$id = $entry->insert();
$entry->publish($id);

log_debug("User created: $username");
?>

Funzione: Riceve i dati utente da LinkedIn e crea direttamente un account MediaWiki completo, visibile in Special:Users.


✅ Riassunto finale

  • **3 file**: `linkedin-login.php`, `linkedin-callback.php`, `create_mw_user_direct.php`
  • **Cartella consigliata**: `/oauth/`
  • **Log consigliati**:
 * `linkedin_callback.log`
 * `incoming_user_debug.json`
 * `mw_user_creation.log`

🧪 Debug e test

1. Inserisci correttamente i tuoi `client_id` e `client_secret` nei file. 2. Collega il pulsante o link di login LinkedIn alla pagina:

  /oauth/linkedin-login.php

3. Verifica nei log se la creazione dell’utente avviene correttamente.

4. Controlla la pagina Special:Users per vedere se l’utente è stato registrato.


🔐 Sicurezza finale

Dopo la messa in produzione:

  • Rimuovere le righe `ini_set('display_errors', 1)` e `log_debug(...)`
  • Proteggere l'accesso alla cartella `/oauth/` se non strettamente necessario.
  • Salvare backup regolari di `incoming_user_debug.json` e log.

Documentazione tecnica completa - SSO LinkedIn su MediaWiki (Masticationpedia)

🧠 Obiettivo del sistema SSO LinkedIn

Consentire agli utenti di Masticationpedia di accedere direttamente al sito tramite il proprio profilo LinkedIn, senza registrazione manuale. L’utente viene autenticato tramite OAuth2 (OpenID Connect) e, se non esiste già, viene creato automaticamente nel database MediaWiki e visibile su `Special:Users`.

✅ Risultati ottenuti

Al momento attuale (luglio 2025), il sistema ha raggiunto diversi traguardi fondamentali:

  • Il pulsante di login LinkedIn apre correttamente la finestra di autorizzazione.
  • LinkedIn restituisce il `code` e lo scambio con `access_token` funziona perfettamente.
  • I dati dell’utente (sub, nome, email) vengono ricevuti correttamente.
  • L’utente teoricamente viene creato tramite `create_mw_user_direct.php`, con salvataggio previsto su `Special:Users`.
  • I log di debug sono ben strutturati (incoming\_user\_debug.json, mw\_user\_creation.log)

❌ Problema attuale (blocco finale)

Nonostante il flusso OAuth appaia corretto:

1. **L’utente non compare in `Special:Users`**, né risulta registrato in modo persistente da MediaWiki.

2. I file di debug non vengono più scritti (es: `incoming_user_debug.json` è vuoto), anche se fino a poco prima funzionavano.

3. In alcuni tentativi recenti, **LinkedIn ha bloccato il flusso** reindirizzando su una pagina interna di errore: `challenge_global_internal_error`.

🧪 Possibili cause analizzate

🔹 1. LinkedIn blocca il flusso con errore interno ===

  • Dopo numerosi tentativi ravvicinati, LinkedIn ha mostrato CAPTCHA e poi un errore generico con redirect su `/checkpoint/lg/login?errorKey=challenge_global_internal_error`.
  • È possibile che il sistema LinkedIn consideri i tentativi come "anormali" da parte dello stesso IP server.
  • Tuttavia, il login classico sul sito LinkedIn funziona, quindi l'account **non è bannato**.

🔹 2. Il file `create_mw_user_direct.php` non viene nemmeno raggiunto ===

  • Potrebbe essere dovuto a un errore nella `curl_exec` finale nel callback.
  • Oppure a **permessi Apache/PHP** sulla cartella `/oauth/`.
  • Nessuna scrittura su `incoming_user_debug.json` è un forte indizio che l'esecuzione si ferma prima.

🔹 3. La fase di scrittura su MediaWiki fallisce silenziosamente

  • Anche quando tutto sembra completarsi, l’utente non è visibile.
  • MediaWiki potrebbe accettare la richiesta ma non completare il commit nel database.

🧰 Diagnostica svolta

  • Test del singolo script `create_mw_user_direct.php` → funzionante in locale.
  • Uso di `file_put_contents()` in vari punti → successivamente non più visibili.
  • Logging attivo con timestamp → ora assente.
  • Permessi `755` per i file PHP confermati.

📌 Prossimi tentativi suggeriti ==

1. **Verificare i permessi su tutta la cartella `/oauth/`**, specialmente se `www-data` ha accesso in scrittura.

2. **Inserire `var_dump()` o `echo` diagnostici in cima ai file** per vedere se si attivano realmente.

3. **Ripristinare uno script minimo** che scriva sempre qualcosa, anche senza passaggi LinkedIn, per confermare che la `curl` arrivi.

4. **Pulire cache LinkedIn** o aspettare 24-48h dopo l’errore `challenge_global_internal_error`.

5. **Verificare la variabile `client_id` e `client_secret`**: in uno degli ultimi tentativi era errata e ha mandato in confusione il flusso.

🧩 Conclusione provvisoria

Il sistema è quasi completo. La parte più difficile (flusso OAuth, access token, lettura dati utente) è superata con successo.

Resta da risolvere:

  • La corretta chiamata finale a `create_mw_user_direct.php`
  • La scrittura reale nel DB MediaWiki
  • Il logging per capire il vero punto di blocco.

🔐 Nota finale

Si raccomanda di:

Una volta ripristinata la scrittura JSON o il log, potremo eseguire un nuovo ciclo completo e definitivo.

Pagina privata generata da ChatGPT su richiesta del fondatore di Masticationpedia, Gianni Frisardi.