47,33 → 47,57 |
} |
} |
|
class identificationSso { |
|
// Attention bien v�rifier la pr�sence des variables suivantes : |
// IDEN_UTILISE_SSO, IDEN_URL_SSO, IDEN_HEADER_SSO, IDEN_COOKIE_SSO |
// IDEN_UTILISE_SSO, IDEN_URL_SSO, IDEN_COOKIE_SSO, IDEN_SSO_SYNC |
// dans le fichier iden_config.inc.php |
private $cookie_tentative_identification = ""; |
/** Une tentative par minute pour s'identifier suffit largement */ |
private $delai_tentative_identification = 60; |
class identificationSso { |
/** |
* si la valeur est vraiment vide, le cookie n'est pas posé, alors on met |
* une valeur vide pas vide :) |
*/ |
public static $VALEUR_JETON_VIDE = "jeton-vide"; |
|
private $auth_header = 'Authorization'; |
protected $cookie_mandataire = ""; |
/** le cookie qui dure jusqu'à Vladivostok, si synchro partielle seulement */ |
protected $duree_cookie_mandataire = (3600 * 24 * 365); |
|
private $annuaire_url = ''; |
/** |
* lorsqu'appelé par un client non-navigateur (qui n'envoie et ne reçoit pas |
* de cookies), permet de ne pas rediriger en boucle, en fournissant le |
* paramètre GET "non_interactif" |
*/ |
protected $mode_non_interactif = false; |
|
private $bdd_annuaire = ''; |
private $table_annuaire = ''; |
private $champ_login = ''; |
private $champ_mdp = ''; |
/** voir IDEN_SSO_SYNC dans iden_config.inc.php */ |
protected $synchro_complete; |
|
private $communs_papyrus = null; |
protected $annuaire_url = ''; |
protected $bdd_annuaire = ''; |
protected $table_annuaire = ''; |
protected $champ_login = ''; |
protected $champ_mdp = ''; |
|
protected $communs_papyrus = null; |
|
public function __construct() { |
$this->communs_papyrus = $GLOBALS['_GEN_commun']; |
|
$this->cookie_tentative_identification = IDEN_COOKIE_SSO; |
$this->cookie_mandataire = IDEN_COOKIE_SSO; |
$this->auth_header = IDEN_HEADER_SSO; |
$this->annuaire_url = IDEN_URL_SSO; |
$this->synchro_complete = IDEN_SSO_SYNC; |
|
// gestion des clients qui ne gèrent pas les cookies (file_get_contents...) |
if (isset($_GET['non_interactif'])) { |
$this->mode_non_interactif = true; |
} |
|
// si on est en mode synchro complète, on vérifie périodiquement l'état |
// du SSO, en utilisant un cookie qui ne dure pas jusqu'à Vladivostok |
if ($this->synchro_complete === true) { |
$this->duree_cookie_mandataire = 60; // une fois par minute (ça ou autre chose) |
} |
|
// c'est moche mais je n'ai pas trouv� plus simple pour r�cuperer la table annuaire en cours |
// d'utilisation pour le site actuel (la bdd annuaire est la derni�re partie du dsn) |
$dsn_annuaire = $this->communs_papyrus['info_auth_bdd']->gsab_dsn; |
85,97 → 109,173 |
$this->champ_mdp = $this->communs_papyrus['info_auth_bdd']->gsab_nom_champ_mdp; |
} |
|
function getToken() { |
// Premier essai, dans le header |
$headers = @apache_request_headers(); |
$token = !empty($headers['Authorization']) ? $headers['Authorization'] : null; |
// Eventuellement, le jeton a pu �tre pass� dans un header non standard, comme dans |
// le cas o� le header Authorization est supprim� par le mod cgi d'apache |
// Dans ce cas l� on v�rifie aussi dans un header alternatif si celui ci a �t� renseign� |
if($token == null && $this->auth_header != 'Authorization') { |
$token = !empty($headers[$this->auth_header]) ? $headers[$this->auth_header] : null; |
} |
|
// Sinon dans $_REQUEST ? |
if($token == null) { |
$token = !empty($_REQUEST['Authorization']) ? $_REQUEST['Authorization'] : null; |
} |
|
// Sinon dans $_COOKIE ? |
if($token == null) { |
$token = !empty($_COOKIE['tb_auth']) ? $_COOKIE['tb_auth'] : null; |
} |
|
return $token; |
} |
|
public function decoderToken($token) { |
$token_parts = explode('.', $token); |
return json_decode(base64_decode($token_parts[1]), true); |
} |
|
// http://stackoverflow.com/questions/1251582/beautiful-way-to-remove-get-variables-with-php?lq=1 |
function supprimerUrlVar($url, $var) { |
return rtrim(preg_replace('/([?&])'.$var.'=[^&]+(&|$)/','$1',$url), '&?'); |
protected function supprimerUrlVar($url, $var) { |
return rtrim(preg_replace('/([?&])'.$var.'=[^&]*(&|$)/','$1',$url), '&?'); |
} |
|
function connecterEtRediriger() { |
/** |
* Se connecte au SSO : redirige vers le service d'authentification, qui pose |
* le cookie tb_auth, puis re-redirige vers Papyrus avec le jeton en GET, puis |
* Papyrus stocke ce jeton dans son cookie mandataire, puis se re-redirige |
* vers lui-même pour éliminer le paramètre GET de l'URL (ouf !) |
*/ |
public function connecterEtRediriger() { |
//echo "JE CONNECTE<br/>"; |
// sauvegarde de l'URL courante |
$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; |
$params = 'login='.$_POST['username'].'&password='.$_POST['password'].'&redirect_url='.urlencode($url_redirect); |
$connexion_url = $this->annuaire_url."connexion?".$params; |
|
// redirection vers l'annuaire, qui va nous connecter au SSO et nous |
// renvoyer un jeton en GET |
header('Location: '.$connexion_url); |
exit; |
} |
|
function deconnecterEtRediriger() { |
/** |
* Se déconnecte du SSO : redirige vers le service d'authentification, qui |
* supprime le cookie tb_auth, puis re-redirige vers Papyrus avec un jeton |
* vide en GET; Papyrus stocke ce jeton vide dans son cookie mandataire, |
* puis se re-redirige vers lui-même pour éliminer le paramètre GET de l'URL |
*/ |
public function deconnecterEtRediriger() { |
//echo "JE DECONNECTE<br/>"; |
// sauvegarde de l'URL courante |
$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; |
$url_redirect = $this->supprimerUrlVar($url_redirect, 'logout'); |
|
$deconnexion_url = $this->annuaire_url."deconnexion?".'redirect_url='.urlencode($url_redirect); |
|
// redirection vers l'annuaire, qui va nous déconnecter du SSO et nous |
// renvoyer un jeton vide en GET |
header('Location: '.$deconnexion_url); |
exit; |
} |
|
function verifierIdentiteEtRediriger() { |
protected function synchroniserDepuisEtatSso() { |
//echo "JE SYNCHRONISE<br/>"; |
// sauvegarde de l'URL courante |
$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; |
$params = 'redirect_url='.urlencode($url_redirect); |
$identite_url = $this->annuaire_url."identite?".$params; |
// redirection vers l'annuaire, qui va nous donner l'état du SSO et nous |
// renvoyer un jeton en GET |
header('Location: '.$identite_url); |
exit; |
} |
|
/** |
* Appelée à chaque chargement de page |
*/ |
public function verifierIdentiteEtRediriger() { |
// si on fait autre chose qu'un GET, on ne vérifie pas l'identité, car |
// cela conduirait à une redirection en GET (avec le jeton), qui |
// supprimerait les données du corps de la requête |
if ($_SERVER['REQUEST_METHOD'] == "GET") { |
if(empty($_COOKIE['sso_tentative_identification'])) { |
|
if($this->communs_papyrus['pear_auth']->getAuth()) { |
// lecture jeton en GET si on vient de l'annuaire |
if (isset($_GET['Authorization'])) { |
//echo "Re-Redirection pour éliminer le GET<br/>"; |
|
$cookie_persistant_nom = session_name().'-memo'; |
$cookie_utilisateur_nom = session_name().'-utilisateur'; |
|
// Si l'utilisateur est d�j� connect� par pear |
// on fait tout de m�me une op�ration de logout |
// pour coordonner la d�connection depuis une autre application |
$this->communs_papyrus['pear_auth']->logout(); |
// Destruction du cookie de session de Papyrus : est ce utile? |
setcookie(session_name(), session_id(), time()-3600, '/'); |
// Destruction du cookie de permanence de l'identitification de Papyrus |
setcookie($cookie_persistant_nom, '', time()-3600, '/'); |
setcookie($cookie_utilisateur_nom, '', time()-3600, '/'); |
// création / mise à jour du cookie mandataire (le jeton peut être |
// vide en cas de déconnexion) |
$jetonRecu = $_GET['Authorization']; |
if ($jetonRecu == '') { |
$jetonRecu = self::$VALEUR_JETON_VIDE; |
} |
$this->setCookieMandataire($jetonRecu); |
//echo "JETON REÇU: " . $_GET['Authorization']; |
//echo "JETON POSÉ: "; var_dump($jetonRecu); |
//exit; |
|
// redirection pour éliminer le paramètre GET |
$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; |
$url = $this->annuaire_url."identite?redirect_url=".urlencode($url_redirect); |
$url_redirect = $this->supprimerUrlVar($url_redirect, 'Authorization'); |
//echo "URL Redirect: $url_redirect"; exit; |
header('Location: ' . $url_redirect); |
exit; |
} |
|
// une tentative toutes les $this->delai_tentative_identification |
setcookie($this->cookie_tentative_identification, 1, time() + $this->delai_tentative_identification, '/'); |
// une fois qu'on a fait une connexion ou une déconnexion, on se base |
// sur le cookie mandataire pour gérer l'identité dans Papyrus |
//var_dump($_COOKIE); echo "<br/>"; |
// lecture cookie mandataire de Papyrus |
$jeton = null; |
$cookiePresent = false; |
if (isset($_COOKIE[$this->cookie_mandataire])) { |
$cookiePresent = true; |
$jeton = $_COOKIE[$this->cookie_mandataire]; |
} |
//echo "Cookie Présent: "; var_dump($cookiePresent); |
//echo "JETON: "; var_dump($jeton); echo "<br/>"; |
//exit; |
|
header('Location: '.$url); |
// s'il y a un cookie, qu'il contienne un jeton valide ou vide |
if ($cookiePresent) { |
// s'il contient un jeton non-vide |
if ($jeton != self::$VALEUR_JETON_VIDE) { |
// reconnexion PEAR (l'utilisateur peut avoir changé) |
//echo "RECONNEXION!<br/>"; exit; |
$this->deconnexionPear(); |
$this->connexionPear($jeton); |
|
// prolonge le cookie de 30 secondes si on est connecté, pour |
// minimiser les synchros avec le SSO |
$this->setCookieMandataire($jeton, 30); |
|
// si mode synchro partielle, le cookie mandataire dure logntemps, |
// on rafraîchit donc le jeton pour... euh... on sait jamais :-/ |
if (! $this->synchro_complete) { |
// appel annuaire / identité avec jeton en GET |
$infosJson = $this->rafraichirJeton($jeton); |
$infos = json_decode($infosJson, true); |
//echo "INFOS: "; var_dump($infos); echo "<br/>"; |
$jetonRafraichi = null; |
if (isset($infos['token'])) { |
$jetonRafraichi = $infos['token']; |
} |
//echo "JETON Rafraîchi: "; var_dump($jetonRafraichi); echo "<br/>"; |
//exit; |
// si jeton rafraîchi reçu |
if ($jetonRafraichi != null) { |
// màj cookie avec jeton rafraîchi |
$this->setCookieMandataire($jetonRafraichi); |
// reconnexion PEAR (l'utilisateur peut avoir changé) |
$this->deconnexionPear(); |
$this->connexionPear($jetonRafraichi); |
//exit; |
} else { |
$jeton = $this->getToken(); |
// sinon (non connecté ou problème annuaire / jeton) |
// écriture cookie avec jeton vide |
$this->setCookieMandataire(self::$VALEUR_JETON_VIDE); |
// déconnexion PEAR |
$this->deconnexionPear(); |
} |
} |
} else { |
// déconnexion PEAR ? |
$this->deconnexionPear(); |
} |
} else { // sinon (aucun cookie mandataire) |
// en mode synchro complète, on vérifie chaque minute (lorsque le |
// cookie mandataire n'est plus présent) si on n'est pas connecté |
// sur le SSO, sauf si on est en mode non interactif |
if ($this->synchro_complete && (! $this->mode_non_interactif)) { |
$this->synchroniserDepuisEtatSso(); |
} |
} |
} |
} |
|
if($jeton != null) { |
// Verification du jeton aupres de l'annuaire |
$valide = $this->verifierToken($jeton); |
if ($valide === true) { |
protected function setCookieMandataire($valeur, $duree=null) { |
if ($duree === null) { |
$duree = $this->duree_cookie_mandataire; |
} |
setcookie($this->cookie_mandataire, $valeur, time() + $duree); |
} |
|
/** |
* Connecte l'utilisateur à Papyrus avec le système traditionnel fourni par PEAR |
*/ |
protected function connexionPear($jeton) { |
$jeton_decode = $this->decoderToken($jeton); |
|
// R�cup�ration du mot de passe pour remplir les infos de l'objet PEAR Auth |
185,7 → 285,6 |
|
// TODO: normalement �a n'est jamais le cas mais que fait t'on si l'utilisateur n'existe pas |
// dans notre base de donn�es ? (au pire il ne sera pas connect�) |
|
$this->communs_papyrus['pear_auth']->username = $jeton_decode['sub']; |
$this->communs_papyrus['pear_auth']->password = $this->communs_papyrus['pear_db']->getOne($requete); |
|
196,23 → 295,50 |
if (isset($this->communs_papyrus['pear_auth']->storage->options)) { |
$this->communs_papyrus['pear_auth']->storage->options['cryptType'] = 'none'; |
} |
|
// si on fait pas ça, ça marche pas (régénération de session apparemment) |
//$this->communs_papyrus['pear_auth']->setAuth($jeton_decode['sub']); |
} |
|
/** |
* Supprime tout ce qui a trait à PEAR afin de déconnecter l'utilisateur du |
* système d'authentification traditionnel de Papyrus |
*/ |
protected function deconnexionPear() { |
$this->communs_papyrus['pear_auth']->logout(); |
|
$cookie_persistant_nom = session_name().'-memo'; |
$cookie_utilisateur_nom = session_name().'-utilisateur'; |
// Destruction du cookie de session de Papyrus : est ce utile? |
setcookie(session_name(), session_id(), time()-3600, '/'); |
// Destruction du cookie de permanence de l'identitification de Papyrus |
setcookie($cookie_persistant_nom, '', time()-3600, '/'); |
setcookie($cookie_utilisateur_nom, '', time()-3600, '/'); |
} |
} |
} |
} |
|
/** |
* Vérifie un jeton auprès de l'annuaire |
* Fournit un jeton à l'annuaire (jeton provenant du cookie mandataire |
* de Papyrus), le fait rafraîchir puis met à jour le cookie mandataire avec |
* le jeton rafraîchi |
*/ |
protected function verifierToken($token) { |
$verificationServiceURL = $this->annuaire_url . "verifytoken"; |
$verificationServiceURL .= "?token=" . $token; |
protected function rafraichirJeton($jeton) { |
$identiteServiceURL = $this->annuaire_url . "identite"; |
$identiteServiceURL .= "?token=" . $jeton; |
//echo "URL: $identiteServiceURL<br/>"; |
$ch = curl_init($identiteServiceURL); |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); |
$jetonRafraichi = curl_exec($ch); |
//var_dump($jetonRafraichi); |
//var_dump(curl_error($ch)); exit; |
|
$info = file_get_contents($verificationServiceURL); |
$info = json_decode($info, true); |
return $jetonRafraichi; |
} |
|
return ($info === true); |
protected function decoderToken($token) { |
$token_parts = explode('.', $token); |
return json_decode(base64_decode($token_parts[1]), true); |
} |
} |
?> |