public function authenticate($_login = null, $_password = null) { global $debug_test_mdp, $debug_test_mdp_file, $debug_login_nouveaux_comptes, $loguer_nouveau_login; global $mysqli; // Quelques petits tests de sécurité // Vérification de la liste noire des adresses IP if (isset($GLOBALS['liste_noire_ip']) && in_array($_SERVER['REMOTE_ADDR'], $GLOBALS['liste_noire_ip'])) { tentative_intrusion(1, "Tentative de connexion depuis une IP sur liste noire (login utilisé : ".$_login.")"); return "3"; die(); } if ($_login != null && mb_strtoupper($_login) != mb_strtoupper($this->login)) { //on a une connexion sous un nouveau login, on purge la session $this->reset("10"); } if($debug_test_mdp=="y") { $f_tmp=fopen($debug_test_mdp_file,"a+"); fwrite($f_tmp,strftime("%a %d/%m/%Y - %H%M%S").": \$_login=$_login et \$_password=$_password\n"); fclose($f_tmp); } elseif($debug_login_nouveaux_comptes=="y") { $loguer_nouveau_login="******"; if(preg_match("/[A-Za-z0-9_\.-]/", $_login)) { $sql="SELECT 1=1 FROM utilisateurs WHERE login='******' AND change_mdp='y';"; $resultat = mysqli_query($mysqli, $sql); $nb_lignes = $resultat->num_rows; $resultat->close(); if($nb_lignes>0) { $loguer_nouveau_login="******"; $f_tmp=fopen($debug_test_mdp_file,"a+"); fwrite($f_tmp,strftime("%a %d/%m/%Y - %H%M%S").": \$_login=$_login et \$_password=$_password : "******"y")&& ($_login!="")&& ($_password!="")&& (getSettingAOui('autoriser_sso_password_auth'))) { $auth_mode="gepi"; } switch ($auth_mode) { case "gepi": # Authentification locale sur la base de données Gepi $auth = $this->authenticate_gepi($_login,$_password); break; case "ldap": # Authentification sur un serveur LDAP $auth = $this->authenticate_ldap($_login,$_password); break; case "simpleSAML": $auth = $this->authenticate_simpleSAML(); break; case "sso": # Authentification gérée par un service de SSO # On n'a pas besoin du login ni du mot de passe switch ($this->auth_sso) { case "cas": $auth = $this->authenticate_cas(); break; case "lemon": $auth = $this->authenticate_lemon(); break; case "lcs": $auth = $this->authenticate_lcs(); break; } break; case false: # L'utilisateur n'existe pas dans la base de données ou bien # n'a pas été passé en paramètre. # On va donc tenter d'abord une authentification simpleSAML, puis LDAP, # puis une authentification SSO, à condition que celles-ci # soient bien sûr configurées. if ($this->auth_ldap && $_login != null && $_password != null) { $auth = $this->authenticate_ldap($_login,$_password); }if ($this->auth_simpleSAML) { $auth = $this->authenticate_simpleSAML(); } else if ($this->auth_sso && $_login == null) { // L'auth LDAP n'a pas marché, on essaie le SSO switch ($this->auth_sso) { case "cas": $auth = $this->authenticate_cas(); break; case "lemon": $auth = $this->authenticate_lemon(); break; case "lcs": $auth = $this->authenticate_lcs(); break; } } else { $auth = false; } break; default: # Si on arrive là, c'est qu'il y a un problème avec la définition # du mode d'authentification pour l'utilisateur en question. $auth = false; break; } // A partir d'ici soit on a un avis d'échec de l'authentification, soit // une session valide. if ($auth) { // L'authentification en elle-même est valide. // Dans le cas du multisite, il faut maintenant déterminer le RNE // de l'utilisateur avant d'aller plus loin, sauf s'il a déjà été passé // en paramètre. if (isset($GLOBALS['multisite']) && $GLOBALS['multisite'] == "y") { if (!isset($_GET['rne']) AND (!isset($_COOKIE["RNE"]) OR $_COOKIE["RNE"] == 'RNE')) { if (isset($GLOBALS['mode_choix_base']) && $GLOBALS['mode_choix_base'] == "url") { // dans ce cas, on se connecte à l'url $url_cas_sso donnée par le secure/connect.inc.php $t_rne = file_get_contents($GLOBALS[url_cas_sso] . '?login='******'&cle=' . $GLOBALS['cle_url_cas']); if ($t_rne != 'erreur') { $rep_rne = explode("|", $t_rne); $nbre_rne = count($rep_rne); if ($nbre_rne > 1) { header("Location: choix_rne.php?nbre=".$nbre_rne."&lesrne=".$t_rne); exit(); } else{ if ($this->current_auth_mode == "sso") { setcookie('RNE', $t_rne, null, '/'); header("Location: login_sso.php?rne=".$t_rne); exit(); } else { header("Location: login.php?rne=".$t_rne); exit(); } } } } elseif (LDAPServer::is_setup()) { // Le RNE n'a pas été transmis. Il faut le récupérer et recharger la page // pour obtenir la bonne base de données $ldap = new LDAPServer; $user = $ldap->get_user_profile($this->login); // On teste pour savoir si on a plusieurs RNE $test = count($user["rne"]); if ($test >= 1) { # On a au moins un RNE, on peut continuer if ($test > 1) { // On envoie l'utilisateur choisir lui même son RNE $rnes = NULL; for($a = 0 ; $a < $test ; $a++){ $rnes .= $user["rne"][$a].'|'; } header("Location: choix_rne.php?nbre=".$test."&lesrne=".$rnes); exit(); }else{ // Il n'y en a qu'un, on recharge ! if ($this->current_auth_mode == "sso") { setcookie('RNE', $user["rne"][0], null, '/'); header("Location: login_sso.php?rne=".$user["rne"][0]); exit(); } else { header("Location: login.php?rne=".$user["rne"][0]); exit(); } } } else { return "8"; exit(); } } else { return "8"; exit(); } } } // On va maintenant effectuer quelques tests pour vérifier // que le compte n'est pas bloqué. if ($this->account_is_locked()) { $this->reset(2); return "2"; exit(); } # On charge les données de l'utilisateur if (!$this->load_user_data()) { # Si on ne parvient pas à charger les données, c'est que # l'utilisateur n'est pas présent en base de données. # On essaie d'importer son profil depuis le LDAP. # Si on a activé la synchro Scribe, on utilise alors l'import spécifique if (getSettingValue("may_import_user_profile") == "yes" && getSettingValue("sso_scribe") == "yes") { $load = $this->import_user_profile_from_scribe(); # Sinon, on utilise l'import classique, très basique. } elseif (getSettingValue("may_import_user_profile")) { $load = $this->import_user_profile(); } if (!$load) { return "6"; exit(); } else { # Si l'import a réussi, on tente à nouveau de charger # les données de l'utilisateur. $this->load_user_data(); } } # On vérifie que l'utilisateur est bien actif if ($this->etat != "actif") { $this->reset(2); return "4"; exit(); } # On vérifie que les connexions sont bien activées. $disable_login = getSettingValue("disable_login"); if ($this->statut != "administrateur" && ($disable_login == "yes" || $disable_login == "soft")) { $this->reset(2); return "7"; exit(); } # On teste la cohérence de mode de connexion // 20140301 if((!isset($auth_sso_secours))|| ($auth_sso_secours!="y")|| (!getSettingAOui('autoriser_sso_password_auth'))) { $auth_mode = self::user_auth_mode($this->login); if ($this->current_auth_mode != 'simpleSAML' && $auth_mode != $this->current_auth_mode) { $this->reset(2); return "5"; exit; } } # Si on est en mode CAS, on met à jour à la volée les attributs de # l'utilisateur (le cas échéant) if ($this->auth_sso == 'cas') { $this->update_user_with_cas_attributes(); } # Tout est bon. On valide définitivement la session. $sql_start = mysqli_query($mysqli, "SELECT now();"); $row = $sql_start->fetch_row(); $this->start = $row[0]; $sql_start->close(); $_SESSION['start'] = $this->start; $this->insert_log(); # On supprime l'historique des logs conformément à la durée définie. $sql_del = "delete from log where START < now() - interval " . getSettingValue("duree_conservation_logs") . " day and END < now()"; $resultat = mysqli_query($mysqli, $sql_del); # On envoie un mail, si l'option a été activée mail_connexion(); return "1"; exit(); } else { // L'authentification a échoué. // On nettoie la session. $this->reset(2); // On enregistre l'échec. // En cas d'échec répété, on renvoie un code d'erreur de // verrouillage de compte, pour brouiller les pistes en cas // d'attaque brute-force sur les logins. if ($this->record_failed_login($_login)) { return "2"; exit(); } // On retourne le code d'erreur générique return "9"; } }
function authenticate($_login = null, $_password = null) { // Quelques petits tests de sécurité // Vérification de la liste noire des adresses IP if (isset($GLOBALS['liste_noire_ip']) && in_array($_SERVER['REMOTE_ADDR'], $GLOBALS['liste_noire_ip'])) { tentative_intrusion(1, "Tentative de connexion depuis une IP sur liste noire (login utilisé : ".$_login.")"); return "3"; die(); } // On initialise la session de l'utilisateur. // On commence par extraire le mode d'authentification défini // pour l'utilisateur. Si l'utilisateur n'existe pas, on essaiera // l'authentification LDAP et le SSO quand même. $auth_mode = Session::user_auth_mode($_login); switch ($auth_mode) { case "gepi": # Authentification locale sur la base de données Gepi $auth = $this->authenticate_gepi($_login,$_password); break; case "ldap": # Authentification sur un serveur LDAP $auth = $this->authenticate_ldap($_login,$_password); break; case "sso": # Authentification gérée par un service de SSO # On n'a pas besoin du login ni du mot de passe switch ($this->auth_sso) { case "cas": $auth = $this->authenticate_cas(); break; case "lemon": $auth = $this->authenticate_lemon(); break; case "lcs": $auth = $this->authenticate_lcs(); break; } break; case false: # L'utilisateur n'existe pas dans la base de données ou bien # n'a pas été passé en paramètre. # On va donc tenter d'abord une authentification LDAP, # puis une authentification SSO, à condition que celles-ci # soient bien sûr configurées. if ($this->auth_ldap && $_login != null && $_password != null) { $auth = $this->authenticate_ldap($_login,$_password); } else if ($this->auth_sso && $_login == null) { // L'auth LDAP n'a pas marché, on essaie le SSO switch ($this->auth_sso) { case "cas": $auth = $this->authenticate_cas(); break; case "lemon": $auth = $this->authenticate_lemon(); break; case "lcs": $auth = $this->authenticate_lcs(); break; } } else { $auth = false; } break; default: # Si on arrive là, c'est qu'il y a un problème avec la définition # du mode d'authentification pour l'utilisateur en question. $auth = false; break; } // A partir d'ici soit on a un avis d'échec de l'authentification, soit // une session valide. if ($auth) { // L'authentification en elle-même est valide. // Dans le cas du multisite, il faut maintenant déterminer le RNE // de l'utilisateur avant d'aller plus loin, sauf s'il a déjà été passé // en paramètre. if (isset($GLOBALS['multisite']) && $GLOBALS['multisite'] == "y") { if (!isset($_GET['rne']) AND !isset($_COOKIE["RNE"])) { if (LDAPServer::is_setup()) { // Le RNE n'a pas été transmis. Il faut le récupérer et recharger la page // pour obtenir la bonne base de données $ldap = new LDAPServer; $user = $ldap->get_user_profile($this->login); // On teste pour savoir si on a plusieurs RNE $test = count($user["rne"]); if ($test >= 1) { # On a au moins un RNE, on peut continuer if ($test > 1) { // On envoie l'utilisateur choisir lui même son RNE $rnes = NULL; for($a = 0 ; $a < $test ; $a++){ $rnes .= $user["rne"][$a].'|'; } header("Location: choix_rne.php?nbre=".$test."&lesrne=".$rnes); }else{ // Il n'y en a qu'un, on recharge ! if ($this->current_auth_mode == "sso") { header("Location: login_sso.php?rne=".$user["rne"]); exit(); } else { header("Location: login.php?rne=".$user["rne"]); exit(); } } } else { return "8"; exit(); } } else { return "8"; exit(); } } } // On va maintenant effectuer quelques tests pour vérifier // que le compte n'est pas bloqué. if ($this->account_is_locked()) { $this->reset(2); return "2"; exit(); } # On charge les données de l'utilisateur if (!$this->load_user_data()) { # Si on ne parvient pas à charger les données, c'est que # l'utilisateur n'est pas présent en base de données. # On essaie d'importer son profil depuis le LDAP. if (getSettingValue("may_import_user_profile") == "yes") { if (!$this->import_user_profile()) { return "6"; exit(); } else { # Si l'import a réussi, on tente à nouveau de charger # les données de l'utilisateur. $this->load_user_data(); } } } # On vérifie que l'utilisateur est bien actif if ($this->etat != "actif") { $this->reset(2); return "4"; exit(); } # On vérifie que les connexions sont bien activées. $disable_login = getSettingValue("disable_login"); if ($this->statut != "administrateur" && ($disable_login == "yes" || $disable_login == "soft")) { $this->reset(2); return "7"; exit(); } # On teste la cohérence de mode de connexion $auth_mode = Session::user_auth_mode($this->login); if ($auth_mode != $this->current_auth_mode) { $this->reset(2); return "5"; exit; } # Tout est bon. On valide définitivement la session. $this->start = mysql_result(mysql_query("SELECT now();"),0); $_SESSION['start'] = $this->start; $this->insert_log(); # On supprime l'historique des logs conformément à la durée définie. sql_query("delete from log where START < now() - interval " . getSettingValue("duree_conservation_logs") . " day and END < now()"); # On envoie un mail, si l'option a été activée mail_connexion(); return "1"; exit(); } else { // L'authentification a échoué. // On nettoie la session. $this->reset(2); // On enregistre l'échec. // En cas d'échec répété, on renvoie un code d'erreur de // verrouillage de compte, pour brouiller les pistes en cas // d'attaque brute-force sur les logins. if ($this->record_failed_login($_login)) { return "2"; exit(); } // On retourne le code d'erreur générique return "9"; } }