diff --git a/VERSIONS_WIP/40971 b/VERSIONS_WIP/40971 new file mode 100644 index 0000000000000000000000000000000000000000..6bac9e99215e8a61ddfbf5562fcafba8f5e936b9 --- /dev/null +++ b/VERSIONS_WIP/40971 @@ -0,0 +1 @@ + - ticket #40971 : Nanook : Pouvoir prendre l'email comme identifiant alternatif de l'abonné \ No newline at end of file diff --git a/application/modules/opac/controllers/AuthController.php b/application/modules/opac/controllers/AuthController.php index c9a803952143459e3d3e8a3c7fd9cf31b81c92f6..ff318b380bc7bc1507a7d1cbf6a58b32a20b2792 100644 --- a/application/modules/opac/controllers/AuthController.php +++ b/application/modules/opac/controllers/AuthController.php @@ -26,6 +26,13 @@ class AuthController extends ZendAfi_Controller_Action { } + public function onPasswordNotSecure($message, $pattern) { + $this->_setParam('password_hint', $message) + ->_setParam('pattern', $pattern) + ->_forward('secure-password'); + } + + public function indexAction() { $this->_redirect('/opac'); } @@ -90,8 +97,61 @@ class AuthController extends ZendAfi_Controller_Action { } + public function securePasswordAction() { + $this->_setupSecurePasswordForm(); + } + + + protected function _setupSecurePasswordForm() { + $form = new ZendAfi_Form_SecurePassword(); + $form->current_password->setValue($this->_request->getPost('password')); + $form->password_hint->setValue($this->_getParam('password_hint')); + $form->pattern->setValue($this->_getParam('pattern')); + $form + ->secure_password + ->addValidator( + (new Zend_Validate_Regex($this->_getParam('pattern'))) + ->setMessage($this->_getParam('password_hint'), Zend_Validate_Regex::NOT_MATCH)); + + $this->view->title = $this->_('Sécurisation du compte'); + + $this->view->message = $this->_('Vous vous connectez pour la première fois avec votre courriel. Vous devez modifier votre mot de passe pour sécuriser l\'accès par courriel.'); + + $this->view->password_hint = $this->_getParam('password_hint'); + + $this->view->form = $form; + return $form->setAction($this->view->url(['action' => 'do-secure-password'])); + } + + + public function doSecurePasswordAction() { + $card = $this->_request->getPost('card'); + $current_password = $this->_request->getPost('current_password'); + + $form = $this->_setupSecurePasswordForm(); + if (!$form->isValid($this->_request->getPost())) + return $this->renderScript('auth/secure-password.phtml'); + + if (!ZendAfi_Auth::getInstance()->authenticateLoginPassword($card, $current_password)) { + $form->card->addError($this->_('Numéro de carte incorrect')); + return $this->renderScript('auth/secure-password.phtml'); + } + + $user = Class_Users::getIdentity(); + $user->getFicheSIGB(); // init sigb infos + $user + ->setPassword($this->_request->getPost('secure_password')) + ->save(); + + $this->getHelper('notify')->bePopup(); + $this->_helper->notify($this->_('Votre compte est sécurisé. Vous pouvez maintenant vous connecter avec votre courriel et votre nouveau mot de passe.')); + + $this->_redirect('/'); + } + + //see http://www.jasig.org/cas/protocol#cas-uris - function validateAction() { + public function validateAction() { $this->_forward('validate', 'cas-server'); } @@ -110,9 +170,11 @@ class AuthController extends ZendAfi_Controller_Action { $strategy = Auth_Strategy_Abstract::strategyForController($this); $strategy->setDefaultUrl($redirect); - $strategy->onLoginSuccess(function($user) { - $user->registerNotificationsOn($this->getHelper('notify')->bePopup()); - }); + $strategy + ->onLoginSuccess(function($user) + { + $user->registerNotificationsOn($this->getHelper('notify')->bePopup()); + }); $strategy->processLogin(); $this->view->form_action = 'login'; } @@ -124,19 +186,20 @@ class AuthController extends ZendAfi_Controller_Action { $this->view->preferences = $this->_loginPrefFromWidgetOrModule(); - $strategy = Auth_Strategy_Abstract::strategyForController($this); - $strategy->disableRedirect(); - $strategy->onLoginSuccess(function($user) use ($redirect, $location) { - $user->registerNotificationsOn($this->getHelper('notify')); - $this->renderPopup($redirect, $location); - }); - $strategy->processLogin(); - - if (!Class_Users::hasIdentity()) { - $this->renderPopup($this->view->url(['action' => 'popup-login']) - . '?redirect=' . urlencode($redirect) - . ($location ? '&location=' . urlencode($location) : '')); - } + Auth_Strategy_Abstract::strategyForController($this) + ->disableRedirect() + ->onLoginSuccess(function($user) use ($redirect, $location) + { + $user->registerNotificationsOn($this->getHelper('notify')); + $this->renderPopup($redirect, $location); + }) + ->onLoginFail(function() use ($redirect, $location) + { + $this->renderPopup($this->view->url(['action' => 'popup-login']) + . '?redirect=' . urlencode($redirect) + . ($location ? '&location=' . urlencode($location) : '')); + }) + ->processLogin(); } @@ -191,7 +254,11 @@ class AuthController extends ZendAfi_Controller_Action { $this->view->preferences = Class_Profil::getCurrentProfil() ->getModuleAccueilPreferencesByType('LOGIN'); - $url = ($target = Class_Profil::find((int)$this->view->preferences['profil_redirect'])) + $profil_redirect = isset($this->view->preferences['profil_redirect']) + ? (int)$this->view->preferences['profil_redirect'] + : 0; + + $url = ($target = Class_Profil::find($profil_redirect)) ? $target->getUrl() : $this->_request->getServer('HTTP_REFERER'); @@ -510,7 +577,9 @@ class AuthController extends ZendAfi_Controller_Action { abstract class Auth_Strategy_Abstract { protected $redirect_url = '', - $disable_redirect = false; + $disable_redirect = false, + $on_login_success_callback, + $on_login_fail_callback; static public function strategyForController($controller) { if ($controller->isCasRequest() && static::isLogged()) @@ -522,7 +591,6 @@ abstract class Auth_Strategy_Abstract { if ($controller->isLectura()) return new Auth_Strategy_Lectura($controller); - if (static::isLogged()) return new Auth_Strategy_Logged($controller); @@ -534,71 +602,119 @@ abstract class Auth_Strategy_Abstract { return Class_Users::getIdentity(); } + public function disableRedirect() { $this->disable_redirect = true; + return $this; } + public function __construct($controller) { $this->controller = $controller; $this->default_url = $this->controller->getRedirectDefaultUrl(); } + public function getRequest(){ return $this->controller->getRequest(); } + public function processLogin() { $this->prepareLogin(); - if ($this->getRequest()->isPost()) - $this->handlePost(); + if (!$this->getRequest()->isPost()) + return $this->_handleRedirect(); + + $callback = $this->_handlePost(); + + $password_not_secure = Class_WebService_SIGB_Nanook_PatronPasswordNotSecure::getInstance(); + + if (($message = $password_not_secure->getMessage()) + && !$this->controller->view->isPopup()) + return $this->controller->onPasswordNotSecure($message, + $password_not_secure->getPattern()); + + $callback(); + return $this->_handleRedirect(); + } + + + protected function _handleRedirect() { if ($this->shouldRedirect()) $this->controller->redirect($this->redirect_url); + + return $this; } public function setDefaultUrl($url) { - $this->default_url=$url; + $this->default_url = $url; } public function prepareLogin() { - } - /** @codeCoverageIgnore */ - public function handlePost() { + /** @codeCoverageIgnore */ + protected function _handlePost() { + return function() {}; } + public function shouldRedirect() { return ($this->getRedirectUrl()!=''); } + public function getRedirectUrl() { if ($this->disable_redirect) return ''; return $this->redirect_url; } + public function onLoginSuccess($do) { $this->on_login_success_callback = $do; + return $this; } -} + public function onLoginFail($do) { + $this->on_login_fail_callback = $do; + return $this; + } -class Auth_Strategy_NotLogged extends Auth_Strategy_Abstract{ - public function handlePost() { - $this->redirect_url=$this->default_url; - if ($error=$this->controller->_authenticate()) { - $this->controller->notify($error); - } + protected function _doOnLoginFail() { + if (isset($this->on_login_fail_callback)) + call_user_func($this->on_login_fail_callback); + return $this; + } + + protected function _doOnLoginSuccess() { if (($user = Class_Users::getIdentity()) && isset($this->on_login_success_callback)) call_user_func($this->on_login_success_callback, $user); + return $this; + } +} + + + + +class Auth_Strategy_NotLogged extends Auth_Strategy_Abstract{ + protected function _handlePost() { + $this->redirect_url = $this->default_url; + if (!$error = $this->controller->_authenticate()) + return function() { return $this->_doOnLoginSuccess(); }; + + return function() use($error) { + $this->controller->notify($error); + return $this->_doOnLoginFail(); + }; } } @@ -660,10 +776,12 @@ class Auth_Strategy_Cas_Logged extends Auth_Strategy_Cas_Abstract{ class Auth_Strategy_Cas_NotLogged extends Auth_Strategy_Cas_Abstract{ - public function handlePost() { - if ($error=$this->controller->_authenticate()) - return $this->controller->notify($error); - $this->redirect_url=$this->urlServiceCas(); + protected function _handlePost() { + if ($error = $this->controller->_authenticate()) + return function() use($error) { return $this->controller->notify($error); }; + + $this->redirect_url = $this->urlServiceCas(); + return function() {}; } } @@ -671,16 +789,20 @@ class Auth_Strategy_Cas_NotLogged extends Auth_Strategy_Cas_Abstract{ class Auth_Strategy_Lectura extends Auth_Strategy_Abstract { - public function handlePost() { + protected function _handlePost() { $this->controller->getHelper('ViewRenderer')->setNoRender(); - $response= $this->controller->getResponse(); + + $response = $this->controller->getResponse(); $view = $this->controller->view; $request = $this->controller->getRequest(); + $response->setHeader('Content-Type', 'application/xml;charset=utf-8'); $login = $request->getPost('CAB'); $password = $request->getPost('PWD'); $response->setBody($this->getXmlResponse($view, ZendAfi_Auth::getInstance()->authenticateLoginPassword($login, $password))); + + return function() {}; } @@ -696,10 +818,11 @@ class Auth_Strategy_Lectura extends Auth_Strategy_Abstract { class Auth_Strategy_OAuth extends Auth_Strategy_NotLogged { - public function handlePost() { - parent::handlePost(); + protected function _handlePost() { + parent::_handlePost(); + if (!$user = Class_Users::getIdentity()) - return $this; + return function() {}; $request = $this->controller->getRequest(); @@ -708,5 +831,7 @@ class Auth_Strategy_OAuth extends Auth_Strategy_NotLogged { $this->redirect_url = sprintf('%s#token=%s', $request->getParam('redirect_uri'), $token->getToken()); + + return function() {}; } } \ No newline at end of file diff --git a/application/modules/opac/views/scripts/auth/ajax-login.phtml b/application/modules/opac/views/scripts/auth/ajax-login.phtml index dd16c16189591505d4ef03d3b87a89846b3928cf..ef0a781ecfa6a85dda1b830bfa1829c459dd58d8 100644 --- a/application/modules/opac/views/scripts/auth/ajax-login.phtml +++ b/application/modules/opac/views/scripts/auth/ajax-login.phtml @@ -29,14 +29,17 @@ function submit() { } else { ?> <div class="formTable"> <?php + $action = ['controller' => 'auth', + 'action' => 'ajax-login']; + if ($this->isPopup()) + $action['render'] = 'popup'; + $form = ZendAfi_Form_Login::newWithOptions(['data' => array_merge($this->preferences, ['redirect_url' => $this->redirect, 'id_notice' => $this->id_notice]), - 'action' => $this->url(['controller' => 'auth', - 'action' => 'ajax-login'], - null, true) - . ($this->location ? '?location=' . $this->location : '')]); + 'action' => $this->url($action, null, true) + . ($this->location ? '?location=' . $this->location : '')]); echo $this->renderForm($form); diff --git a/application/modules/opac/views/scripts/auth/secure-password.phtml b/application/modules/opac/views/scripts/auth/secure-password.phtml new file mode 100644 index 0000000000000000000000000000000000000000..c353be76edbb720734bca4195a46cbeed29eb089 --- /dev/null +++ b/application/modules/opac/views/scripts/auth/secure-password.phtml @@ -0,0 +1,9 @@ +<?php +$this->openBoite($this->title); + +echo $this->tag('p', $this->message); +echo $this->tag('p', $this->password_hint); + +echo $this->renderForm($this->form); + +$this->closeBoite(); diff --git a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php index a625bef5ae55b8c88c9e910bf2f77a9d1b6ea794..e977750460a33fd098dbf4e9a1a1fabfd6cf37a7 100644 --- a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php +++ b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php @@ -26,7 +26,8 @@ class Cosmo_IntegrationControllerTestActionTest extends CosmoControllerTestCase public function setUp() { parent::setUp(); $this->_service = $this->mock()->whenCalled('test')->answers(''); - Class_WebService_SIGB_Nanook::setService($this->_service); + Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://localhost/ilsdi'], + $this->_service); } diff --git a/library/Class/WebService/SIGB/AbstractRESTService.php b/library/Class/WebService/SIGB/AbstractRESTService.php index 857648b26603573f365e4efc3bc6b9bfe319fac9..d7415cddd5dd016aec4832bc49916fb5387db89a 100644 --- a/library/Class/WebService/SIGB/AbstractRESTService.php +++ b/library/Class/WebService/SIGB/AbstractRESTService.php @@ -188,27 +188,6 @@ abstract class Class_WebService_SIGB_AbstractRESTService extends Class_WebServic } - /** - * Authentifie un utilisateur via SIGB et si réussi affecte l'id_sigb reçu - * @param $user Class_Users - * @return boolean true if successful - */ - public function ilsdiAuthenticatePatron($user) { - $params = ['service' => 'AuthenticatePatron', - 'username' => $user->getLogin(), - 'password' => $user->getPassword()]; - - $xml = $this->httpGet($params); - - if ('' != $patronId = $this->_getTagData($xml, 'patronId')) { - $user->setIdSigb($patronId); - return true; - } - - return false; - } - - /** * @param array $params * @return array diff --git a/library/Class/WebService/SIGB/Nanook.php b/library/Class/WebService/SIGB/Nanook.php index 4e71a26a73f7614d116b9e7249efc1ebdde4973b..b7a22e09fdfc7af40e87b7f9d1cb476a006c1644 100644 --- a/library/Class/WebService/SIGB/Nanook.php +++ b/library/Class/WebService/SIGB/Nanook.php @@ -18,21 +18,40 @@ * along with BOKEH; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -class Class_WebService_SIGB_Nanook extends Class_WebService_SIGB_Abstract { +class Class_WebService_SIGB_Nanook { + protected static $services = []; + + public static function makeKey($params) { + return md5(serialize($params)); + } public static function getService($params){ + $key = static::makeKey($params); + if (!isset($params['provide_suggest'])) $params = array_merge(['provide_suggest' => ''], $params); - if (!isset(static::$service)) { + + if (!isset(static::$services[$key])) { $instance = new static(); $classname = get_called_class().'_Service'; - static::$service = $classname::getService($params['url_serveur'], - $params['provide_suggest'] === '1'); + $service = $classname::getService($params['url_serveur'], + $params['provide_suggest'] === '1'); + static::$services[$key] = $service; } - return static::$service; + return static::$services[$key]; + } + + + public static function setService($params, $service) { + static::$services[static::makeKey($params)] = $service; + } + + + public static function reset() { + static::$services = []; } } diff --git a/library/Class/WebService/SIGB/Nanook/PatronPasswordNotSecure.php b/library/Class/WebService/SIGB/Nanook/PatronPasswordNotSecure.php new file mode 100644 index 0000000000000000000000000000000000000000..36ed6a8b106d3e74d838f84e34db3202a5143c61 --- /dev/null +++ b/library/Class/WebService/SIGB/Nanook/PatronPasswordNotSecure.php @@ -0,0 +1,26 @@ +<?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_WebService_SIGB_Nanook_PatronPasswordNotSecure extends Class_Entity { + use Trait_Singleton; + +} diff --git a/library/Class/WebService/SIGB/Nanook/Service.php b/library/Class/WebService/SIGB/Nanook/Service.php index 457b1a8b43a55e59f7e1f24583d2932c150c4cdf..7c38e2365de84bb67e375b18f7ff02963e6de69c 100644 --- a/library/Class/WebService/SIGB/Nanook/Service.php +++ b/library/Class/WebService/SIGB/Nanook/Service.php @@ -60,6 +60,38 @@ class Class_Webservice_SIGB_Nanook_Service extends Class_WebService_SIGB_Abstrac } + /** + * Authentifie un utilisateur via SIGB et si réussi affecte l'id_sigb reçu + * @param $user Class_Users + * @return boolean true if successful + */ + public function ilsdiAuthenticatePatron($user) { + $params = ['service' => 'AuthenticatePatron', + 'username' => $user->getLogin(), + 'password' => $user->getPassword()]; + + $xml = $this->httpGet($params); + + if ('PatronPasswordNotSecure' == $this->_getTagData($xml, 'error')) { + $message = $this->_getTagData($xml, 'securePasswordLabel'); + $pattern = '/' . $this->_getTagData($xml, 'securePasswordPattern') . '/'; + + Class_WebService_SIGB_Nanook_PatronPasswordNotSecure::getInstance() + ->setMessage($message) + ->setPattern($pattern); + + return false; + } + + if ('' != $patronId = $this->_getTagData($xml, 'patronId')) { + $user->setIdSigb($patronId); + return true; + } + + return false; + } + + /** * @param Class_Users $user * @return Class_WebService_SIGB_Emprunteur diff --git a/library/ZendAfi/Form/SecurePassword.php b/library/ZendAfi/Form/SecurePassword.php new file mode 100644 index 0000000000000000000000000000000000000000..6692e75c543eb05f655a0f4dbf0625556a79feac --- /dev/null +++ b/library/ZendAfi/Form/SecurePassword.php @@ -0,0 +1,55 @@ +<?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_SecurePassword extends ZendAfi_Form { + public function init() { + parent::init(); + + $this->addElement('text', + 'card', + ['label' => $this->_('Numéro de carte'), + 'required' => true, + 'allowEmpty' => false]) + + ->addElement('password', + 'secure_password', + ['label' => $this->_('Nouveau mot de passe'), + 'required' => true, + 'renderPassword' => true, + 'allowEmpty' => false]) + + ->addElement('password', + 'confirm_password', + ['label' => $this->_('Confirmez le mot de passe'), + 'required' => true, + 'renderPassword' => true, + 'allowEmpty' => false, + 'validators' => [new ZendAfi_Validate_PasswordEquals('secure_password')]]) + + ->addElement('hidden', 'current_password') + ->addElement('hidden', 'password_hint') + ->addElement('hidden', 'pattern') + + ->addUniqDisplayGroup('password', ['legend' => '']) + ; + } +} diff --git a/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php b/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f60991fb2144a922cc61178c975f82bd05a60479 --- /dev/null +++ b/tests/application/modules/opac/controllers/AuthControllerWithNanookTest.php @@ -0,0 +1,310 @@ +<?php +/** + * Copyright (c) 2012, 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 AuthControllerNanookTestCase extends AbstractControllerTestCase { + + protected + $_storm_default_to_volatile = true, + $_web_client, + $_service; + + public function setUp() { + parent::setUp(); + + Class_WebService_SIGB_Nanook::reset(); + + $this->_web_client = $this + ->mock() + ->whenCalled('open_url') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/AuthenticatePatron/username/name%40server.tld/password/1987') + ->answers('<?xml version="1.0" encoding="UTF-8"?><AuthenticatePatron><patronId>4</patronId><error>PatronPasswordNotSecure</error>' + . '<securePasswordPattern>^(?=.*[A-Za-z])(?=.*\d).{6,}$</securePasswordPattern>' + . '<securePasswordLabel>Le mot de passe doit comporter au minimum 6 caractères et doit être constitué d\'au moins un chiffre et une lettre</securePasswordLabel>' + . '</AuthenticatePatron>') + ->beStrict(); + + $this->_service = Class_WebService_SIGB_Nanook_Service::newInstance() + ->setServerRoot('http://localhost:8080/afi_Nanook/ilsdi/') + ->setWebClient($this->_web_client); + + $params = ['url_serveur' => 'http://localhost:8080/afi_Nanook/ilsdi/', + 'id_bib' => 5, + 'type' => Class_IntBib::COM_NANOOK]; + + Class_WebService_SIGB_Nanook::setService($params, $this->_service); + + ZendAfi_Auth::getInstance()->clearIdentity(); + + $this->fixture('Class_Bib', + ['id' => 5, + 'libelle' => 'Seynod']); + + $this->fixture('Class_IntBib', + ['id' => 5, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => serialize($params)]); + } + + + public function tearDown() { + Class_WebService_SIGB_Nanook::reset(); + parent::tearDown(); + } +} + + + + +class AuthControllerWithNanookPostLoginWithMailAndUnsecurePassword + extends AuthControllerNanookTestCase { + + public function setUp() { + parent::setUp(); + + $this->postDispatch('/opac/auth/boite-login', ['username' => 'name@server.tld', + 'password' => '1987']); + } + + /** @test */ + public function pageShouldContainsParagraphWithExplanation() { + $this->assertXPathContentContains('//p', 'Vous vous connectez'); + } + + + /** @test */ + public function pageShouldContainsPasswordExplanation() { + $this->assertXPathContentContains('//p', 'Le mot de passe doit comporter au minimum 6'); + } + + + /** @test */ + public function formShouldContainsInputPasswordHint() { + $this->assertXPath('//form//input[@type="hidden"][contains(@value, "Le mot de passe")][@name="password_hint"]'); + } + + +/** @test */ + public function formShouldContainsInputPattern() { + $this->assertXPath('//form//input[@type="hidden"][@value="/^(?=.*[A-Za-z])(?=.*\d).{6,}$/"][@name="pattern"]'); + } + + + /** @test */ + public function responseShouldContainsFormWithCard() { + $this->assertXPath('//form//input[@name="card"]'); + } + + + /** @test */ + public function formShouldContainsCurrentPasswordField() { + $this->assertXPath('//form//input[@type="hidden"][@name="current_password"][@value="1987"]'); + } + + + /** @test */ + public function formShouldContainsSecurePasswordField() { + $this->assertXPath('//form//input[@type="password"][@name="secure_password"]'); + } + + + /** @test */ + public function formShouldContainsConfirmPasswordField() { + $this->assertXPath('//form//input[@type="password"][@name="confirm_password"]'); + } + + + /** @test */ + public function formActionShouldBeAuthSecurePassword() { + $this->assertXPath('//form[contains(@action, "/auth/do-secure-password")]', $this->_response->getBody()); + } +} + + + + +class AuthControllerWithNanookPostSecurePasswordWithMailAndUnsecurePassword + extends AuthControllerNanookTestCase { + + public function setUp() { + parent::setUp(); + + $this->_web_client + ->whenCalled('open_url') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/AuthenticatePatron/username/ZBTIC1234/password/1987') + ->answers('<?xml version="1.0" encoding="UTF-8"?><AuthenticatePatron><patronId>9876</patronId></AuthenticatePatron>') + + ->whenCalled('open_url') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/GetPatronInfo/patronId/9876') + ->answers('<?xml version="1.0" encoding="utf-8"?><GetPatronInfo><patronId>9876</patronId><mail>name@server.tld</mail><barcode>03456</barcode></GetPatronInfo>') + + ->whenCalled('postData') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/UpdatePatronInfo/patronId/9876', + ['password' => 'rox@r#1', + 'mail' => 'name@server.tld', + 'phoneNumber' => '']) + ->answers('<?xml version="1.0" encoding="utf-8"?><GetPatronInfo><patronId>9876</patronId><mail>name@server.tld</mail><barcode>03456</barcode></GetPatronInfo>') + + ->beStrict(); + + + $this->postDispatch('/opac/auth/do-secure-password', ['card' => 'ZBTIC1234', + 'current_password' => '1987', + 'secure_password' => 'rox@r#1', + 'confirm_password' => 'rox@r#1', + 'pattern' => '/^(?=.*[^0-9])(?=.*[0-9]).{6,}$/', + 'password_hint' => 'doit faire au moins 6', + ]); + } + + + /** @test */ + public function responseShouldRedirect() { + $this->assertRedirectTo('/'); + } + + + /** @test */ + public function usersZBTIC1234ShouldHavePasswordRoxor() { + $this->assertNotNull(Class_Users::findFirstBy(['login' => 'ZBTIC1234', + 'password' => 'rox@r#1'])); + } + + + /** @test */ + public function responseShouldNotifyAccountSuccessfullySecured() { + $this->assertFlashMessengerContentContains('compte est sécurisé'); + } + + + /** @test */ + public function userShouldBeConnected() { + $this->assertNotNull(Class_Users::getIdentity()); + } +} + + + + +class AuthControllerWithNanookPostDoSecurePasswordWithWrongCard + extends AuthControllerNanookTestCase { + public function setUp() { + parent::setUp(); + + $this->_web_client + ->whenCalled('open_url') + ->with('http://localhost:8080/afi_Nanook/ilsdi/service/AuthenticatePatron/username/ZBTIC1234/password/1987') + ->answers('<?xml version="1.0" encoding="UTF-8"?><AuthenticatePatron><error>PatronNotFound</error></AuthenticatePatron>') + ->beStrict(); + + $this->postDispatch('/opac/auth/do-secure-password', ['card' => 'ZBTIC1234', + 'current_password' => '1987', + 'secure_password' => 'rox@r#1', + 'confirm_password' => 'rox@r#1', + 'pattern' => '/^(?=.*[^0-9])(?=.*[0-9]).{6,}$/', + 'password_hint' => 'doit faire au moins 6', + ]); + } + + + /** @test */ + public function formShouldDisplayErrorBadCard() { + $this->assertXPathContentContains('//li', 'Numéro de carte incorrect'); + } + + + /** @test */ + public function passwordShouldContains1987() { + $this->assertXPath('//form//input[@type="hidden"][@name="current_password"][@value="1987"]'); + } + + + /** @test */ + public function inputCardShouldContainsZBTIC1234() { + $this->assertXPath('//form//input[@type="text"][@name="card"][@value="ZBTIC1234"]'); + } + + + /** @test */ + public function securePasswordShouldContainsRoxor() { + $this->assertXPath('//form//input[@type="password"][@name="secure_password"][@value="rox@r#1"]'); + } + + + /** @test */ + public function confirmPasswordShouldContainsRoxor() { + $this->assertXPath('//form//input[@type="password"][@name="confirm_password"][@value="rox@r#1"]'); + } +} + + + +class AuthControllerWithNanookPostDoSecurePasswordWithErrorsTest + extends AuthControllerNanookTestCase { + + /** @test */ + public function formShouldDisplayErrorPasswordDoesNotMatch() { + $this->postDispatch('/opac/auth/do-secure-password', ['card' => 'ZBTIC1234', + 'current_password' => '1987', + 'secure_password' => 'rox@r#1', + 'confirm_password' => 'rouk1', + 'pattern' => '/^(?=.*[^0-9])(?=.*[0-9]).{6,}$/', + 'password_hint' => 'doit faire au moins 6', + ]); + $this->assertXPathContentContains('//li', 'Les champs \'Mot de passe\' sont différents'); + } + + + /** @test */ + public function formShouldDisplayErrorPasswordDoesNotFollowPattern() { + $this->postDispatch('/opac/auth/do-secure-password', ['card' => 'ZBTIC1234', + 'current_password' => '1987', + 'secure_password' => 'pouet', + 'confirm_password' => 'pouet', + 'pattern' => '/^(?=.*[^0-9])(?=.*[0-9]).{6,}$/', + 'password_hint' => 'doit faire au moins 6', + ]); + $this->assertXPathContentContains('//li', 'doit faire au moins 6'); + } +} + + + + +class AuthControllerWithNanookPostLoginWithMailAndUnsecurePasswordOthersLogins + extends AuthControllerNanookTestCase { + + /** @test */ + public function withActionLoginShouldForwardToSecurePassword() { + $this->postDispatch('/opac/auth/login', ['username' => 'name@server.tld', + 'password' => '1987']); + + $this->assertXPathContentContains('//p', 'Vous vous connectez', $this->_response->getBody()); + } + + + /** @test */ + public function withActionAjaxLoginShouldForwardToSecurePassword() { + $this->postDispatch('/opac/auth/ajax-login', ['username' => 'name@server.tld', + 'password' => '1987']); + + $this->assertXPathContentContains('//p', 'Vous vous connectez', $this->_response->getBody()); + } +} \ No newline at end of file diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php index 4137cb2d0307e9aca0f912fdc542e78b969ce29e..b33436331fe17be0ad14f2fd6940fc879d228916 100644 --- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php +++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php @@ -645,6 +645,7 @@ class NoticeAjaxControllerResumeAlbumTest extends AbstractControllerTestCase { abstract class NoticeAjaxControllerExemplairesTestCase extends AbstractControllerTestCase { protected + $_storm_default_to_volatile=true, $_notice, $_sigb_exemplaire; @@ -656,7 +657,8 @@ abstract class NoticeAjaxControllerExemplairesTestCase extends AbstractControlle $this->fixture('Class_IntBib', ['id' => 4, - 'comm_sigb' => Class_IntBib::COM_NANOOK]); + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => ['url_serveur' => 'http://nanook']]); $this->fixture('Class_bib', ['id' => 99]); @@ -705,7 +707,10 @@ abstract class NoticeAjaxControllerExemplairesTestCase extends AbstractControlle ->whenCalled('canConsult') ->answers(false); - Class_WebService_SIGB_Nanook::setService($mock_sigb_comm); + Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://nanook', + 'id_bib' => 4, + 'type' => Class_IntBib::COM_NANOOK,], + $mock_sigb_comm); } } @@ -1415,7 +1420,7 @@ class NoticeAjaxControllerDisponibiliteNoticeTest extends AbstractControllerTest abstract class NoticeAjaxControllerNoticeWithAvisTestCase extends AbstractControllerTestCase { - + protected $_storm_default_to_volatile = true; public function setup() { parent::setup(); diff --git a/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php b/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php index f84f21dae803badda27e58e8fb88f59db7028183..1cb371b15aaf553675669fceb365452364f3f269 100644 --- a/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php +++ b/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php @@ -104,27 +104,31 @@ class RechercheControllerReservationPickupAjaxActionPostTest extends AbstractCon class RechercheControllerReservationPickupAjaxActionTestWithChosenPickupDispatch extends AbstractControllerTestCase { - protected $_json, $_xpath; + protected $_json, $_xpath, $_storm_default_to_volatile = true; public function setUp() { parent::setUp(); - $this->jajm = $this->fixture('Class_Users', - ['id' => 1, - 'login' => 'jajm', - 'password' => 'secret', - 'idabon' => '0000007', - 'int_bib' => $this->fixture('Class_IntBib', - ['id' => 1, - 'comm_sigb' => Class_IntBib::COM_NANOOK, - 'comm_params' => ['url_serveur' => 'http://bib.valensol.net']]) - ]); + $this->jajm = $this + ->fixture('Class_Users', + ['id' => 1, + 'login' => 'jajm', + 'password' => 'secret', + 'idabon' => '0000007', + 'int_bib' => $this->fixture('Class_IntBib', + ['id' => 1, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => ['url_serveur' => 'http://bib.valensol.net']]) + ]); $this->nanook = Storm_Test_ObjectWrapper::mock() ->whenCalled('isConnected')->answers(true) ->whenCalled('reserverExemplaire')->answers(true); - Class_WebService_SIGB_Nanook::setService($this->nanook); + Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net', + 'id_bib' => 1, + 'type' => Class_IntBib::COM_NANOOK,], + $this->nanook); ZendAfi_Auth::getInstance()->logUser($this->jajm); @@ -148,8 +152,9 @@ class RechercheControllerReservationPickupAjaxActionTestWithChosenPickupDispatch } -class RechercheControllerReservationPickupAjaxActionTestWithPatronLibraryPickup extends AbstractControllerTestCase { - protected $_json, $_xpath; +class RechercheControllerReservationPickupAjaxActionTestWithPatronLibraryPickup + extends AbstractControllerTestCase { + protected $_json, $_xpath, $_storm_default_to_volatile = true; public function setUp() { parent::setUp(); @@ -171,7 +176,10 @@ class RechercheControllerReservationPickupAjaxActionTestWithPatronLibraryPickup ->whenCalled('providesPickupLocations')->answers(false) ->whenCalled('getUserAnnexe')->answers('12'); - Class_WebService_SIGB_Nanook::setService($this->nanook); + Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net', + 'id_bib' => 12, + 'type' => Class_IntBib::COM_NANOOK,], + $this->nanook); ZendAfi_Auth::getInstance()->logUser($this->jajm); @@ -207,7 +215,7 @@ class RechercheControllerReservationPickupAjaxActionTestWithPatronLibraryPickup class RechercheControllerReservationPickupAjaxActionTestWithItemLibraryPickup extends AbstractControllerTestCase { - protected $_json, $_xpath; + protected $_json, $_xpath, $_storm_default_to_volatile=true; public function setUp() { parent::setUp(); @@ -229,7 +237,10 @@ class RechercheControllerReservationPickupAjaxActionTestWithItemLibraryPickup ex ->whenCalled('reserverExemplaire')->answers(true); - Class_WebService_SIGB_Nanook::setService($this->nanook); + Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net', + 'id_bib' => 1, + 'type' => Class_IntBib::COM_NANOOK,], + $this->nanook); ZendAfi_Auth::getInstance()->logUser($this->jajm); diff --git a/tests/library/Class/CommSigbTest.php b/tests/library/Class/CommSigbTest.php index a9b31874825dff5da983445029ec32359cd176cf..e582ffabe34bf8638c5054c5d58f93f3200458ef 100644 --- a/tests/library/Class/CommSigbTest.php +++ b/tests/library/Class/CommSigbTest.php @@ -478,21 +478,24 @@ class CommSigbLocalNanookTest extends CommSigbTestCase { public function setUp() { parent::setUp(); - $this->bib_pontault = Class_IntBib::getLoader() - ->newInstanceWithId(5) - ->setCommParams(array("url_serveur" => 'http://192.168.2.3:9080/afi_Nanook-0.7.5/ilsdi/')) + $params = ["url_serveur" => 'http://192.168.2.3:9080/afi_Nanook-0.7.5/ilsdi/']; + $this->bib_pontault = Class_IntBib::newInstanceWithId(5) + ->setCommParams(["url_serveur" => 'http://192.168.2.3:9080/afi_Nanook-0.7.5/ilsdi/']) ->setCommSigb(7); - Class_WebService_SIGB_Nanook::setService($this->createMockForService('Nanook')); + Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://192.168.2.3:9080/afi_Nanook-0.7.5/ilsdi/', + 'id_bib' => 5, + 'type' => Class_IntBib::COM_NANOOK,], + $this->createMockForService('Nanook')); } /** @test */ public function getModeCommShouldReturnAnArrayWithCommParams() { - $this->assertEquals(array("url_serveur" => 'http://192.168.2.3:9080/afi_Nanook-0.7.5/ilsdi/', - "type" => Class_IntBib::COM_NANOOK, - 'id_bib' => 5), + $this->assertEquals(["url_serveur" => 'http://192.168.2.3:9080/afi_Nanook-0.7.5/ilsdi/', + "type" => Class_IntBib::COM_NANOOK, + 'id_bib' => 5], $this->bib_pontault->getModeComm(5)); } } diff --git a/tests/library/ZendAfi/Auth/Adapter/AuthCommSigbTest.php b/tests/library/ZendAfi/Auth/Adapter/AuthCommSigbTest.php index fa6a681fb76d6a264d46e3cfd1c5c340e077880d..485d959306a23ac2fe5640e3983096e4fe9b9cfb 100644 --- a/tests/library/ZendAfi/Auth/Adapter/AuthCommSigbTest.php +++ b/tests/library/ZendAfi/Auth/Adapter/AuthCommSigbTest.php @@ -74,13 +74,18 @@ abstract class AuthCommSigbWithWebServicesAndAbonneZorkTestCase extends AuthComm public function setUp() { parent::setUp(); - $this->fixture('Class_IntBib', ['id' => 1, 'comm_sigb' => Class_IntBib::COM_NANOOK]); + $comm_params = ['url_serveur' => 'http://localhost:8080/afi_Nanook/ilsdi/', + 'id_bib' => 1, + 'type' => Class_IntBib::COM_NANOOK]; + $this->fixture('Class_IntBib', ['id' => 1, + 'comm_sigb' => Class_IntBib::COM_NANOOK, + 'comm_params' => $comm_params]); $this->fixture('Class_IntBib', ['id' => 95, 'comm_sigb' => Class_IntBib::COM_ORPHEE]); $this->fixture('Class_IntBib', ['id' => 74, 'comm_sigb' => Class_IntBib::COM_OPSYS, 'nom_court' => 'TestingOpsys']); - Class_WebService_SIGB_Nanook::setService($this->nanook = $this->mock()); + Class_WebService_SIGB_Nanook::setService($comm_params, $this->nanook = $this->mock()); Class_WebService_SIGB_Orphee::setService($this->orphee = $this->mock()); Class_WebService_SIGB_Opsys::setService($this->opsys = $this->mock()); @@ -119,7 +124,7 @@ abstract class AuthCommSigbWithWebServicesAndAbonneZorkTestCase extends AuthComm public function tearDown() { - Class_WebService_SIGB_Nanook::setService(null); + Class_WebService_SIGB_Nanook::reset(); Class_WebService_SIGB_Orphee::setService(null); Class_WebService_SIGB_Opsys::setService(null);