Subversion Repositories eFlore/Applications.coel

Compare Revisions

Ignore whitespace Rev 1905 → Rev 1906

/trunk/jrest/jrest.ini.php.defaut
16,6 → 16,7
urlBaseJrest = "http://www.tela-botanica.org/eflore/coel/jrest/"
aideBaseUrlTpl = "http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki="
urlAnnuaire = "http://www.tela-botanica.org/service:annuaire-test:utilisateur/identite-complete-par-courriel"
urlServiceBaseAuth = "https://www.tela-botanica.org/service-test:annuaire:auth/"
loginAnnuaire =
mdpAnnuaire =
correctionLogin =
/trunk/jrest/services/CoelUtilisateur.php
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$
30,206 → 29,117
* @copyright 2009
*/
class CoelUtilisateur extends Coel {
private $licence_acceptee = false;
// TODO : controle systematique... dans tous les services si connected : name cookie = name service
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))) {
protected $licence_acceptee = false;
 
/**
* Point d'entrée GET
*/
public function getRessource() {
// 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";
}
} 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());
// et vlan, passe-moi l'éponge
$this->envoyer($infos);
}
 
/**
* Renvoie un profil utilisateur CoeL anonyme
* (licence vide, id de session, non connecté)
*/
protected function getUtilisateurAnonyme() {
$info = array("", session_id(), false);
return $info;
}
 
/**
* 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"];
 
// 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);
 
// 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 COEL vis à vis de l'annuaire de Tela Botanica
if (!is_null($infosAnnuaire) && $this->avoirBesoinMiseAJour($utilisateur_existant)) {
$this->debug[] = "Besoin d'une mise à jour";
 
$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']}";
$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);
}
} 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);
 
// 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());
}
} 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());
// Envoie sur la sortie standard
$this->envoyer($info);
return $utilisateur;
}
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() {
protected 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);
$this->setInfosAnnuaire($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;
}
// Vérification de la nécessité de mettre à jour l'utilisateur du 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']);
$this->debug[] = "Presence:$presence_dans_coel";
if ($presence_dans_coel) {
// Nécessite de faire une mise à jour
$this->debug[] = "Mise à jour de l'utilisateur {$infosAnnuaire['id']}";
$this->mettreAJourUtilisateur($login, $mot_de_passe_sha1, $infosAnnuaire);
$utilisateur_existant['licence'] = (int) $this->recupererLicenceUtilisateur($infosAnnuaire['id']);
} else {
// Nécessite d'ajouter le nouvel utilisateur
$this->debug[] = "Ajout d'une nouvel utilisateur";
$this->ajouterUtilisateurACoel($infosAnnuaire, $mot_de_passe_sha1);
}
$this->setUtilisateur($utilisateur_existant, $permanence);
} else {
$this->debug[] = "Identification INCORRECTE avec md5";
return false;
}
} 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;
}
}
}
private function avoirBesoinMiseAJour($info_annuaire_coel) {
/**
* 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'],
261,17 → 171,11
}
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 '.
293,8 → 197,12
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)} ".
311,25 → 219,12
$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
}
}
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']}', ".
348,8 → 243,11
$messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
}
}
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
374,21 → 272,11
$messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
}
}
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;
}
}
?>
/trunk/jrest/services/Coel.php
551,7 → 551,11
protected function getUtilisateur() {
return (isset($_SESSION['coel_utilisateur']) ? $_SESSION['coel_utilisateur'] : '');
}
 
/**
* Tente de trouver un utilisateur dans la table Personnes de CoeL, en fonction de son
* courriel ($login); si le mot de passe est fournie, le vérifie, sinon l'ignore
*/
protected function chargerUtilisateur($login, $mot_de_passe = null) {
$sortie = false;
$requete = 'SELECT cp_id_personne AS id, cp_fmt_nom_complet AS nom_complet, cp_prenom AS prenom, '.
583,14 → 587,20
return $sortie;
}
 
/**
* Définit un utilisateur comme "actif" en plaçant un objet Utilisateur dans la session;
* Ne pose plus de cookies depuis l'adaptation au SSO, sauf pour la licence (acceptée ou non)
* @param unknown $utilisateur
* @param number $permanence
*/
protected function setUtilisateur($utilisateur, $permanence = 1) {
$_SESSION['coel_utilisateur'] = $utilisateur;
$this->debug[] = $_SESSION['coel_utilisateur'];
$this->setCookiePersistant('coel_login', $utilisateur['login'], $permanence);
//$this->debug[] = $_SESSION['coel_utilisateur'];
/*$this->setCookiePersistant('coel_login', $utilisateur['login'], $permanence);
$this->setCookiePersistant('coel_mot_de_passe', $utilisateur['mot_de_passe'], $permanence);
$this->setCookiePersistant('coel_permanence', $permanence, $permanence);*/
$this->setCookiePersistant('coel_licence', $utilisateur['licence'], $permanence);
$this->setCookiePersistant('coel_permanence', $permanence, $permanence);
}
protected function setCookiePersistant($cookie_nom, $valeur, $permanence = 1) {
664,7 → 674,7
}
 
/*
* Retourne une pair de coordonnée depuis un tableau représentant une adresse
* Retourne une paire de coordonnée depuis un tableau représentant une adresse
* ou une adresse partielle à l'aide du service Nominatim.
* (http://wiki.openstreetmap.org/wiki/Nominatim)
*
/trunk/src/org/tela_botanica/client/Mediateur.java
160,9 → 160,9
creerPanneauSud();
fenetreJournal = new FenetreJournal(this);
// Connection de l'utilisateur
connecterUtilisateur(null, null);
// Connexion de l'utilisateur
getEtatUtilisateur();
 
// Creer la table qui gère le panneau de chargement/déchargement
fileDAttenteChargement = new HashMap<Object, Integer>();
440,6 → 440,10
public void deconnecterUtilisateur() {
modele.deconnecterUtilisateur(this);
}
 
public void getEtatUtilisateur() {
modele.getEtatUtilisateur(this);
}
public void repandreEtatIdentification(Utilisateur utilisateur) {
// Mise à jour du registre
/trunk/src/org/tela_botanica/client/configuration/Configuration.java
89,6 → 89,7
listesId.put("nbElementsPage", Integer.valueOf(configuration.get("nbElementsPage")));
listesId.put("relationPersonnePublication", Integer.valueOf(configuration.get("relationPersonnePublication")));
urls.put("base", configuration.get("serviceBaseUrl"));
urls.put("baseAuth", configuration.get("serviceAuthBaseUrl"));
urls.put("cel", configuration.get("celUrl"));
urls.put("remarques", configuration.get("remarquesUrl"));
urls.put("bogue", configuration.get("bogueUrl"));
117,7 → 118,15
public String getServiceBaseUrl() {
return getUrl("base");
}
/**
* Accesseur pour l'url de base du service annuaire::auth
*/
public String getAuthServiceBaseUrl() {
return getUrl("baseAuth");
}
 
 
public String getUrl(String code) {
if (urls.containsKey(code)) {
return urls.get(code);
/trunk/src/org/tela_botanica/client/util/UtilDAO.java
18,6 → 18,7
public class UtilDAO {
private static String baseUrl = ((Configuration) Registry.get(RegistreId.CONFIG)).getServiceBaseUrl();
private static String baseAuthUrl = ((Configuration) Registry.get(RegistreId.CONFIG)).getAuthServiceBaseUrl();
public static final String GET = "GET";
public static final String POST = "POST";
public static final String DELETE = "DELETE";
95,9 → 96,32
}
return cheminUrl;
}
 
/**
* Construit un JsonRestRequestBuilder avec le header Authorization
*/
public static JsonRestRequestBuilder construireRequeteAuth(String nomService, HashMap<String, String> parametres) {
return construireRequeteAuth(nomService, parametres, true);
}
 
/**
* Construit un JsonRestRequestBuilder simple; si authorizationHeader vaut true, ajoute le header
* "Authorization" pour le service d'authentification SSO (annuaire::auth)
*
* @param nomService le nom du service (identite, login, logout...)
* @param parametres tableau de paramètres
* @param boolean authorizationHeader si true, enverra le jeton (si existant) dans un header Authorization
* @return JsonRestRequestBuilder
*/
public static JsonRestRequestBuilder construireRequeteAuth(String nomService, HashMap<String, String> parametres, boolean authorizationHeader) {
String parametresUrl = construireUrlParametres(parametres);
String urlComplete = baseAuthUrl + nomService + parametresUrl;
String urlCompleteEncodee = URL.encode(urlComplete);
JsonRestRequestBuilder jrrb = new JsonRestRequestBuilder(JsonRestRequestBuilder.GET, urlCompleteEncodee, authorizationHeader);
return jrrb;
}
 
public static String getUrlService(String nomService) {
return baseUrl + nomService;
}
}
/trunk/src/org/tela_botanica/client/http/JsonRestRequestBuilder.java
11,9 → 11,15
 
public class JsonRestRequestBuilder extends RequestBuilderWithCredentials {
 
// avec header "Authorization"
public JsonRestRequestBuilder(Method httpMethod, String url) {
super(httpMethod, url);
}
 
// ajoute le header "Authorization" si authorizationHeader vaut true
public JsonRestRequestBuilder(Method httpMethod, String url, boolean authorizationHeader) {
super(httpMethod, url, authorizationHeader);
}
public Request envoyerRequete(String donneesRequete, RequestCallback retour) {
Request requeteSortie = null;
/trunk/src/org/tela_botanica/client/http/RequestBuilderWithCredentials.java
1,11 → 1,27
package org.tela_botanica.client.http;
 
import org.tela_botanica.client.modeles.Utilisateur;
 
import com.google.gwt.http.client.RequestBuilder;
 
public class RequestBuilderWithCredentials extends RequestBuilder {
 
/**
* Crée une requête AJAX avec les headers "Credentials" (pour CORS) et "Authorization" (pour SSO)
*/
public RequestBuilderWithCredentials(Method httpMethod, String url) {
this(httpMethod, url, true);
}
 
/**
* Crée une requête AJAX avec les headers "Credentials" (pour CORS); si authorizationHeader est true,
* ajoute le header "Authorization" pour SSO
*/
public RequestBuilderWithCredentials(Method httpMethod, String url, boolean authorizationHeader) {
super(httpMethod, url);
if(authorizationHeader && Utilisateur.getJeton() != null && ! Utilisateur.getJeton().isEmpty()) {
this.setHeader("Authorization", Utilisateur.getJeton());
}
this.setIncludeCredentials(true);
}
}
/trunk/src/org/tela_botanica/client/http/JsonRestRequestCallback.java
37,7 → 37,7
// Affichage du débogage.
afficherDebug(response);
// Si le code de réponse HTTP ne vaut pas 200 OK, on lance le mécanise d'erreur HTTP
// Si le code de réponse HTTP ne vaut pas 200 OK, on lance le mécanisme d'erreur HTTP
if (response.getStatusCode() != 200) {
onErrorHTTP(request, response);
} else {
/trunk/src/org/tela_botanica/client/Modele.java
92,6 → 92,11
uDao.deconnecterUtilisateur();
}
public void getEtatUtilisateur(Rafraichissable vue) {
UtilisateurAsyncDao uDao = new UtilisateurAsyncDao(vue);
uDao.getEtatUtilisateur();
}
public void accepterLicence(Rafraichissable vue) {
UtilisateurAsyncDao uDao = new UtilisateurAsyncDao(vue);
uDao.accepterLicence();
/trunk/src/org/tela_botanica/client/modeles/Utilisateur.java
1,6 → 1,5
package org.tela_botanica.client.modeles;
 
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
 
9,6 → 8,11
public class Utilisateur extends aDonnee {
 
private static final long serialVersionUID = -4016615552202089985L;
 
// Jeton encodé en base64 passé de manière automatique aux services dans un header
private static String jeton = "";
// Durée de vie du jeton en secondes (sert au rafraîchissement automatique)
private static int duree = 0;
public static final String PREFIXE = "cp";
public static String[] champsObligatoires = {"cp_id_personne"};
141,6 → 145,22
public void setParametre(String param) {
set("parametre", param);
}
 
public static String getJeton() {
return Utilisateur.jeton;
}
 
public static void setJeton(String jeton) {
Utilisateur.jeton = jeton;
}
 
public static int getDureeJeton() {
return Utilisateur.duree;
}
 
public static void setDureeJeton(int duree) {
Utilisateur.duree = duree;
}
// +---------------------------------------------------------------------------------------------------------------+
// IDENTIFIÉ
/trunk/src/org/tela_botanica/client/modeles/AuthInfo.java
New file
0,0 → 1,30
package org.tela_botanica.client.modeles;
 
/**
* Une mini classe pour stocker facilement le retour d'un appel aux services
* annuaire:auth (connexion, deconnexion, identite)
*
* @author mathias
*/
public class AuthInfo {
 
public String token;
public boolean session;
public String tokenId;
public int duration;
public Integer lastModif; // Integer pour pouvoir mettre null dedans
public String error;
 
public AuthInfo(String token, boolean session, String tokenId, int duration, Integer lastModif, String error) {
this.token = token;
this.session = session;
this.tokenId = tokenId;
this.duration = duration;
this.lastModif = lastModif;
this.error = error;
}
 
public AuthInfo() {
this(null, false, null, 0, null, null);
}
}
/trunk/src/org/tela_botanica/client/modeles/UtilisateurAsyncDao.java
1,5 → 1,8
package org.tela_botanica.client.modeles;
 
import java.util.HashMap;
 
import org.tela_botanica.client.Coel;
import org.tela_botanica.client.RegistreId;
import org.tela_botanica.client.http.JsonRestRequestBuilder;
import org.tela_botanica.client.http.JsonRestRequestCallback;
7,11 → 10,15
import org.tela_botanica.client.util.UtilDAO;
 
import com.extjs.gxt.ui.client.Registry;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.Response;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.Timer;
 
/**
* Modele DAO, specifique, permettant la validation, l'acces aux donnees distantes et la présentation des donnees en retour
22,6 → 29,8
private Utilisateur utilisateur = null;
private Rafraichissable vueARafraichir = null;
 
private static Timer rafraichisseurJeton = null;
/**
* Constructeur
31,72 → 40,196
vueARafraichir = vueARafraichirCourrante;
utilisateur = (Utilisateur) Registry.get(RegistreId.UTILISATEUR_COURANT);
}
 
/**
* Méthode de classe d'appel du service des gestion d'identification.
* Recupere des informations d'authentification à partir du JSON renvoyé par les
* services Auth de l'annuaire (SSO)
*
* @param valeurJson
* @return AuthInfo
*/
public void getEtatUtilisateur() {
final JsonRestRequestBuilder rb = UtilDAO.construireRequete(SERVICE_NOM);
rb.envoyerRequete(null, new JsonRestRequestCallback() {
@Override
public void surReponse(JSONValue responseValue) {
if (responseValue.isArray() != null) {
final JSONArray reponse = responseValue.isArray();
// Identifiant utilisateur ou identifiant de session si non identifié
String login = ((JSONString) reponse.get(2)).stringValue();
// Drapeau leve si utilisateur deja identifié
boolean identifie = ((JSONBoolean) reponse.get(3)).booleanValue();
utilisateur.setIdentification(identifie);
utilisateur.setLogin(login);
vueARafraichir.rafraichir(utilisateur);
public static AuthInfo parserAuthJson(JSONValue valeurJson) {
AuthInfo authInfo = new AuthInfo();
JSONObject authJson = valeurJson.isObject();
 
JSONValue erreurJSON = authJson.get("error");
// test si erreur
if (erreurJSON != null) {
JSONString erreur = erreurJSON.isString();
if (erreur != null) {
authInfo.error = erreur.stringValue();
} else {
authInfo.error = "erreur d'authentification";
}
} else {
boolean session = authJson.get("session").isBoolean().booleanValue();
authInfo.session = session;
// test si session ouverte
if (session) {
JSONValue tokenJson = authJson.get("token");
String token = null;
// protection paranoïaque
if (tokenJson != null) {
JSONString tokenString = tokenJson.isString();
if (tokenString != null) {
token = tokenString.stringValue();
}
}
String tokenId = authJson.get("token_id").isString().stringValue();
int duration = (int) authJson.get("duration").isNumber().doubleValue();
JSONValue lastModifJson = authJson.get("last_modif");
 
authInfo.token = token;
authInfo.tokenId = tokenId;
authInfo.duration = duration;
// test si lastModif est null
if (lastModifJson != null) {
JSONNumber lastModif = lastModifJson.isNumber();
if (lastModif != null) {
authInfo.lastModif = (int) lastModif.doubleValue();
}
}
}
});
}
return authInfo;
}
 
/**
* Enregistre le jeton (potentiellement NULL), sa durée de vie; appelle le service Coel pour
* obtenir les données de l'utilisateur relatives à l'application; lorsque le jeton
* n'est pas nul et que sa durée de vie est spécifiée, déclenche un rafraîchissement
* périodique du jeton
*
* @param objetRetour le retour de l'appel au service annuaire:auth (connexion, deconnexion ou identite)
*/
protected void gererRetourAuthInfo(AuthInfo objetRetour) {
// Stockage du jeton rafraîchi et de sa durée (pourrait avoir changé)
Utilisateur.setJeton(objetRetour.token);
Utilisateur.setDureeJeton(objetRetour.duration);
 
// Rafraîchissement automatique du jeton - s'annule lorsque le jeton devient nul
if (Utilisateur.getJeton() != null && Utilisateur.getDureeJeton() > 0) {
if (rafraichisseurJeton == null) { // on sait jamais
// 3/4 de la durée de vie du jeton, en millisecondes (ça laisse de la marge)
int delaiRepetition = (Utilisateur.getDureeJeton() * 1000) * 3 / 4;
delaiRepetition = 10000; // debug
rafraichisseurJeton = new Timer() {
@Override
public void run() {
//Coel.LogVersFirebug("rafraichir utilisateur");
// Appel de l'annuaire pour rafraîchir le jeton (cb nul pour l'instant)
getEtatUtilisateur();
}
};
rafraichisseurJeton.scheduleRepeating(delaiRepetition);
}
} else {
if (rafraichisseurJeton != null) { // on sait jamais non plus
rafraichisseurJeton.cancel();
rafraichisseurJeton = null;
}
}
 
// Obtention de l'utilisateur final d'après le service de préférences
//Coel.LogVersFirebug("va chercher utilisateur Coel");
getEtatUtilisateurSansAnnuaire();
}
 
/**
* Méthode déconnectant un utilisateur de l'application.
* @param identifiant de l'utilisateur à déconnecter.
*/
public void deconnecterUtilisateur() {
String[] parametres = {utilisateur.getId()};
final JsonRestRequestBuilder rb = UtilDAO.construireRequete(SERVICE_NOM, parametres);
//Coel.LogVersFirebug("deconnexion");
final JsonRestRequestBuilder rb = UtilDAO.construireRequeteAuth("deconnexion", null);
rb.envoyerRequete(null, new JsonRestRequestCallback() {
@Override
public void surReponse(JSONValue responseValue) {
if (responseValue.isArray() != null) {
final JSONArray reponse = responseValue.isArray();
// Identifiant utilisateur ou identifiant de session si non identifié
String id = ((JSONString) reponse.get(1)).stringValue();
// Drapeau levé si l'utilisateur est déjà identifié
boolean identifie = ((JSONBoolean) reponse.get(2)).booleanValue();
// Nous réinitialisons l'utilisateur
utilisateur = new Utilisateur(id, identifie);
GWT.log(utilisateur.toString(), null);
vueARafraichir.rafraichir(utilisateur);
}
//Coel.LogVersFirebug(responseValue.toString());
AuthInfo info = parserAuthJson(responseValue);
gererRetourAuthInfo(info);
}
});
}
/**
* Méthode connectant un utilisateur à l'application.
* @param Utilisateur l'utilisateur courant.
* Méthode connectant un utilisateur à l'application
*/
public void connecterUtilisateur() {
String[] parametres = {utilisateur.getLogin(), utilisateur.getMotDePasse()};
HashMap<String, String> parametres = new HashMap<String, String>();
parametres.put("login", utilisateur.getLogin());
parametres.put("password", utilisateur.getMotDePasse());
//Coel.LogVersFirebug("connexion");
final JsonRestRequestBuilder rb = UtilDAO.construireRequeteAuth("connexion", parametres);
final JsonRestRequestBuilder rb = UtilDAO.construireRequete(SERVICE_NOM, parametres);
rb.envoyerRequete(null, new JsonRestRequestCallback() {
@Override
public void surReponse(JSONValue responseValue) {
if (responseValue.isArray() != null) {
final JSONArray reponse = responseValue.isArray();
AuthInfo info = parserAuthJson(responseValue);
gererRetourAuthInfo(info);
}
});
}
 
/**
* Va chercher les infos de l'utilisateur en vérifiant d'abord l'identité auprès de l'annuaire
*/
public void getEtatUtilisateur() {
getEtatUtilisateur(false);
}
 
/**
* Va chercher les infos de l'utilisateur; si ignorerAnnuaire est false, vérifiera d'abord
* l'identité auprès de l'annuaire (service annuaire:auth/identite)
*/
public void getEtatUtilisateur(boolean ignorerAnnuaire) {
// par défaut, on appelle d'abord le service auth/identite de l'annuaire, afin de connaître
// le statut de l'utilisateur vis à vis du SSO (connecté ou non) et rafraîchir le jeton
if (! ignorerAnnuaire) {
//Coel.LogVersFirebug("get état");
// sans header Authorization, sinon une déconnexion depuis une autre appli ne sera pas
// prise en compte et le jeton sera rafraîchi indéfiniment
final JsonRestRequestBuilder rb = UtilDAO.construireRequeteAuth("identite", null, false);
rb.envoyerRequete(null, new JsonRestRequestCallback() {
@Override
public void surReponse(JSONValue responseValue) {
AuthInfo info = parserAuthJson(responseValue);
gererRetourAuthInfo(info);
}
@Override
public void onErrorHTTP(Request request, Response reponse) {
// Si on a été déconnecté, on va chercher un profil utilisateur "anonyme" et
// on avertit l'interface
gererRetourAuthInfo(new AuthInfo());
}
});
} else { // sinon on optimise, quand on vient de se (de)connecter, pas la peine de rappeler l'annuaire
getEtatUtilisateurSansAnnuaire();
}
}
 
/**
* Va chercher les infos de l'utilisateur Coel sans vérifier l'identité auprès de l'annuaire;
* transmet un jeton SSO à chaque fois pour que le service se base dessus
*/
public void getEtatUtilisateurSansAnnuaire() {
final JsonRestRequestBuilder rb = UtilDAO.construireRequete(SERVICE_NOM);
rb.envoyerRequete(null, new JsonRestRequestCallback() {
@Override
public void surReponse(JSONValue responseValue) {
//Coel.LogVersFirebug("réponse reçue");
JSONArray reponse = responseValue.isArray();
if (reponse != null) {
// Identifiant utilisateur ou identifiant de session si non identifié
String login = ((JSONString) reponse.get(1)).stringValue();
 
// Drapeau leve si utilisateur deja identifié
boolean identifie = ((JSONBoolean) reponse.get(2)).booleanValue();
 
utilisateur.setIdentification(identifie);
utilisateur.setLogin(login);
 
//Ajout des informations licence
if (reponse.get(0).isString() != null) {
utilisateur.setLicence(reponse.get(0).isString().stringValue());
103,46 → 236,55
} else {
utilisateur.setLicence("");
}
if (reponse.size() > 0) {
 
//Coel.LogVersFirebug("Utilisateur CoeL chargé !!");
//Coel.LogVersFirebug("id: " + identifie + ", login: " + login + ", licence: " + utilisateur.getLicence());
//Coel.LogVersFirebug("Taille réponse:" + reponse.size());
 
// Utilisateur connecté (non anonyme)
if (reponse.size() > 3) {
//Coel.LogVersFirebug("Utilisateur identifié, on charge plus de trucs !");
// Identifiant de l'utilisateur ou identifiant de session si non identifié
utilisateur.setId(((JSONString) reponse.get(1)).stringValue());
// Drapeau levé si l'utilisateur est déjà identifié
utilisateur.setIdentification(((JSONBoolean) reponse.get(2)).booleanValue());
// Plus de deux valeurs, l'utilisateur est identifié nous récupérons des données supplémentaires
if (reponse.size() > 3) {
// Nom complet de l'utilisateur
if (reponse.get(3).isString() != null) {
utilisateur.setNomComplet(((JSONString) reponse.get(3)).stringValue());
}
// Prénom de l'utilisateur
if (reponse.get(4).isString() != null) {
utilisateur.setPrenom(((JSONString) reponse.get(4)).stringValue());
}
// Nom de l'utilisateur
if (reponse.get(5).isString() != null) {
utilisateur.setNom(((JSONString) reponse.get(5)).stringValue());
}
// Paramètres
if (reponse.get(6).isString() != null) {
utilisateur.setParametre(((JSONString) reponse.get(6)).stringValue());
}
String idUtilisateur = ((JSONString) reponse.get(1)).stringValue();
//Coel.LogVersFirebug("ID utilisateur: " + idUtilisateur);
utilisateur.setId(idUtilisateur);
 
// Nom complet de l'utilisateur
if (reponse.get(3).isString() != null) {
String nomComplet = ((JSONString) reponse.get(3)).stringValue();
//Coel.LogVersFirebug("Nom complet: " + nomComplet);
utilisateur.setNomComplet(nomComplet);
}
vueARafraichir.rafraichir(utilisateur);
// Prénom de l'utilisateur
if (reponse.get(4).isString() != null) {
String prenom = ((JSONString) reponse.get(4)).stringValue();
utilisateur.setPrenom(prenom);
//Coel.LogVersFirebug("Prénom: " + prenom);
}
// Nom de l'utilisateur
if (reponse.get(5).isString() != null) {
String nom = ((JSONString) reponse.get(5)).stringValue();
utilisateur.setNom(nom);
//Coel.LogVersFirebug("Nom: " + nom);
}
// Paramètre => was ist das ?
if (reponse.get(6).isString() != null) {
String parametre = ((JSONString) reponse.get(6)).stringValue();
utilisateur.setParametre(parametre);
//Coel.LogVersFirebug("Paramètre: " + parametre);
}
}
 
//Coel.LogVersFirebug("Rafraîchissement vue");
vueARafraichir.rafraichir(utilisateur);
}
}
});
}
/*
* */
 
/**
* @TODO CHANGER ÇA !
*/
public void accepterLicence() {
String[] parametres = {utilisateur.getLogin(), utilisateur.getMotDePasse(), utilisateur.getId()};
/trunk/war/config/config.defaut.js
1,5 → 1,6
var configuration = {
serviceBaseUrl:"http://www.tela-botanica.org/eflore/coel/jrest/",
serviceAuthBaseUrl:"https://www.tela-botanica.org/service:annuaire:auth/",
bogueUrl:"http://www.tela-botanica.net/suivi/index.php?project=31",
commentaireUrl:"http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=AideCoelCommentaire",
celUrl:"http://www.tela-botanica.org/appli:cel",