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.