diff --git a/VERSIONS_WIP/passhash b/VERSIONS_WIP/passhash new file mode 100644 index 0000000000000000000000000000000000000000..6832bc78e94a99b1f46ade03ecbbd999a11a2f06 --- /dev/null +++ b/VERSIONS_WIP/passhash @@ -0,0 +1 @@ + - Administration : hashage des mots de passe administrateurs \ No newline at end of file diff --git a/application/modules/admin/controllers/IndexController.php b/application/modules/admin/controllers/IndexController.php index 016d6dca266f9f144642eff5f107f0d683a594c6..a40df7c01d396605b42a52979c0bfac47d83dbe4 100644 --- a/application/modules/admin/controllers/IndexController.php +++ b/application/modules/admin/controllers/IndexController.php @@ -161,23 +161,35 @@ class Admin_IndexController extends ZendAfi_Controller_Action { public function becomeAction() { - if(!Class_Users::getIdentity()->isSuperAdmin()) { + if (!Class_Users::getIdentity()->isSuperAdmin()) { $this->_helper->notify($this->_('Vous n\'avez pas les droits suffisants pour utiliser cette fonctionnalité.')); return $this->_redirectToIndex(); } - if(!$user = Class_Users::find($this->_getParam('id', null))) { + if (!$user = Class_Users::find($this->_getParam('id', null))) { $this->_helper->notify($this->_('Utilisateur invalide')); return $this->_redirectToIndex(); } - if(!ZendAfi_Auth::getInstance()->authenticateLoginPassword($user->getLogin(), $user->getPassword())) { + if ($user->isAbonne()) + return $this->_becomePatron($user); + + ZendAfi_Auth::getInstance()->logUser($user); + $this->_helper->notify($this->_('Vous êtes maintenant connecté avec l\'utilisateur "%s"', + $user->getNomComplet())); + $this->_redirectToIndex(); + } + + + protected function _becomePatron($user) { + if (!ZendAfi_Auth::getInstance()->authenticateLoginPassword($user->getLogin(), $user->getPassword())) { $this->_helper->notify($this->_('Nom d\'utilisateur ou mot de passe invalide')); return $this->_redirectToIndex(); } $this->_helper->notify($this->_('Vous êtes maintenant connecté avec l\'utilisateur "%s"', $user->getNomComplet())); - $this->_redirectToIndex(); + + return $this->_redirectToIndex(); } } \ No newline at end of file diff --git a/application/modules/opac/controllers/AuthController.php b/application/modules/opac/controllers/AuthController.php index b3a171a11f486d4b119605eff23bde8932dd5a2f..62cdd9891fdcaf108fd5c15badffcb12cbe6264b 100644 --- a/application/modules/opac/controllers/AuthController.php +++ b/application/modules/opac/controllers/AuthController.php @@ -20,6 +20,10 @@ */ class AuthController extends ZendAfi_Controller_Action { + const + LOST_PASS_NOLOGIN = 1, + LOST_PASS_NOUSER = 2, + LOST_PASS_NOMAIL = 4; public function init() { $this->view->locale = Zend_Registry::get('locale'); @@ -54,12 +58,13 @@ class AuthController extends ZendAfi_Controller_Action { public function getErrorMessages($error_code) { - $messages= [1 => $this->_('Veuillez saisir votre identifiant.'), - 2 => $this->_('Identifiant inconnu.'), - 4 => $this->_("Votre mail n'est pas renseigné dans votre compte lecteur. Merci de vous adresser à la bibliothèque pour récupérer votre mot de passe ou bien le remplacer par un nouveau.")]; - if (isset($messages[$error_code])) - return $messages[$error_code]; - return ''; + $messages = [static::LOST_PASS_NOLOGIN => $this->_('Veuillez saisir votre identifiant.'), + static::LOST_PASS_NOUSER => $this->_('Identifiant inconnu.'), + static::LOST_PASS_NOMAIL => $this->_("Votre mail n'est pas renseigné dans votre compte lecteur. Merci de vous adresser à la bibliothèque pour récupérer votre mot de passe ou bien le remplacer par un nouveau.")]; + + return isset($messages[$error_code]) + ? $messages[$error_code] + : ''; } @@ -84,13 +89,13 @@ class AuthController extends ZendAfi_Controller_Action { $password = $f->filter($this->_request->getPost('password')); if (empty($username)) - return $this->view->_('Entrez votre identifiant S.V.P.'); + return $this->_('Entrez votre identifiant S.V.P.'); if (empty($password)) - return $this->view->_('Entrez votre mot de passe S.V.P.'); + return $this->_('Entrez votre mot de passe S.V.P.'); if (!ZendAfi_Auth::getInstance()->authenticateLoginPassword($username, $password)) - return $this->view->_('Identifiant ou mot de passe incorrect.'); + return $this->_('Identifiant ou mot de passe incorrect.'); $user = Class_Users::getIdentity(); $this->_helper->trackEvent('authentification', 'connexion', 'utilisateur', $user->getId()); @@ -296,25 +301,54 @@ class AuthController extends ZendAfi_Controller_Action { public function lostpassAction() { $preferences = $this->_loginPrefFromWidgetOrModule(); + $options = ['username_label' => $preferences["identifiant"], + 'username_placeholder' => $preferences["identifiant_exemple"]]; - $this->view->form = ZendAfi_Form_LostPassword::newWithOptions(['username_label' => $preferences["identifiant"], - 'username_placeholder' => $preferences["identifiant_exemple"]]) + $form = ZendAfi_Form_LostPassword::newWithOptions($options) ->setAction($this->view->url(['module' => 'opac', 'controller' => 'auth', 'action' => 'lostpass'], null , true)); + $this->view->form = $form; - if(!$this->_request->isPost()) + if(!$this->_request->isPost() + || !$form->isValid($this->_request->getPost())) return; - $user = ZendAfi_Filters_Post::filterStatic($this->_request->getPost('lost_username')); - $classe_user = new Class_Users(); - $ret = $classe_user->lostpass($user); + $login = ZendAfi_Filters_Post::filterStatic($this->_request->getPost('lost_username')); + $this->view->username = $login; - $this->view->message = $this->getErrorMessages($ret["error"]); - $this->view->message_mail = isset($ret["message_mail"]) - ? $ret["message_mail"] - : ''; - $this->view->username=$user; + $user = Class_Users::findFirstValidOrNotBy(['login' => $login]); + $this->view->message_mail = (new Class_User_LostPass($user))->send(); + } + + + public function resetPasswordAction() { + $this->view->title = $this->_('Réinitialisation du mot de passe'); + + if (!$user = Class_Users::find((int)$this->_getParam('id'))) + return $this->view->message = $this->_('Utilisateur inconnu'); + + $lostpass = new Class_User_LostPass($user); + $created = $this->_getParam('created'); + if ($this->_getParam('token', '') != $lostpass->tokenAt($created)) + return $this->view->message = $this->_('Jeton de réinitialisation invalide'); + + if ($lostpass->tokenHasExpiredFrom($created)) + return $this->view->message = $this->_('Jeton de réinitialisation expiré'); + + $this->view->form = $form = new ZendAfi_Form_ResetPassword(); + $form->setAction($this->view->url()); + + if (!$this->_request->isPost() + || !$form->isValid($this->_request->getPost())) + return; + + $user->setPassword($form->getValue('new_pass')) + ->save(); + + $this->_helper->notify($this->_('Votre mot de passe a été réinitialisé, vous pouvez vous connecter.')); + + $this->_redirect('/auth/login'); } diff --git a/application/modules/opac/views/scripts/auth/reset-password.phtml b/application/modules/opac/views/scripts/auth/reset-password.phtml new file mode 100644 index 0000000000000000000000000000000000000000..e41e768a2d04b4662d7c8e33e3d76a67aaeeaff8 --- /dev/null +++ b/application/modules/opac/views/scripts/auth/reset-password.phtml @@ -0,0 +1,10 @@ +<?php +$this->openBoite($this->title); + +if ($this->message) + echo $this->tag('div', $this->message); + +if ($this->form) + echo $this->renderForm($this->form); + +$this->closeBoite(); diff --git a/cosmogramme/php/_identification.php b/cosmogramme/php/_identification.php index 310d0dcb0e06200e4f77c18362e70afb462c81f6..a02e72b04d4b41e28f3a87cd31cc891161825437 100644 --- a/cosmogramme/php/_identification.php +++ b/cosmogramme/php/_identification.php @@ -37,7 +37,8 @@ function cosmo_auth($user, $passe, $cfg) { if ($user == getVariable('catalog_login') && $passe == getVariable('catalog_pwd')) return 'catalogueur'; - if (($bokeh_user = Class_Users::findFirstBy(['login' => $user, 'password' => $passe])) + if (($bokeh_user = Class_Users::findFirstBy(['login' => $user])) + && $bokeh_user->verifyPassword($passe) && $bokeh_user->isSuperAdmin()) return 'admin_systeme'; } diff --git a/cosmogramme/sql/patch/patch_338.php b/cosmogramme/sql/patch/patch_338.php new file mode 100644 index 0000000000000000000000000000000000000000..aaa9e0fe7fe61eaea145698130cc95c15ff2fb96 --- /dev/null +++ b/cosmogramme/sql/patch/patch_338.php @@ -0,0 +1,2 @@ +<?php +(new Class_Migration_HashAdminPasswords)->run(); \ No newline at end of file diff --git a/library/Class/Crypt.php b/library/Class/Crypt.php new file mode 100644 index 0000000000000000000000000000000000000000..37684aa60f4160946c50eb0f7630a801c77a0559 --- /dev/null +++ b/library/Class/Crypt.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_Crypt { + /** @see http://php.net/manual/en/function.crypt.php CRYPT_BLOWFISH section */ + const BLOWFISH_PATTERN = '/^\$2[axy]\$[0-9]{2}\$/'; + + public function isBlowFish($value) { + return 1 === preg_match(static::BLOWFISH_PATTERN, $value); + } + + + public function blowFishHashOf($value) { + return password_hash($value, PASSWORD_BCRYPT); + } +} diff --git a/library/Class/Mail.php b/library/Class/Mail.php index 35f72b7f376c3ee9e10017024ac8691de864b1d1..c8a262bed768d5ad150403727062a289519561a2 100644 --- a/library/Class/Mail.php +++ b/library/Class/Mail.php @@ -16,29 +16,22 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -//////////////////////////////////////////////////////////////////////////////////////// -// OPAC3 : ENVOI DE MAILS -/////////////////////////////////////////////////////////////////////////////////////// -class Class_Mail -{ +class Class_Mail { + use Trait_Translator; + private $params_ok=false; // Flag de controle si un mail peut etre envoyé private $mail_from; // Header from - private $_translate; - -//--------------------------------------------------------------------------------- -// constructeur : init des parametres -//--------------------------------------------------------------------------------- + public function __construct() { - $this->_translate = Zend_Registry::get('translate'); $this->params_ok = false; $this->mail_from = Class_Profil::getCurrentProfil()->getMailSiteOrPortail(); if (!$this->mail_from) $this->mail_from = Class_CosmoVar::get('mail_admin'); - + if ($this->isMailValid($this->mail_from)) { ini_set('sendmail_from', $this->mail_from); $this->params_ok=true; @@ -46,12 +39,7 @@ class Class_Mail } - public function _translate($message) { - return $this->_translate->_($message); - } - - - public function mail($destinataire, $sujet, $body, $headers) { + public function mail($destinataire, $sujet, $body) { $mail = new ZendAfi_Mail('utf8'); $mail ->setSubject($sujet) @@ -67,21 +55,21 @@ class Class_Mail } } -//--------------------------------------------------------------------------------- -// Envoi de mail -//--------------------------------------------------------------------------------- - public function sendMail($sujet,$body,$destinataire,$data=false) - { + + public function sendMail($sujet, $body, $destinataire, $data=false) { $error_message = sprintf('%s <br/> %s', - $this->_translate("Les paramètres d'envoi de mails du portail sont incomplets."), - $this->_translate("Merci de le signaler aux responsables de la bibliothèque.")); + $this->_("Les paramètres d'envoi de mails du portail sont incomplets."), + $this->_("Merci de le signaler aux responsables de la bibliothèque.")); + + if(!$this->params_ok or !trim($body)) + return $error_message; - // Controle des parametres if(!trim($destinataire)) - return $this->_translate->_("Adresse du destinataire absente."); + return $this->_("L'Adresse du destinataire est absente."); + + if (!$this->isMailValid($destinataire)) + return $this->_("L'adresse e-mail du destinataire est incorrecte."); - if($this->params_ok==false or !trim($body)) - return $error_message; // Fusion if($data) @@ -93,20 +81,12 @@ class Class_Mail } } $body = wordwrap($body, 60); - - // Envoi du mail - $ret=$this->getHeaders($destinataire); - if (array_isset("erreur", $ret)) - return $ret["erreur"]; - else - $headers=$ret["headers"]; - - $statut = $this->mail($destinataire, $sujet, $body, $headers); - if($statut == false) - return $error_message; + $statut = $this->mail($destinataire, $sujet, $body); - return ""; + return (true === $statut) + ? '' + : $error_message; } @@ -114,27 +94,4 @@ class Class_Mail $validator = new Zend_Validate_EmailAddress(); return $validator->isValid($mail); } - - -//--------------------------------------------------------------------------------- -// Constitution des headers -//--------------------------------------------------------------------------------- - protected function getHeaders($destinataire) - { - $ret = array('headers' => ''); - if (!$this->isMailValid($destinataire)) { - $ret["erreur"]= "L'adresse e-mail du destinataire est incorrecte."; - return $ret; - } - - // Headers - $headers = 'MIME-Version: 1.0' . "\r\n"; - $headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n"; - $headers .= 'To: '.$destinataire. "\r\n"; - $headers .= 'From: '.$this->mail_from . "\r\n"; - $ret["headers"]=$headers; - return $ret; - } -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/library/Class/Migration/HashAdminPasswords.php b/library/Class/Migration/HashAdminPasswords.php new file mode 100644 index 0000000000000000000000000000000000000000..600968002b8c79a390835b25e8f0436701eaccbc --- /dev/null +++ b/library/Class/Migration/HashAdminPasswords.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_Migration_HashAdminPasswords { + public function run() { + foreach(Class_Users::findAllBy(['where' => 'role_level > 2']) as $user) + $user->save(); + } +} diff --git a/library/Class/User/LostPass.php b/library/Class/User/LostPass.php new file mode 100644 index 0000000000000000000000000000000000000000..eb3b83dde9199302efd94c82815483aece3736d7 --- /dev/null +++ b/library/Class/User/LostPass.php @@ -0,0 +1,144 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_User_LostPass { + use Trait_TimeSource; + + const MAX_MINUTES = 30; + const TOKEN_SEPARATOR = '@'; + const TOKEN_DATE_FORMAT = 'YmdHis'; + + protected $_user; + + public function __construct($user) { + $this->_user = $user; + } + + + public function send() { + $strategy = $this->_user->isAbonne() + ? new Class_User_LostPassPatron($this) + : new Class_User_LostPassLocal($this); + + return $strategy->sendTo($this->_user); + } + + + public function tokenAt($date) { + $parts = [$this->_user->getId(), $this->_user->getLogin(), $date]; + return sha1(implode(static::TOKEN_SEPARATOR, $parts)); + } + + + public function tokenHasExpiredFrom($date) { + $from = DateTime::createFromFormat(static::TOKEN_DATE_FORMAT, $date); + $now = new DateTime($this->getCurrentDateTime()); + $from->add(new DateInterval('PT' . static::MAX_MINUTES . 'M')); + + return $from < $now; + } +} + + + +abstract class Class_User_LostPassSender { + use Trait_Translator; + + protected $_lostpass; + + public function __construct($lostpass) { + $this->_lostpass = $lostpass; + } + + + public function sendTo($user) { + $error = (new Class_Mail()) + ->sendMail(Class_Profil::getCurrentProfil()->getTitreSite(), + $this->_contentFor($user), + $user->getMail()); + + return $error + ? '<p class="error">' . $error . '</p>' + : $this->_successMessage(); + } + + + protected function _contentFor($user) { + return ''; + } + + + protected function _successMessage() { + return ''; + } +} + + + +class Class_User_LostPassPatron extends Class_User_LostPassSender { + protected function _contentFor($user) { + return + sprintf("%s\n\n", + $this->_('Vous avez fait une demande de mot de passe sur le portail.')) + . $this->_("Votre identifiant : %s\n", $user->getLogin()) + . $this->_("Votre mot de passe : %s\n", $user->getPassword()) + . sprintf("%s\n\n", $this->_('Bonne navigation sur le portail')) + ; + } + + + protected function _successMessage() { + return $this->_('Un mail vient de vous être envoyé avec vos paramètres de connexion.'); + } +} + + + +class Class_User_LostPassLocal extends Class_User_LostPassSender{ + use Trait_TimeSource; + + protected function _contentFor($user) { + $created_at = $this->getCurrentTime(); + $created_at_part = date(Class_User_LostPass::TOKEN_DATE_FORMAT, $created_at); + $token = $this->_lostpass->tokenAt($created_at_part); + + return + sprintf("%s\n\n", + $this->_('Vous avez fait une demande de réinitialisation de votre mot de passe sur le portail.')) + . $this->_("Votre lien de réinitialisation : %s\n", + Class_Url::absolute(['module' => 'opac', + 'controller' => 'auth', + 'action' => 'reset-password', + 'id' => $user->getId(), + 'token' => $token, + 'created' => $created_at_part], null, true)) + . $this->_("ATTENTION : ce lien créé à %s est valide pendant %s minutes\n", + date('H:i', $created_at), + Class_User_LostPass::MAX_MINUTES) + . sprintf("%s\n\n", $this->_('Bonne navigation sur le portail')); + } + + + protected function _successMessage() { + return $this->_('Un mail vient de vous être envoyé contenant un lien de réinitialisation du mot de passe.'); + } +} \ No newline at end of file diff --git a/library/Class/User/Password.php b/library/Class/User/Password.php new file mode 100644 index 0000000000000000000000000000000000000000..eedb739ae717c6042cf7f7316edf0afc442ad26d --- /dev/null +++ b/library/Class/User/Password.php @@ -0,0 +1,83 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Class_User_Password { + protected $_user; + + public function __construct($user) { + $this->_user = $user; + } + + + public function format() { + return $this->shouldHash() + ? $this->asBlowFish() + : $this->password(); + } + + + public function verify($value) { + if (!$value) + return false; + + $value = strtolower($value); + + return $this->isBlowFish() + ? password_verify(strtolower($value), $this->password()) + : $value == strtolower($this->password()); + } + + + public function shouldHash() { + return $this->hasRoleLevel() && !$this->isPatron() && !$this->isBlowFish(); + } + + + public function password() { + return $this->_user->getPassword(); + } + + + public function isPatron() { + return $this->_user->isAbonne(); + } + + + public function hasRoleLevel() { + return $this->_user->hasRoleLevel(); + } + + + public function isBlowFish() { + return $this->crypt()->isBlowFish($this->password()); + } + + + public function asBlowFish() { + return $this->crypt()->blowFishHashOf(strtolower($this->password())); + } + + + public function crypt() { + return new Class_Crypt(); + } +} diff --git a/library/Class/Users.php b/library/Class/Users.php index c5c17052a5216d40e2db294fbf960da88f0108cd..9dc2857b98ee7c4c3a996571e88e146516cd3c1f 100644 --- a/library/Class/Users.php +++ b/library/Class/Users.php @@ -241,10 +241,11 @@ class UsersLoader extends Storm_Model_Loader { public function findBlowfish($login) { + $crypt = new Class_Crypt(); return array_filter( Class_Users::findAllBy(['login' => $login]), - function($user) { - return substr($user->getPassword(), 0, 4) === '$2a$'; + function($user) use($crypt) { + return $crypt->isBlowFish($user->getPassword()); }); } @@ -320,6 +321,14 @@ class UsersLoader extends Storm_Model_Loader { $count_params = $this->_buildSearchParams($defaults, $where, $valide_subscription); return Class_Users::countBy($count_params); } + + + public function findFirstValidOrNotBy($params) { + if (!$user = Class_Users::findFirstBy($params)) + $user = Class_UsersNonValid::findFirstBy($params); + + return $user; + } } @@ -1114,7 +1123,7 @@ class Class_Users extends Storm_Model_Abstract { } - function lostpass($login) { + public function lostpass($login) { if(!trim($login)) return ['error' => 1]; @@ -1378,6 +1387,8 @@ class Class_Users extends Storm_Model_Abstract { public function beforeSave() { $this->setDateMaj(Class_Multimedia_Utils_DateTimeFormat::getInstance() ->getCurrentDateFormatInYmdHMS()); + + $this->setPassword((new Class_User_Password($this))->format()); } @@ -1859,4 +1870,9 @@ class Class_Users extends Storm_Model_Abstract { public function hasPaniers() { return (0 < $this->numberOfPaniers()); } + + + public function verifyPassword($value) { + return (new Class_User_Password($this))->verify($value); + } } diff --git a/library/ZendAfi/Auth/Adapter/Success.php b/library/ZendAfi/Auth/Adapter/Success.php new file mode 100644 index 0000000000000000000000000000000000000000..c7d2b58b76a356a434591aebbf72d98e58ec1a36 --- /dev/null +++ b/library/ZendAfi/Auth/Adapter/Success.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_Auth_Adapter_Success implements Zend_Auth_Adapter_Interface { + protected $_user; + + /** + * Performs an authentication attempt + * + * @throws Zend_Auth_Adapter_Exception If authentication cannot be performed + * @return Zend_Auth_Result + */ + public function authenticate() { + return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->_user->getId()); + } + + + public function __construct($user) { + $this->_user = $user; + } + + + public function getResultObject() { + return $this->_user->toStdClass(); + } +} diff --git a/library/ZendAfi/Auth/TryHarder.php b/library/ZendAfi/Auth/TryHarder.php index 6e54e799149bb8eab0fc8e162d767659f23a8e7a..aae00cb897cd5867637bb6e5970f1a52628418b8 100644 --- a/library/ZendAfi/Auth/TryHarder.php +++ b/library/ZendAfi/Auth/TryHarder.php @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -31,14 +31,18 @@ class ZendAfi_Auth_TryHarder { public function tryHarder($login, $password) { $this->_adapter->setIdentity($login); - return - $this->trySimpleFormats($login, $password) or $this->tryBlowfish($login, $password); + + return $this->trySimpleFormats($login, $password) + or $this->tryBlowfish($login, $password); } protected function trySimpleFormats($login, $password) { - $formats = [function ($password) {return $password;}, - function ($password) {return $this->md5_base64($password);}]; + if ((new Class_Crypt)->isBlowFish($password)) + return false; + + $formats = [function ($password) { return $password; }, + function ($password) { return $this->md5_base64($password); }]; foreach($formats as $format) { $this->_adapter->setCredential($format($password)); @@ -55,10 +59,10 @@ class ZendAfi_Auth_TryHarder { return false; foreach(Class_Users::findBlowfish($login) as $user) { - $salt = substr($user->getPassword(), 0, 29); - $this->_adapter->setCredential(crypt($password, $salt)); - if ($this->authenticate()) - return true; + if ($user->verifyPassword($password)) { + $this->_adapter = new ZendAfi_Auth_Adapter_Success($user); + return $this->authenticate(); + } } return false; diff --git a/library/ZendAfi/Form/LostPassword.php b/library/ZendAfi/Form/LostPassword.php index 3bebbbde9382b786558ee47b73704c93b92e13b7..e51c8b1d79c86a8a8965a70cf6d08815cc262763 100644 --- a/library/ZendAfi/Form/LostPassword.php +++ b/library/ZendAfi/Form/LostPassword.php @@ -29,11 +29,12 @@ class ZendAfi_Form_LostPassword extends ZendAfi_Form { ['label' => $this->getAttrib('username_label'), 'placeholder' => $this->getAttrib('username_placeholder'), 'required' => true, - 'allowEmpty' => false]) + 'allowEmpty' => false, + 'validators' => ['LostUsername']]) ->addDisplayGroup(['lost_username'], 'lostpass_display_group', - ['legend' => $this->_('Récupération du mot de passe')]) + ['legend' => '']) ->setAttribs([]) ->setName('form_lostpass'); } diff --git a/library/ZendAfi/Form/ResetPassword.php b/library/ZendAfi/Form/ResetPassword.php new file mode 100644 index 0000000000000000000000000000000000000000..062a853a71ea26d161e694c547d53c03c42c28d1 --- /dev/null +++ b/library/ZendAfi/Form/ResetPassword.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_Form_ResetPassword extends ZendAfi_Form { + public function init() { + parent::init(); + + $this + ->addElement('password', 'new_pass', + ['label' => $this->_('Nouveau mot de passe'), + 'required' => true, + 'allowEmpty' => false]) + + ->addElement('password', 'confirm_pass', + ['label' => $this->_('Confirmez le nouveau mot de passe'), + 'required' => true, + 'allowEmpty' => false, + 'validators' => [new ZendAfi_Validate_PasswordEquals('new_pass')]]) + + ->addUniqDisplayGroup('reset-password') + ; + } +} diff --git a/library/ZendAfi/Validate/LostUsername.php b/library/ZendAfi/Validate/LostUsername.php new file mode 100644 index 0000000000000000000000000000000000000000..eead94453952c1080477cccb6a55b4ddceb2fe0d --- /dev/null +++ b/library/ZendAfi/Validate/LostUsername.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_Validate_LostUsername extends Zend_Validate_Abstract { + use Trait_Translator; + + const + NO_USER = 'no_user', + NO_MAIL = 'no_mail'; + + + public function __construct() { + $this->_messageTemplates = + [static::NO_USER => $this->_('Identifiant inconnu.'), + static::NO_MAIL => $this->_("Votre mail n'est pas renseigné dans votre compte lecteur. Merci de vous adresser à la bibliothèque pour récupérer votre mot de passe ou bien le remplacer par un nouveau.")]; + } + + + /** + * @param $value mixed + * @param $fields array + * @return boolean + */ + public function isValid($value, array $fields_values = array()) { + $value = ZendAfi_Filters_Post::filterStatic($value); + if (!$user = Class_Users::findFirstValidOrNotBy(['login' => $value])) { + $this->_error(static::NO_USER); + return false; + } + + if (!$user->hasMail()) { + $this->_error(static::NO_MAIL); + return false; + } + + return true; + } +} diff --git a/tests/application/modules/admin/controllers/UsersControllerTest.php b/tests/application/modules/admin/controllers/UsersControllerTest.php index 474f9204ce05210dce0e546d91d9ef2105dd3d95..a755d6c67afe88b56a26e071ebfec56130ec67c9 100644 --- a/tests/application/modules/admin/controllers/UsersControllerTest.php +++ b/tests/application/modules/admin/controllers/UsersControllerTest.php @@ -456,7 +456,7 @@ class UsersControllerPostMarcusDataTest extends UsersControllerWithMarcusTestCas /** @test */ - function marcusShouldHaveBeenSaved() { + public function marcusShouldHaveBeenSaved() { $this->assertEquals($this->marcus, Class_Users::find(10)); } @@ -966,7 +966,6 @@ class Admin_UsersControllerFormEditAdminTest extends Admin_UsersControllerEditAd class UsersControllerPostEditAdminTest extends Admin_UsersControllerEditAdminTestCase { - public function setUp() { parent::setUp(); $this->postDispatch('/admin/users/edit/id/10', ['login' => 'Tom', @@ -998,10 +997,58 @@ class UsersControllerPostEditAdminTest extends Admin_UsersControllerEditAdminTes $this->assertEquals($this->_admin->getRedmineLibrary()->getLibelle(), $this->_lib_po->getLibelle()); } + + + /** @test */ + public function passwordShouldBeHashed() { + $this->assertTrue((new Class_Crypt())->isBlowFish($this->_admin->getPassword())); + } + + + /** @test */ + public function hashShouldNotBeCaseSensitive() { + $this->assertTrue($this->_admin->verifyPassword('TuTu')); + } } +class UsersControllerPostEditWithHashedPasswordAdminTest extends Admin_UsersControllerEditAdminTestCase { + public function setUp() { + parent::setUp(); + $this->postDispatch('/admin/users/edit/id/10', + ['login' => 'Tom', + 'password' => '$2y$10$VDozEsvlDhp80/qz9qqOqOwq0uV/jxV2ayONdeacSY.fGipYMjvSe', + 'nom' => 'Davis', + 'prenom' => 'Miles', + 'pseudo' => 'Dave', + 'mail' => 'mdavis@free.fr', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL, + 'id_site' => '7', + 'idabon' => '2341', + 'ordreabon' => '2', + 'telephone' => '', + 'adresse' => '12 rue miles', + 'code_postal' => '75000', + 'ville' => 'Paris', + 'civilite' => 1, + 'mobile' => '', + 'naissance' => '1976-02-17', + 'date_debut' => '', + 'date_fin' => '', + 'user_group_ids' => '', + 'redmine_library' => '15']); + } + + + /** @test */ + public function passwordShouldStayTheSame() { + $this->assertEquals('$2y$10$VDozEsvlDhp80/qz9qqOqOwq0uV/jxV2ayONdeacSY.fGipYMjvSe', + $this->_admin->getPassword()); + } +} + + class UsersControllerEditSuperAdminTest extends Admin_AbstractControllerTestCase { protected $_storm_default_to_volatile = true; diff --git a/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php b/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php index b83784d68c7cba02c5f844cb6799f28e84c3df8a..06789ff79f94f373aaae47073b3f47d96bdbda5e 100644 --- a/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php +++ b/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php @@ -41,7 +41,7 @@ abstract class AbstractAbonneControllerNewslettersTestCase extends AbstractContr 'password' => 'mysecret', 'date_debut' => null, 'role' => 'abonne_sigb', - 'role_level' => 3, + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, 'id_site' => 999, 'idabon' => '00123', 'fiche_SIGB' => ['type_comm' => 0] diff --git a/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatNanookTest.php b/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatNanookTest.php index dea46bd3212d816b44d1a50d10a77ddcf9a4591a..d2f908e942357a1ad67776f3c82db406084cea83 100644 --- a/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatNanookTest.php +++ b/tests/application/modules/opac/controllers/AbonneControllerSuggestionAchatNanookTest.php @@ -54,9 +54,12 @@ abstract class AbstractAbonneControllerSuggestionAchatNanookTestCase extends Abs $sigb_conf->setIdBib(12); $this->_francis = $this->fixture('Class_Users', ['id' => 3, + 'id_site' => 12, 'id_sigb' => '187', 'login' => 'francis', 'password' => 'test', + 'idabon' => 'francis', + 'role_level' => 2, 'int_bib' => $sigb_conf]); ZendAfi_Auth::getInstance()->logUser($this->_francis); diff --git a/tests/application/modules/opac/controllers/AuthControllerResetPasswordTest.php b/tests/application/modules/opac/controllers/AuthControllerResetPasswordTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c37537bff1a543a5c53ca9dda8568e05a11b7f4d --- /dev/null +++ b/tests/application/modules/opac/controllers/AuthControllerResetPasswordTest.php @@ -0,0 +1,133 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +abstract class AuthControllerResetPasswordTestCase extends AbstractControllerTestCase { + protected + $_storm_default_to_volatile=true, + $_user; + + public function setUp() { + parent::setUp(); + + Class_User_LostPass::setTimeSource((new TimeSourceForTest('2017-11-30')) + ->atCoffeeTime()); + + $this->_user = $this->fixture('Class_Users', + ['id' => 45, + 'login' => 'sysnoadm', + 'password' => 'supersecret']); + } + + + public function tearDown() { + Class_User_LostPass::setTimeSource(null); + parent::tearDown(); + } + + + protected function urlFor($id, $token, $created) { + return sprintf('/opac/auth/reset-password/id/%s/token/%s/created/%s', + $id, $token, $created); + } +} + + + +class AuthControllerResetPasswordActionTest + extends AuthControllerResetPasswordTestCase { + + /** @test */ + public function unknownUserShouldHaveError() { + $this->dispatch($this->urlFor(99999999, sha1('test'), '20231207040545'), true); + $this->assertXPathContentContains('//div', 'Utilisateur inconnu', + $this->_response->getBody()); + } + + + /** @test */ + public function badTokenShouldHaveError() { + $this->dispatch($this->urlFor($this->_user->getId(), sha1('test'),'20231207040545'), true); + $this->assertXPathContentContains('//div', 'Jeton de réinitialisation invalide', + $this->_response->getBody()); + } + + + /** @test */ + public function outdatedTokenShouldHaveError() { + $token = (new Class_User_LostPass($this->_user))->tokenAt('20071207040545'); + + $this->dispatch($this->urlFor($this->_user->getId(), $token, '20071207040545'), true); + $this->assertXPathContentContains('//div', 'Jeton de réinitialisation expiré', + $this->_response->getBody()); + } + + + /** @test */ + public function validTokenShouldDisplayForm() { + $token = (new Class_User_LostPass($this->_user))->tokenAt('20171130154500'); + + $this->dispatch($this->urlFor($this->_user->getId(), $token, '20171130154500'), true); + $this->assertXPath('//form[contains(@action, "auth/reset-password")]', + $this->_response->getBody()); + } +} + + + +class AuthControllerResetPasswordActionPostTest + extends AuthControllerResetPasswordTestCase { + protected $_url; + + public function setUp() { + parent::setUp(); + + $token = (new Class_User_LostPass($this->_user))->tokenAt('20171130154500'); + $this->_url = $this->urlFor($this->_user->getId(), $token, '20171130154500'); + } + + + /** @test */ + public function withoutPasswordsShouldHaveError() { + $this->postDispatch($this->_url, ['new_pass' => '', 'confirm_pass' => '']); + $this->assertXPathContentContains('//div', 'Une valeur est requise'); + } + + + /** @test */ + public function withDifferentPasswordsShouldHaveError() { + $this->postDispatch($this->_url, ['new_pass' => 'secret', + 'confirm_pass' => 'terces']); + + $this->assertXPathContentContains('//div', 'Les champs \'Mot de passe\' sont différents'); + } + + + /** @test */ + public function withSamePasswordShouldUpdateUserAndRedirectToLogin() { + $this->postDispatch($this->_url, ['new_pass' => 'secret', + 'confirm_pass' => 'secret']); + + $this->assertTrue($this->_user->verifyPassword('secret')); + $this->assertRedirectTo('/auth/login'); + $this->assertFlashMessengerContentContains('Votre mot de passe a été réinitialisé, vous pouvez vous connecter.'); + } +} \ No newline at end of file diff --git a/tests/application/modules/opac/controllers/AuthControllerTest.php b/tests/application/modules/opac/controllers/AuthControllerTest.php index fc725cc8659a33e366c099e97c1c1757b3a69b99..816969a0dd1737347c0ba10644064dc7e62c8434 100644 --- a/tests/application/modules/opac/controllers/AuthControllerTest.php +++ b/tests/application/modules/opac/controllers/AuthControllerTest.php @@ -1316,27 +1316,27 @@ class AuthControllerLoginActionWithDefaultPreferencesRenderTest extends AuthCont } } -class AuthControllerLostPasswordUnknownPostTest extends AbstractControllerTestCase{ - protected $_storm_default_to_volatile = true; - public function setUp() { - parent::setUp(); - } +class AuthControllerLostPasswordUnknownPostTest extends AbstractControllerTestCase{ + protected $_storm_default_to_volatile = true; /** @test */ public function withUnknowUserShouldDisplayError() { - $this->postDispatch('/opac/auth/lostpass',['lost_username' => 'unknown']); - $this->assertXPathContentContains('//div', 'Identifiant inconnu',$this->_response->getBody()); + $this->postDispatch('/opac/auth/lostpass', ['lost_username' => 'unknown']); + $this->assertXPathContentContains('//div', + 'Identifiant inconnu', + $this->_response->getBody()); } /** @test */ public function withEmptyUserShouldDisplayError() { - $this->postDispatch('/opac/auth/lostpass',['lost_username' => '']); - $this->assertXPathContentContains('//div', 'Veuillez saisir votre identifiant.',$this->_response->getBody()); + $this->postDispatch('/opac/auth/lostpass', ['lost_username' => '']); + $this->assertXPathContentContains('//div', + 'Une valeur est requise', + $this->_response->getBody()); } - } diff --git a/tests/application/modules/opac/controllers/MultimediaControllerTest.php b/tests/application/modules/opac/controllers/MultimediaControllerTest.php index 7bb1f5039962303c66f0fbd2d8e38d9f9a9eb7a7..22fa897a70ec6efea747767a3e705b9d6428a83a 100644 --- a/tests/application/modules/opac/controllers/MultimediaControllerTest.php +++ b/tests/application/modules/opac/controllers/MultimediaControllerTest.php @@ -105,10 +105,10 @@ abstract class MultimediaControllerAuthenticateTestCase extends MultimediaContro /** * @param $user Class_Users */ - protected function _expectUserToLoad($user) { + protected function _expectUserToLoad($user, $pass=null) { $this->_auth ->whenCalled('authenticateLoginPassword') - ->with($user->getLogin(), $user->getPassword(), ['auth_sigb', 'auth_db']) + ->with($user->getLogin(), $pass ? $pass : $user->getPassword(), ['auth_sigb', 'auth_db']) ->willDo( function() use ($user) { $this->_auth @@ -215,7 +215,7 @@ class MultimediaControllerAuthenticateInviteNonAfiMultimediaTest extends Multime public function setUp() { parent::setUp(); $user = MultimediaControllerUsersFixtures::getInvite(); - $this->_expectUserToLoad($user); + $this->_expectUserToLoad($user, 'invite'); $this->_json = $this->getJson('/multimedia/authenticate/login/invite/password/invite'); } @@ -225,7 +225,6 @@ class MultimediaControllerAuthenticateInviteNonAfiMultimediaTest extends Multime public function shouldReturnSubscriptionExpired() { $this->assertEquals('SubscriptionExpired', $this->_json->error); } - } @@ -233,7 +232,7 @@ class MultimediaControllerAuthenticateInviteAfiMultimediaTest extends Multimedia public function setUp() { parent::setUp(); $user = MultimediaControllerUsersFixtures::getInvite(); - $this->_expectUserToLoad($user); + $this->_expectUserToLoad($user, 'invite'); $this->_expectGroupForUser($user, 'Abonne multimedia'); $this->_json = $this->getJson('/multimedia/authenticate/login/invite/password/invite'); diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php index 83773d7f2582ee4a954a1d59af1e467f921c5838..5dcef8ae354ddb6934a43b4a81391119c5d3cc35 100644 --- a/tests/db/UpgradeDBTest.php +++ b/tests/db/UpgradeDBTest.php @@ -1774,3 +1774,22 @@ class UpgradeDB_337_Test extends UpgradeDBTestCase { $this->assertColumn('multimedia_device', 'note'); } } + + + +class UpgradeDB_338_Test extends UpgradeDBTestCase { + public function prepare() { + try { + $this->query('update bib_admin_users set password="pass" where id_user=1'); + } catch(Exception $e) {} + } + + + /** @test */ + public function adminPasswordShouldBeHashed() { + $datas = $this->query('select password from bib_admin_users where id_user=1') + ->fetch(); + + $this->assertEquals('$2y$', substr($datas['password'], 0, 4)); + } +} diff --git a/tests/library/Class/MailTest.php b/tests/library/Class/MailTest.php index 8e6a5133eb76ead842e33d584980ab3d539bc0e1..ba5fec229aa939cd3106c706d7758cef90d455b9 100644 --- a/tests/library/Class/MailTest.php +++ b/tests/library/Class/MailTest.php @@ -16,22 +16,21 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class Class_MailTesting extends Class_Mail { - protected - $_destinataire, - $_sujet, - $_body, - $_headers, + protected + $_destinataire, + $_sujet, + $_body, + $_headers, $_mail_return_value; - public function mail($destinataire, $sujet, $body, $headers) { + public function mail($destinataire, $sujet, $body) { $this->_destinataire = $destinataire; $this->_sujet = $sujet; $this->_body = $body; - $this->_headers = $headers; return $this->_mail_return_value; } @@ -58,21 +57,22 @@ class Class_MailTesting extends Class_Mail { -class MailToZorkFromFlorenceTest extends Storm_Test_ModelTestCase { +class MailToZorkFromFlorenceTest extends ModelTestCase { + protected $_storm_default_to_volatile=true; + public function setUp() { parent::setUp(); Class_CosmoVar::getLoader() ->newInstanceWithId('mail_admin') ->setValeur('florence@astrolabe-melun.fr'); - - Class_Profil::getCurrentProfil()->setMailSite(''); - Class_Profil::getPortail()->setMailSite(''); + $this->fixture('Class_Profil', ['id' => 1, + 'mail_site' => '']); $this->_mail_testing = new Class_MailTesting(); $this->_mail_testing->mailReturns(true); - $this->_status = $this->_mail_testing->sendMail('Bienvenue !', + $this->_status = $this->_mail_testing->sendMail('Bienvenue !', 'Vous êtes inscrit', 'zork@gmail.com'); } @@ -100,35 +100,28 @@ class MailToZorkFromFlorenceTest extends Storm_Test_ModelTestCase { function bodyShouldBeVousEtesInscrit() { $this->assertEquals('Vous êtes inscrit', $this->_mail_testing->getBody()); } - - - /** @test */ - function headersShouldContainSenderFlorence() { - $this->assertContains('From: florence@astrolabe-melun.fr', - $this->_mail_testing->getMailHeaders()); - } } -class MailErrorsTest extends Storm_Test_ModelTestCase { +class MailErrorsTest extends ModelTestCase { + protected $_storm_default_to_volatile=true; + public function setUp() { parent::setUp(); - Class_Profil::getCurrentProfil()->setMailSite(''); - Class_Profil::getPortail()->setMailSite(''); + + $profil = $this->fixture('Class_Profil', ['id' => 1, 'mail_site' => '']); + Class_Profil::setCurrentProfil($profil); } /** @test */ function withoutMailAdminShouldReturnErrorMessage() { - Class_CosmoVar::getLoader() - ->newInstanceWithId('mail_admin') - ->setValeur(''); - + Class_CosmoVar::setValueOf('mail_admin', ''); $mail_testing = new Class_MailTesting(); $mail_testing->mailReturns(true); - $status = $mail_testing->sendMail('Bienvenue !', + $status = $mail_testing->sendMail('Bienvenue !', 'Vous êtes inscrit', 'zork@gmail.com'); $this->assertContains("Les paramètres d'envoi de mails du portail sont incomplets.", @@ -156,16 +149,15 @@ class MailErrorsTest extends Storm_Test_ModelTestCase { Class_CosmoVar::getLoader() ->newInstanceWithId('mail_admin') ->setValeur('laurent@gmail.com'); + $mail_testing = new Class_MailTesting(); $mail_testing->mailReturns(false); - $status = $mail_testing->sendMail('Bienvenue !', + $status = $mail_testing->sendMail('Bienvenue !', 'Vous êtes inscrit', 'zork@gmail.com'); + $this->assertContains("Les paramètres d'envoi de mails du portail sont incomplets.", $status); } } - - -?> \ No newline at end of file diff --git a/tests/library/Class/WebService/SIGB/CarthameTest.php b/tests/library/Class/WebService/SIGB/CarthameTest.php index 66293b684a06f6b616f23f161bfe63bec67959cc..91100a3aa05280091a7d37fb39173b28dfa4c455 100644 --- a/tests/library/Class/WebService/SIGB/CarthameTest.php +++ b/tests/library/Class/WebService/SIGB/CarthameTest.php @@ -218,6 +218,9 @@ class CarthameKarviPickupLocationsTest extends CarthameOperationTestCase { $user = $this->fixture('Class_Users', ['id' => 34, 'login' => '90100000119049', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'id_site' => 3, + 'idabon' => '90100000119049', 'password' => 'pass']); $item = $this->fixture('Class_Exemplaire', @@ -388,6 +391,9 @@ class CarthameEmprunteurPatrickBTest extends CarthameOperationTestCase { ['id' => 56, 'login' => 'pbarroca', 'password' => '1974', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'idabon' => 'pbarroca', + 'id_site' => 3, 'int_bib' => $library]); ZendAfi_Auth::getInstance()->logUser($user); diff --git a/tests/library/Class/WebService/SIGB/KohaTest.php b/tests/library/Class/WebService/SIGB/KohaTest.php index c1a66ec1b44de5f22bf9dc35a25be13fe6417720..32ddda29a2d271af734bb2c9a2bf0730e99b17fb 100644 --- a/tests/library/Class/WebService/SIGB/KohaTest.php +++ b/tests/library/Class/WebService/SIGB/KohaTest.php @@ -658,6 +658,9 @@ class KohaGetEmprunteurJeanAndreWithIdSIGBTest extends KohaTestCase { ['id' => 43, 'login' => 'JEAN', 'password' => 'zork', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'idabon' => 'Jean', + 'id_site' => 3, 'id_sigb' => '01234'])); } @@ -1146,17 +1149,20 @@ class KohaAuthenticateWSTest extends KohaTestCase { ->with('http://cat-aficg55.biblibre.com/cgi-bin/koha/ilsdi.pl?service=GetPatronInfo&patron_id=96138&show_contact=1&show_loans=1&show_holds=1') ->answers(KohaFixtures::xmlGetPatronInfoDupont()); - $this->emprunteur = $this->service->getEmprunteur( $this->user = $this->fixture('Class_Users', - [ - 'id' => 10, - 'login' => 'john', - 'password' => '1989'])); + $this->user = $this->fixture('Class_Users', ['id' => 10, + 'login' => 'john', + 'password' => '1989', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'idabon' => 'john', + 'id_site' => 3]); + + $this->emprunteur = $this->service->getEmprunteur($this->user); $this->emprunteur->updateUser($this->user); } public function expectedUser() { - return [[ 'nom', 'DUPONT'], + return [['nom', 'DUPONT'], ['prenom' ,'Jean'], ['login' , 'john'], ['password' , '1989'], diff --git a/tests/library/ZendAfi/Auth/TryHarderTest.php b/tests/library/ZendAfi/Auth/TryHarderTest.php index 6b74cf407ca18d39a82ff54f7efb320a66aab28c..b4dd1decb742fb044d1fd27ee3431dc380f80839 100644 --- a/tests/library/ZendAfi/Auth/TryHarderTest.php +++ b/tests/library/ZendAfi/Auth/TryHarderTest.php @@ -16,38 +16,46 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class ZendAfi_Auth_TryHarderTest extends ModelTestCase { - protected $_auth, $_adapter, $_try_harder; + protected + $_storm_default_to_volatile = true, + $_auth, + $_adapter, + $_try_harder; public function setUp() { parent::setUp(); - $this->fixture('Class_Users', ['id' => 1, - 'login' => 'Biquette', - 'password' => '$2a$08$gPuCFG7FU2psZ52z5R.ACeW295qSfRJuTd04i/zwjjNI67ZUmVIHe']); + $this->fixture('Class_Users', + ['id' => 1, + 'login' => 'Biquette', + 'password' => '$2a$08$gPuCFG7FU2psZ52z5R.ACeFgtjLo1D/7C5goi0KCPcmAbG.zwGog2']); + + $this->fixture('Class_Users', + ['id' => 2, + 'login' => 'Other', + 'password' => 'testFeelsGood']); $this->_auth = $this->mock() - ->whenCalled('authenticate') - ->willDo(function () {return $this->_adapter->authenticate();}); + ->whenCalled('authenticate') + ->willDo(function ($adapter) { return $adapter->authenticate(); }); - $this->_adapter = $this->mock() - ->whenCalled('setIdentity')->answers(true) - ->whenCalled('setCredential')->answers(true); + $this->_adapter = new Class_Entity(); $this->_try_harder = new ZendAfi_Auth_TryHarder($this->_auth, $this->_adapter); - $this->_adapter - ->whenCalled('authenticate') - ->willDo( - function() { - return $this->mock() - ->whenCalled('isValid') - ->answers($this->_adapter->methodHasBeenCalledWithParams('setCredential', ['$2a$08$gPuCFG7FU2psZ52z5R.ACeFgtjLo1D/7C5goi0KCPcmAbG.zwGog2'])); - }); + $authenticate = function() { + return ($user = Class_Users::findFirstBy(['login' => $this->_adapter->getIdentity(), + 'password' => $this->_adapter->getCredential()])) + ? new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $user->getId()) + : new Zend_Auth_Result(Zend_Auth_Result::FAILURE, ''); + }; + + $this->_adapter->whenCalledDo('authenticate', $authenticate); } @@ -58,9 +66,22 @@ class ZendAfi_Auth_TryHarderTest extends ModelTestCase { /** @test */ - public function withoutBlowfishInstalledShouldReturnFalse() { + public function blowfishBiquetteWithHashShouldNotBeLogged() { + $this->assertFalse($this->_try_harder + ->tryHarder('Biquette', + '$2a$08$gPuCFG7FU2psZ52z5R.ACeFgtjLo1D/7C5goi0KCPcmAbG.zwGog2')); + } + + + /** @test */ + public function withoutBlowfishInstalledBiquetteShouldNotBeAbleToLogin() { $this->_try_harder->setBlowfishEnabled(false); $this->assertFalse($this->_try_harder->tryHarder('Biquette', 'password')); } + + + /** @test */ + public function withClearPassOtherShouldBeAbleToLogin() { + $this->assertTrue($this->_try_harder->tryHarder('Other', 'testFeelsGood')); + } } -?> \ No newline at end of file