1,29 → 1,28 |
<?php |
/** |
* Service d'itentification d'un utilisateur. |
* Modifié pour fonctionner avec le SSO. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* |
* Cas d'utilisation : |
* 1: Aucun login ni mot de passe transmis |
* 1: L'application retourne l'identifiant de session en cours |
* 2: Une identification est toujours active, cette identification est retournée |
* Le service reçoit un jeton SSO (ou pas) dans le header "Authorization", le fait |
* vérifier par l'annuaire; s'il est valide, le décode puis retourne le profil utilisateur |
* associé; sinon retourne un profil anonyme. |
* |
* 2: Ce service recoit un login et un mot de passe |
* 1 : On tente d'identifier l'utilisateur |
* 2 : Si réussi, l'état passe à : connecté |
* 3 : sinon, l'état passe à : pas connecté |
* 1: Aucun jeton ou jeton invalide transmis |
* 1: L'application retourne l'identifiant de session en cours (mode anonyme) |
* |
* 3: Ce service reçoit un identifiant (différent du login) et aucun mot de passe : |
* 1 : Déconnexion |
* 2: Jeton valide transmis |
* 1 : Passe ou reste dans l'état "connecté"; le profil actif est retourné |
* |
* En résumé, utilisation des URLs : |
* /CoelUtilisateur/ : retour identifiant de session si jamais connecté, sinon retour de l'id (+ login et mot de passe) |
* /CoelUtilisateur/ * / * / : idem ci-dessus |
* /CoelUtilisateur/id : déconexion |
* /CoelUtilisateur/login/mot_de_passe : connexion |
* /CoelUtilisateur/identite : retour identifiant de session si jamais connecté, sinon retour de l'id (+ login et mot de passe) |
* |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author David DELON <david.delon@clapas.net>abstract |
* @author David DELON <david.delon@clapas.net> |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt> |
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt> |
* @version $Id$ |
31,171 → 30,77 |
*/ |
class CoelUtilisateur extends Coel { |
|
private $licence_acceptee = false; |
protected $licence_acceptee = false; |
|
// TODO : controle systematique... dans tous les services si connected : name cookie = name service |
/** |
* Point d'entrée GET |
*/ |
public function getRessource(){ |
$this->getElement(array('*','*')); |
} |
|
public function getElement($param){ |
$identification = false; |
$info = array(); |
|
// Si la licence n'a pas été accepté nous réinitialisons tout |
if (!isset($param[2]) && (!isset($_COOKIE['coel_licence']) || (isset($_COOKIE['coel_licence']) && $_COOKIE['coel_licence'] != 1))) { |
// par défaut, mode anonyme |
$infos = $this->getUtilisateurAnonyme(); |
// recherche d'un utilisateur identifié en fonction du jeton SSO |
$infosIdentifie = $this->getUtilisateurSSO(); |
if ($infosIdentifie != null) { |
//echo "Infos SSO : "; var_dump($infosIdentifie); |
$infos = $infosIdentifie; |
// si la licence n'a pas été acceptée, au revoir les enfants |
// on envoie tout de même les infos à l'interface mais on déconnecte les services |
$this->deconnecterUtilisateur(); |
} |
|
// S'il y a 3 paramètres, c'est qu'on cherche à mettre à jour la licence |
if (isset($param[2])) { |
$this->debug[] = "Licence acceptee"; |
$this->licence_acceptee = true; |
// Mise à jour de la licence |
if (!$this->accepterLicence($param[0])) { |
$this->debug[] = "Erreur de mise à jour licence utilisateur"; |
// et vlan, passe-moi l'éponge |
$this->envoyer($infos); |
} |
} else if (isset($param[1])) { // Non connecté : vérification |
if (!$this->getUtilisateur()) { // Si non identifié |
$id = null; |
if ($param[0] == '*' && $param[1] == '*') { // Tentative d'identification depuis les cookies permanents |
if (isset($_COOKIE['coel_login']) && ($this->souvenirUtilisateur($_COOKIE['coel_login'], $_COOKIE['coel_mot_de_passe']))) { |
$id = $this->getUtilisateurId(); |
$identification = true; |
$info = array($id, $identification, $this->getUtilisateurNomComplet(), $this->getUtilisateurPrenom(), $this->getUtilisateurNom(), $this->getParametre()); |
} |
} else if ($this->connecterUtilisateur($param[0], $param[1], 1)) { // Tentative d'identification depuis les paramêtres passés dans l'url du service |
$id = $this->getUtilisateurId(); |
$identification = true; |
$info = array($id, $identification, $this->getUtilisateurNomComplet(), $this->getUtilisateurPrenom(), $this->getUtilisateurNom(), $this->getParametre()); |
} |
|
// L'identification a échouée, nous retournons un session_id comme identifiant |
if (is_null($id)) { |
$id = session_id(); |
$identification = false; |
$info = array($id, $identification); |
/** |
* Renvoie un profil utilisateur CoeL anonyme |
* (licence vide, id de session, non connecté) |
*/ |
protected function getUtilisateurAnonyme() { |
$info = array("", session_id(), false); |
return $info; |
} |
} else { // Déjà identifié |
$id = $this->getUtilisateurId(); |
$identification = true; |
$info = array($id, $identification, $this->getUtilisateurNomComplet(), $this->getUtilisateurPrenom(), $this->getUtilisateurNom(), $this->getParametre()); |
} |
} else { // Déconnexion |
$this->deconnecterUtilisateur(); |
$id = session_id(); |
$identification = false; |
$info = array($id, $identification); |
} |
|
array_unshift($info, $this->getLicence()); |
/** |
* Recherche un jeton SSO dans l'entête HTTP "Authorization", vérifie ce |
* jeton auprès de l'annuaire et en cas de succès charge les informations |
* de l'utilisateur associé; si besoin, copie l'utilisateur dans la table |
* Personnes de CoeL |
* |
* @return Array un profil utilisateur ou null |
*/ |
protected function getUtilisateurSSO() { |
$utilisateur = null; |
// lecture du jeton |
$jeton = $this->lireJetonEntete(); |
//echo "Jeton : "; var_dump($jeton); |
if ($jeton != null) { |
// validation par l'annuaire |
$valide = $this->verifierJeton($jeton); |
if ($valide === true) { |
// décodage du courriel utilisateur depuis le jeton |
$donneesJeton = $this->decoderJeton($jeton); |
if ($donneesJeton != null && $donneesJeton["sub"] != "") { |
// récupération de l'utilisateur |
$courriel = $donneesJeton["sub"]; |
|
// Envoie sur la sortie standard |
$this->envoyer($info); |
} |
|
private function getUtilisateurId() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['id']; |
} else { |
return ''; |
} |
} |
|
private function getUtilisateurLogin() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['login']; |
} else { |
return ''; |
} |
} |
|
private function getUtilisateurNomComplet() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['nom_complet']; |
} else { |
return ''; |
} |
} |
|
private function getUtilisateurPrenom() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['prenom']; |
} else { |
return ''; |
} |
} |
|
private function getUtilisateurNom() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['nom']; |
} else { |
return ''; |
} |
} |
|
private function getParametre() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['parametre']; |
} else { |
return ''; |
} |
} |
|
private function getLicence() { |
if (!empty($_SESSION['coel_utilisateur'])) { |
return (string) $_SESSION['coel_utilisateur']['licence']; |
} else { |
return ''; |
} |
} |
|
private function getInfosAnnuaire() { |
if (!empty($_SESSION['coel_infosAnnuaire'])) { |
return $_SESSION['coel_infosAnnuaire']; |
} else { |
return ''; |
} |
} |
|
private function deconnecterUtilisateur() { |
$_SESSION['coel_utilisateur'] = ''; |
$_SESSION['coel_infosAnnuaire'] = ''; |
$this->supprimerCookie('coel_login'); |
$this->supprimerCookie('coel_mot_de_passe'); |
$this->supprimerCookie('coel_licence'); |
$this->supprimerCookie('coel_permanence'); |
} |
|
private function connecterUtilisateur($login, $mot_de_passe, $permanence = 1) { |
// Dans tous les cas, on récupère les informations de l'utilisateur présentes dans l'annuaire de Tela Botanica |
$infosAnnuaire = $this->obtenirInfosAnnuaire($login); |
// lecture des infos dans l'annuaire (relou mais nécessaire pour la copie dans la table Personnes de CoeL) |
$infosAnnuaire = $this->obtenirInfosAnnuaire($courriel); |
$this->setInfosAnnuaire($infosAnnuaire); |
//echo "Infos Annu: "; var_dump($infosAnnuaire); |
|
if ($mot_de_passe == 'debug' && $utilisateur_existant = $this->chargerUtilisateur($login)) { |
$this->setUtilisateur($utilisateur_existant, $permanence); |
return true; |
} else { |
$mot_de_passe_sha1 = sha1($mot_de_passe); |
$mot_de_passe_md5 = md5($mot_de_passe); |
if ($utilisateur_existant = $this->chargerUtilisateur($login, $mot_de_passe_sha1)) { |
// OK, nous poursuivons |
} else if ($utilisateur_existant = $this->chargerUtilisateur($login, $mot_de_passe_md5)) { |
// Mise à jour du mot de passe md5 en sha1 |
$this->mettreAJourMotDePasse($login, $mot_de_passe_md5, $mot_de_passe_sha1); |
$utilisateur_existant['mot_de_passe'] = $mot_de_passe_sha1; |
} |
// lecture de l'utilisateur connu (ou pas) par CoeL (table Personnes) |
$utilisateur_existant = $this->chargerUtilisateur($courriel); |
//echo "UTIL EXIST: "; var_dump($utilisateur_existant); |
|
// Vérification de la nécessité de mettre à jour l'utilisateur du COEL vis à vis de l'annuaire de Tela Botanica |
// Vérification de la nécessité de mettre à jour l'utilisateur COEL vis à vis de l'annuaire de Tela Botanica |
if (!is_null($infosAnnuaire) && $this->avoirBesoinMiseAJour($utilisateur_existant)) { |
$this->debug[] = "Besoin d'une mise à jour"; |
// Vérifions que la personne s'est bien identifiée |
if ($infosAnnuaire['mot_de_passe'] == $mot_de_passe_md5) { |
$this->debug[] = "Identification correcte avec md5"; |
$utilisateur_existant = $this->getInfoAnnuaireCoelDepuisInfoAnnuaireDistant($mot_de_passe_sha1, $infosAnnuaire); |
|
$presence_dans_coel = $this->verifierPresenceUtilisateur($infosAnnuaire['id']); |
$presence_dans_coel = ($utilisateur_existant != false); // si on l'a trouvé juste au dessus |
$this->debug[] = "Presence:$presence_dans_coel"; |
$mot_de_passe_sha1 = $infosAnnuaire['pass']; |
//echo "MDP: " .$mot_de_passe_sha1; |
|
if ($presence_dans_coel) { |
// Nécessite de faire une mise à jour |
$this->debug[] = "Mise à jour de l'utilisateur {$infosAnnuaire['id']}"; |
202,34 → 107,39 |
$this->mettreAJourUtilisateur($login, $mot_de_passe_sha1, $infosAnnuaire); |
$utilisateur_existant['licence'] = (int) $this->recupererLicenceUtilisateur($infosAnnuaire['id']); |
} else { |
echo "Insertion"; |
// Nécessite d'ajouter le nouvel utilisateur |
$this->debug[] = "Ajout d'une nouvel utilisateur"; |
$this->ajouterUtilisateurACoel($infosAnnuaire, $mot_de_passe_sha1); |
// rechargement après l'avoir ajouté (un peu nul) |
$utilisateur_existant = $this->chargerUtilisateur($courriel); |
} |
|
$this->setUtilisateur($utilisateur_existant, $permanence); |
} else { |
$this->debug[] = "Identification INCORRECTE avec md5"; |
return false; |
$this->setUtilisateur($utilisateur_existant); |
} |
} else if ($utilisateur_existant != false) { |
// L'utilisateur est toutefois présent dans l'annuaire de COEL, est correctement identifié et n'a pas besoin de mise à jour |
$this->setUtilisateur($utilisateur_existant, $permanence); |
} else { |
// L'utilisateur n'existe ni dans l'annuaire de Tela Botanica ni dans celui de COEL |
return false; |
} |
|
// L'utilisateur a t il accepté la licence? Nécessaire pour être connecté! |
if ($utilisateur_existant['licence'] == 1) { |
return true; |
} else { |
return false; |
// stockage de l'utilisateur en session |
$this->setUtilisateur($utilisateur_existant); |
|
// renvoi des infos |
$utilisateur = array($utilisateur_existant['licence'], $infosAnnuaire['id'], true, $this->getUtilisateurNomComplet(), $this->getUtilisateurPrenom(), $this->getUtilisateurNom(), $this->getParametre()); |
} |
} |
} |
|
private function avoirBesoinMiseAJour($info_annuaire_coel) { |
return $utilisateur; |
} |
|
protected function deconnecterUtilisateur() { |
$_SESSION['coel_utilisateur'] = ''; |
$_SESSION['coel_infosAnnuaire'] = ''; |
} |
|
/** |
* Retourne true si le compte utilisateur a été modifié dans l'annuaire, et que les |
* modifications ont besoin d'être répercutées dans la table Personnes de Coel |
*/ |
protected function avoirBesoinMiseAJour($info_annuaire_coel) { |
$necessite_maj = false; |
if ($info_annuaire_coel == false) { |
// Le login et/ou le mot de passe a pu changer |
243,7 → 153,7 |
return $necessite_maj; |
} |
|
private function comparerInfosAnnuairesDistantEtCoel($annuaire_distant, $annuaire_coel) { |
protected function comparerInfosAnnuairesDistantEtCoel($annuaire_distant, $annuaire_coel) { |
$identique = true; |
$tableau_annuaire_distant = array('nom' => $annuaire_distant['nom'], |
'prenom' => $annuaire_distant['prenom'], |
262,16 → 172,10 |
return $identique; |
} |
|
private function getInfoAnnuaireCoelDepuisInfoAnnuaireDistant($mot_de_passe_sha1, $infos) { |
$cp_fmt_nom_complet = $infos['prenom'].' '.$infos['nom']; |
$utilisateur_existant = array('id' => $infos['id'], 'login' => $infos['courriel'], |
'mot_de_passe' => $mot_de_passe_sha1, |
'nom_complet' => $cp_fmt_nom_complet, 'nom' => $infos['nom'], 'prenom' => $infos['prenom'], |
'parametre' => '', 'licence' => '0'); |
return $utilisateur_existant; |
} |
|
private function verifierPresenceUtilisateur($id) { |
/** |
* Vérifie si un utilisateur est présent dans la table Personnes de CoeL |
*/ |
protected function verifierPresenceUtilisateur($id) { |
$present = false; |
$requete = 'SELECT COUNT(cp_id_personne) AS nbre '. |
'FROM coel_personne '. |
294,7 → 198,11 |
return $present; |
} |
|
private function recupererLicenceUtilisateur($id) { |
/** |
* Renvoie l'état d'acceptation de la licence pour un utilisateur donné : |
* 0 (non acceptée) ou 1 (acceptée) |
*/ |
protected function recupererLicenceUtilisateur($id) { |
$requete = 'SELECT cp_mark_licence '. |
'FROM coel_personne '. |
"WHERE cp_ce_annuaire = {$this->bdd->quote($id)} ". |
312,24 → 220,11 |
} |
} |
|
private function mettreAJourMotDePasse($login, $mot_de_passe_md5, $mot_de_passe_sha1) { |
/** |
* Met à jour les données de l'utilisateur dans la table CoeL Personnes |
*/ |
protected function mettreAJourUtilisateur($login, $mot_de_passe_sha1, $infos) { |
try { |
$requete = 'UPDATE coel_personne '. |
"SET cp_mot_de_passe = '$mot_de_passe_sha1' ". |
"WHERE cp_login = '$login' ". |
" AND cp_mot_de_passe = '$mot_de_passe_md5' "; |
// Ajout des données |
$resultat = $this->bdd->exec($requete); |
if ($resultat === false) { |
$this->messages[] = "Le mot de passe de l'utilisateur n'a pas été mis à jour car la requête a échouée."; |
} |
} catch (PDOException $e) { |
$messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete); |
} |
} |
|
private function mettreAJourUtilisateur($login, $mot_de_passe_sha1, $infos) { |
try { |
$cp_fmt_nom_complet = $infos['prenom'].' '.$infos['nom']; |
$requete = 'UPDATE coel_personne '. |
"SET cp_id_personne = '{$infos['id']}', ". |
349,7 → 244,10 |
} |
} |
|
private function ajouterUtilisateurACoel($infos, $mot_de_passe_sha1) { |
/** |
* Ajoute une copie de l'utilisateur dans la table CoeL Personnes |
*/ |
protected function ajouterUtilisateurACoel($infos, $mot_de_passe_sha1) { |
try { |
// Construction de la requête d'ajout |
// Notes : pour rester compatibles avec l'annuaire de Tela, les utilisateurs sont ajoutés directement avec l'id |
375,20 → 273,10 |
} |
} |
|
private function souvenirUtilisateur($login, $mot_de_passe_sha1) { |
if ($login == '' && $mot_de_passe_sha1 == '') { |
return false; |
} else if ($utilisateur_existant = $this->chargerUtilisateur($login, $mot_de_passe_sha1)) { |
if ($utilisateur_existant['mot_de_passe'] == $mot_de_passe_sha1) { |
$this->setUtilisateur($utilisateur_existant, $_COOKIE['coel_permanence']); |
return true; |
} else { |
return false; |
} |
} |
} |
|
private function obtenirInfosAnnuaire($login) { |
/** |
* Appelle l'annuaire pour connaître tous les détails de l'utilisateur de courriel $login |
*/ |
protected function obtenirInfosAnnuaire($login) { |
$url_annuaire = $this->config['coel']['urlAnnuaire']; |
$login_annuaire = $this->config['coel']['loginAnnuaire']; |
$mdp_annuaire = $this->config['coel']['mdpAnnuaire']; |
414,11 → 302,10 |
return $tableau_annuaire; |
} |
|
private function setInfosAnnuaire($infosAnnuaire) { |
$_SESSION['coel_infosAnnuaire'] = $infosAnnuaire; |
} |
|
private function accepterLicence($login) { |
/** |
* Enregistre le fait que la personne de login $login a accepté la licence de CoeL |
*/ |
protected function accepterLicence($login) { |
$sortie = false; |
try { |
$requete = 'UPDATE coel_personne '. |
426,10 → 313,11 |
"WHERE cp_login = {$this->bdd->quote($login)} "; |
$resultat = $this->bdd->exec($requete); |
if ($resultat === false) { |
$this->debug[] = "La table Personne n'a pas été mise à jour car la requête a échouée."; |
$this->debug[] = "La table Personne n'a pas été mise à jour car la requête a échoué"; |
} else { |
$this->debug[] = "Création du cookie licence."; |
$_SESSION['coel_utilisateur']['licence'] = '1'; |
// @TODO CHANGER |
$this->setCookiePersistant('coel_licence', '1'); |
$sortie = true; |
} |
438,5 → 326,140 |
} |
return $sortie; |
} |
|
/** |
* Essaye de trouver un jeton JWT non vide dans l'entête HTTP "Authorization" |
* |
* @return String un jeton JWT ou null |
*/ |
protected function lireJetonEntete() { |
$jwt = null; |
$headers = apache_request_headers(); |
if (isset($headers["Authorization"]) && ($headers["Authorization"] != "")) { |
$jwt = $headers["Authorization"]; |
} |
return $jwt; |
} |
|
/** |
* Vérifie un jeton auprès de l'annuaire |
* |
* @param String $jeton un jeton JWT |
* @return true si le jeton est vérifié, false sinon |
*/ |
protected function verifierJeton($jeton) { |
$urlServiceVerification =$this->config['coel']['urlServiceBaseAuth'] . "verifierjeton"; |
$urlServiceVerification .= "?token=" . $jeton; |
|
// file_get_contents râle si le certificat HTTPS est auto-signé |
//$retour = file_get_contents($urlServiceVerification); |
|
// curl avec les options suivantes ignore le pb de certificat (pour tester en local) |
$ch = curl_init(); |
$timeout = 5; |
curl_setopt($ch, CURLOPT_URL, $urlServiceVerification); |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); |
// équivalent de "-k" |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
$data = curl_exec($ch); |
curl_close($ch); |
$retour = $data; |
|
$retour = json_decode($retour, true); |
|
return ($retour === true); |
} |
|
/** |
* Décode un jeton JWT (SSO) précédemment validé et retourne les infos |
* qu'il contient (payload / claims) |
* @param String $jeton un jeton JWT précédemment validé |
*/ |
protected function decoderJeton($jeton) { |
$parts = explode('.', $jeton); |
$payload = $parts[1]; |
$payload = base64_decode($payload); |
$payload = json_decode($payload, true); |
|
return $payload; |
} |
|
// accesseurs à deux ronds |
protected function getUtilisateurId() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['id']; |
} else { |
return ''; |
} |
} |
protected function getUtilisateurLogin() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['login']; |
} else { |
return ''; |
} |
} |
protected function getUtilisateurNomComplet() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['nom_complet']; |
} else { |
return ''; |
} |
} |
protected function getUtilisateurPrenom() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['prenom']; |
} else { |
return ''; |
} |
} |
protected function getUtilisateurNom() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['nom']; |
} else { |
return ''; |
} |
} |
protected function getParametre() { |
if ($utilisateur = $this->getUtilisateur()) { |
return $utilisateur['parametre']; |
} else { |
return ''; |
} |
} |
protected function getLicence() { |
if (!empty($_SESSION['coel_utilisateur'])) { |
return (string) $_SESSION['coel_utilisateur']['licence']; |
} else { |
return ''; |
} |
} |
protected function getInfosAnnuaire() { |
if (!empty($_SESSION['coel_infosAnnuaire'])) { |
return $_SESSION['coel_infosAnnuaire']; |
} else { |
return ''; |
} |
} |
protected function setInfosAnnuaire($infosAnnuaire) { |
$_SESSION['coel_infosAnnuaire'] = $infosAnnuaire; |
} |
} |
|
/** |
* Compatibilité avec nginx - merci http://php.net/manual/fr/function.getallheaders.php |
*/ |
if (! function_exists('apache_request_headers')) { |
function apache_request_headers() { |
$headers = ''; |
foreach ($_SERVER as $name => $value) { |
if (substr($name, 0, 5) == 'HTTP_') { |
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; |
} |
} |
return $headers; |
} |
} |
?> |